Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be able to check if element is tappable/clickable #246

Closed
gran33 opened this issue Aug 23, 2017 · 22 comments
Closed

Be able to check if element is tappable/clickable #246

gran33 opened this issue Aug 23, 2017 · 22 comments

Comments

@gran33
Copy link

gran33 commented Aug 23, 2017

Description

I would like to be able to check if element is tappable/clickable in order to expect on element to tappable/clickable.

Steps to Reproduce

My dream is to be able to do something like this:

await expect(element(by.id(`MY_BUTTON`))).toBeTappable();

@LeoNatan LeoNatan changed the title [Feature Request] Be able to check if element is tappable/clickable Be able to check if element is tappable/clickable Aug 23, 2017
@isnifer
Copy link
Contributor

isnifer commented Aug 23, 2017

@gran33

try {
  await expect(element(by.id(`MY_BUTTON`))).tap();
  console.log('Tappable!')
} catch (e) {
  console.log('Not tappable')
}

@gran33
Copy link
Author

gran33 commented Aug 23, 2017

@isnifer Thanks, I've tried it before, and I get an exception if the element is disabled and I try to tap on it:
Error: Cannot perform action due to constraint(s) failure

@isnifer
Copy link
Contributor

isnifer commented Aug 23, 2017

@gran33 try-catch will help you do not throw an exception. Can you show me full error part of the log?

@gran33
Copy link
Author

gran33 commented Aug 23, 2017

Error: Cannot perform action due to constraint(s) failure.
Exception with Action: {
  "Action Name" : "Tap",
  "Element Description" : "<UINavigationButton:0x7fca2f44b860; AX=Y; AX.id='MY_BUTTON'; AX.label='Save'; AX.frame={{322, 27}, {37, 30}}; AX.activationPoint={340.5, 42}; AX.traits='UIAccessibilityTraitButton,UIAccessibilityTraitNotEnabled'; AX.focused='N'; frame={{322, 7}, {37, 30}}; alpha=1; disabled>",
  "Failed Constraint(s)" : "enabled",
  "All Constraint(s)" : "(!(isSystemAlertViewShown) && ((respondsToSelector(isAccessibilityElement) && isAccessibilityElement) || kindOfClass('UIView')) && (enabled && !(((kindOfClass('UIView') || respondsToSelector(accessibilityContainer)) && ancestorThatMatches(!(enabled))))) && interactable)",
  "Recovery Suggestion" : "Adjust element properties so that it matches the failed constraint(s)."
}

[
  {
    "Description" : "Cannot perform action due to constraint(s) failure.",
    "Error Domain" : "com.google.earlgrey.ElementInteractionErrorDomain",
    "Error Code" : "1",
    "File Name" : "GREYBaseAction.m",
    "Function Name" : "-[GREYBaseAction satisfiesConstraintsForElement:error:]",
    "Line" : "66"
  }
]

@isnifer
Copy link
Contributor

isnifer commented Aug 23, 2017

@gran33 is this a button from navigation bar? Is it enabled?

@gran33
Copy link
Author

gran33 commented Aug 24, 2017

@isnifer Yes, the button is navigation bar button. It disabled and I want to e2e test that the button is disabled.

@isnifer
Copy link
Contributor

isnifer commented Aug 24, 2017

@gran33 So, what happens if the user clicks on the enabled button? Transition to another screen?

@gran33
Copy link
Author

gran33 commented Aug 26, 2017

@isnifer After I press the button a Modal screen should be dismissed, but the point that I cannot test if the button is enabled or disabled.

@isnifer
Copy link
Contributor

isnifer commented Aug 26, 2017

@gran33 ok, got it.

try {
  await element(by.id(`MY_BUTTON`)).tap() // <= it will fail here if button disabled
  await expect(element(by.id(`MY_BUTTON`))).toBeNotVisible() // and will work fine if enabled
  console.log('Modal should be hidden') // <= change console.log to any assertion from your test library (mocha, tape, jest, etc...)
} catch (e) {
  console.log('Button should be disabled')
}

@gran33
Copy link
Author

gran33 commented Aug 26, 2017

Thanks, it seems to be working.
But I don't like the approach with try-catch when something isn't supported, the tests should be super precise and the behaviour should be well defined, when I try-catch like this, no one really promise that the error is just because the button is disabled, an exception can raised for example even if detox can't find the UI element and my test will be green (false-positive).

Thanks again for your time and for the example 🙏

@isnifer
Copy link
Contributor

isnifer commented Aug 26, 2017

@gran33 you're welcome. You may like or dislike, but try-catch is a powerful mechanism. You can write your own helpers to make your tests code more readable and efficient.

@DanielZlotin
Copy link
Contributor

DanielZlotin commented Aug 27, 2017

adding toBeEnabled() or isClickable() shouldn't be hard (we have this in both EarlGrey and Espresso ), and relying on try-catch for e2e assertions is not a good idea because it can fail for a lot of different reasons

@isnifer
Copy link
Contributor

isnifer commented Aug 27, 2017

@DanielZlotin really? What reasons?

@DanielZlotin
Copy link
Contributor

@isnifer well, for example, what if the button is not there at all? what if the button does something to crash the app? etc. etc.
So really the only way to rely on the error in tests is to assert on the error object, which can be really difficult and also means you're coupled to the implementing mechanism that throws the error.
Think about what will happen if someone changes the text of the error in the next patch (which is indeed a non-breaking change)..

Why go that hacky path if you already have support for this exact thing?

@DanielZlotin
Copy link
Contributor

more importantly, in detox the errors usually occur in native, which means you'll have your exception in afterEach(), making all this a moot point

@isnifer
Copy link
Contributor

isnifer commented Aug 27, 2017

  1. Button can't be there at all (when you are writing e2e-tests you know application state on every step)
  2. Crash the app - you will see it when you are starting write tests (crash of the app in the future will be a signal for you that something wrong)
  3. If someone will change text - he should update tests
  4. One more time - try-catch is not hacky. It's a powerful mechanism. If you cannot efficiently manipulate it - it doesn't mean that it's bad practice.
  5. I don't use mocha. Love tape.

@DanielZlotin
Copy link
Contributor

DanielZlotin commented Aug 27, 2017

There are a lot of assumptions here.
When doing TDD I want to see a failure first, then implement the correct behaviour. When writing a failing test I want the failure itself to be correct and as I expect it. Therefore, if I'm writing a trycatch, I expect the error object to be something specific rather than anything (because I expect it to throw something).
Also, as already said, the error itself happens in afterEach making everything much more complicated.
Again, toBeClickable or toBeEnabled is already supported natively. Just need to export this functionality to JS.

@DanielZlotin
Copy link
Contributor

@isnifer I recommend this for further reading

@isnifer
Copy link
Contributor

isnifer commented Aug 27, 2017

Book about TDD. I think it’s the main problem that people compare TDD and E2E. They are different things

@DanielZlotin
Copy link
Contributor

detox is a wrapper around EralGrey and Espresso, e2e testing tools. Your professionalism is your own choice, but detox should provide any and all tooling necessary for doing e2e (TDD or otherwise) using those tools.
Suggesting trycatch without expecting on the error is not a robust solution to the OP's problem, even when writing tests-after-the-fact.

@auval
Copy link

auval commented Mar 27, 2018

@DanielZlotin @rotemmiz Is there a plan to export toBeClickable and toBeEnabled to js? I need this as well.

@LeoNatan
Copy link
Contributor

LeoNatan commented May 3, 2018

Not something that can be easily implemented.

@LeoNatan LeoNatan closed this as completed May 3, 2018
@wix wix locked and limited conversation to collaborators Jul 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants