skip to Main Content

What’s a good alternative to setting XCUIDevice.shared.orientation for changing the orientation during XCTests in Xcode 13?

Many of our app’s existing snapshot tests set the device orientation using:

XCUIDevice.shared.orientation = orientation.deviceOrientation

However in Xcode 13, these tests fail due to the following exception being thrown when this method is called:

Failed to set device orientation: Not authorized for performing UI testing actions.
Exception _XCTestCaseInterruptionException * 0x60000082b060 0x000060000082b060

Googling this error led me to find this Flutter issue where they state:

I guess Xcode 13 will limit the use of XCUIDevice to XCUITests.

Our snapshot tests are not XCUITests, though, so what options do we have to force a particular device rotation so that we can snapshot the way the view would look in landscape and portrait?

3

Answers


  1. Chosen as BEST ANSWER

    This solution from @Dmytro on another question works for me, use:

    UIDevice.current.setValue(
        NSNumber(integerLiteral: orientation.deviceOrientation.rawValue), 
        forKey: "orientation"
    )
    

    instead of:

    XCUIDevice.shared.orientation = orientation.deviceOrientation
    

    and now it works fine.

    Note: .deviceOrientation refers to our custom extension on UIInterfaceOrientation:

    public extension UIInterfaceOrientation {
        var deviceOrientation: UIDeviceOrientation {
            switch self {
            case .landscapeLeft:
                return .landscapeRight
            case .landscapeRight:
                return .landscapeLeft
            case .portrait:
                return .portrait
            case .portraitUpsideDown:
                return .portraitUpsideDown
            case .unknown:
                return .unknown
            }
        }
    }
    

  2. I would take issue with the entire premise of your question; you should be doing UI testing for snapshots, not unit testing. UI testing has very powerful support for snapshotting as well as for dropping a lot of other information into the report for later retrieval.

    It’s true that a UI test can’t reach into an app’s code and make it behave. But to make the app behave in special ways during testing, a UI test can inject environment variables into the app, where the app itself can configure itself in a special way for testing. See for example Xcode UI Test environment variables not being passed from Scheme on how to do that.

    Login or Signup to reply.
  3. We faced the same problem in our project with snapshot tests. Unfortunately,
    UIDevice.current.setValue didn’t do the trick for us.

    So, we decided to go with this solution:

    1. add a new dummy UITest case file (not unit test case!):

    enter image description here

    1. name it starting with an ‘A’ so it would be the first in alphabetical order (and thus will be executed before other tests)

    2. override class setUp() method with your code for changing device orientation. in our case it is changing it to portrait like so:

      override class func setUp() {
          super.setUp()
          if XCUIDevice.shared.orientation != .portrait {
              XCUIDevice.shared.orientation = .portrait
          }
      }
      
    1. add a dummy test, so setUp() will be executed:

      func testDummyTest() {
          XCTAssert(true)
      }
      

    And that’s it. Of course, it will not work when we trigger only one test and not a whole bundle, but as a workaround it can do. Hopefully, it will be fixed in future Xcode releases.

    Here is the full code:

    import XCTest
    
    /// The class name should be the first in alphabetical order
    class AUITestsSetUp: XCTestCase {
    
        override class func setUp() {
            super.setUp()
            if XCUIDevice.shared.orientation != .portrait {
                XCUIDevice.shared.orientation = .portrait
            }
        }
    
        func testDummyTest() {
            XCTAssert(true)
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search