Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I set accessibilityIdentifier to UIAlertController?

This is how I simply create UIAlertController and present it on the screen:

private class func showAlertWithTitle(title: String, message: String) {

    let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
    //alert.accessibilityLabel = "my string here"      //doesnt work
    let action = UIAlertAction(title: "OK", style: .Default) { action in
        alert.dismissViewControllerAnimated(true, completion: nil)
    }

    alert.addAction(action)
    UIStoryboard.topViewController()?.presentViewController(alert, animated: true, completion: nil)
}

and this is how I access it under UITests:

emailAlert = app.alerts["First Name"] //for title "First Name"

but I would like to set there custom identifier and access this by firstName like this:

emailAlert = app.alerts["firstName"]

Is it possible?

like image 347
Bartłomiej Semańczyk Avatar asked Jun 30 '16 08:06

Bartłomiej Semańczyk


3 Answers

This is an old thread but someone might use this.

I was able to set the accessibility identifier like this:

let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.view.accessibilityIdentifier = "custom_alert" alert.view.accessibilityValue = "\(title)-\(message)"  alert.addAction(     UIAlertAction(         title: "ALERT_BUTTON_OK".localized,         style: .default,         handler: handler     ) )  present(alert, animated: true) 

That way I can access the alert by accessibility identifier and check its contents in accessibility value.

It is not perfect of course, but it works - at least for my testing using Appium.

like image 168
Jan Avatar answered Sep 25 '22 17:09

Jan


The only way I figured out to do this was to use Apple's private APIs. You call valueForKey on the UIAlertAction object with this super secret key: "__representer" to get whats called a _UIAlertControllerActionView.

    let alertView = UIAlertController(title: "This is Alert!", message: "This is a message!", preferredStyle: .Alert)     let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)      alertView.addAction(okAction)      self.presentViewController(alertView, animated: true, completion: {         let alertButton = action.valueForKey("__representer")         let view = alertButton as? UIView         view?.accessibilityIdentifier = "okAction_AID"     }) 

This has to be done in the completion handler because that that _UIAlertControllerActionView won't exist until the view is presented. On a side note in my project I used these following extensions to make things easier / more readable:

extension UIAlertController {     func applyAccessibilityIdentifiers()     {         for action in actions         {             let label = action.valueForKey("__representer")             let view = label as? UIView             view?.accessibilityIdentifier = action.getAcAccessibilityIdentifier()         }      }  }  extension UIAlertAction {     private struct AssociatedKeys {         static var AccessabilityIdentifier = "nsh_AccesabilityIdentifier"     }      func setAccessibilityIdentifier(accessabilityIdentifier: String)     {         objc_setAssociatedObject(self, &AssociatedKeys.AccessabilityIdentifier, accessabilityIdentifier, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)     }      func getAcAccessibilityIdentifier() -> String?     {         return objc_getAssociatedObject(self, &AssociatedKeys.AccessabilityIdentifier) as? String     } } 

So the above code would be rewritten:

    let alertView = UIAlertController(title: NSLocalizedString("NMN_LOGINPAGECONTROLLER_ERROR_TITLE", comment: ""), message: message as String, preferredStyle:.Alert)     let okAction = UIAlertAction(title: NSLocalizedString("NMN_OK", comment: ""), style: .Default, handler: nil)     okAction.setAccessibilityIdentifier(InvalidLoginAlertView_AID)       alertView.addAction(okAction)       self.presentViewController(alertView, animated: true, completion: {         alertView.applyAccessibilityIdentifiers()     }) 

My first attempt involved trying to navigate the view hierarchy but that became difficult since UIAlertControllerActionView was not a part of the public API. Anyway I'd probably would try to ifdef out the valueForKey("__representer") for builds submitted for the app store or Apple might give you a spanking.

like image 34
Anthony Olds Avatar answered Sep 21 '22 17:09

Anthony Olds


Right now I have a UIAlertAction called addCamera and I'm just doing:

addCamera.accessibilityLabel = "camera-autocomplete-action-photo"

That allows me to tap it in UI Tests as follows:

app.sheets.buttons["camera-autocomplete-action-photo"].firstMatch.tap()

like image 24
Alper Avatar answered Sep 24 '22 17:09

Alper