Detox: iOS Simulator how to confirm alert message

Viewed 8141

I am using Alert from react-native.

How do I get detox to press the "Log out" button on the alert message?

enter image description here

I tried using await element(by.text('Log out')).tap();

But I get "Multiple elements were matched" error. Presumably it finds 3 elements with same label. The original button with label "Log out" used to trigger the alert message, the alert message title, and the alert message button I want detox to press.

Error Trace: [
  {
    "Description" : "Multiple elements were matched: (
    "<UILabel:0x7fe7964db910; AX=Y; AX.label='Log out'; AX.frame={{41, 234}, {238, 20.5}}; AX.activationPoint={160, 244.25}; AX.traits='UIAccessibilityTraitStaticText'; AX.focused='N'; frame={{16, 20}, {238, 20.5}}; opaque; alpha=1; UIE=N; text='Log out'>",
    "<UILabel:0x7fe7964dda90; AX=Y; AX.label='Log out'; AX.frame={{198.5, 322.5}, {58, 20.5}}; AX.activationPoint={227.5, 332.75}; AX.traits='UIAccessibilityTraitStaticText'; AX.focused='N'; frame={{0, 12}, {58, 20.5}}; opaque; alpha=1; UIE=N; text='Log out'>",
    "<RCTText:0x7fe79652f300; AX=Y; AX.label='Log out'; AX.frame={{16, 338.5}, {288, 17}}; AX.activationPoint={160, 347}; AX.traits='UIAccessibilityTraitStaticText'; AX.focused='N'; frame={{0, 0}, {288, 17}}; alpha=1>"
). Please use selection matchers to narrow the selection down to single element.",
    "Error Domain" : "com.google.earlgrey.ElementInteractionErrorDomain",
    "Error Code" : "5",
    "File Name" : "GREYElementInteraction.m",
    "Function Name" : "-[GREYElementInteraction grey_errorForMultipleMatchingElements:withMatchedElementsIndexOutOfBounds:]",
    "Line" : "956"
  }
]

I guess one way is to use .atIndex(), but that means I need to play with indexes every time something changes to determine the correct element.

Is there no better way to address this issue?

Thanks.

4 Answers

After some tinkering I ended up using this:

await element(by.label('Log out').and(by.type('_UIAlertControllerActionView'))).tap();

Not sure if this will work for every iOS version, but seem to work on 10.3 and 11.1

Use View Hierarchy Debugger provided by Xcode to see if the type has changed for a different version of iOS.

You can now press on native dialogs. Tested on iOS. (did not test on Android)

If your button says "OK" ie:

Alert.alert(
  `Are you sure you would like to remove this image as the coming soon image?`,
  undefined,
  [
    {
      text: "No",
      style: "cancel",
    },
    {
      text: "OK",
      style: "destructive",
      onPress: this.onRemoveHero,
    },
  ]
);

You would click this by doing:

element(by.label("OK")).atIndex(0).tap();

I have wrote a utility function which allows you to do this cross platform.

Function

/**
 * Detects a systme dialog button by label
 * 
 * @param {string} label
 * 
 * @returns {*}
 */
export function systemDialog(label){
    if (device.getPlatform() === 'ios') {
        return element(by.label(label)).atIndex(0);
    }

    return element(by.text(label));
}

Usage

import { systemDialog } from "path to system dialog";

...

await systemDialog('OK').tap();
Related