Open NicholasBoll opened 4 years ago
This specfile does pass for me in both cypress open
and cypress run
in Chrome, Firefox and Electron. What am I missing? 🤔 Are you using the latest Cypress?
spec.js
it('should trigger the click action when typing {enter}', () => {
cy.visit('index.html');
cy.get('button').type('{enter}')
cy.get('output').should('contain', 'Clicked!')
});
index.html
<html>
<body>
<button id="button">My Button</button>
<output id="output"></output>
<script>
document.getElementById("button").addEventListener("click", function () {
document.getElementById("output").textContent = "Clicked!";
});
</script>
</body>
</html>
I am actually running into the same issue at the moment trying to trigger the enter key on links, to test keyboard (accessibility) navigation. I found no way (with type nor trigger) how to get a link to be "entered".
What would be the correct way to do this? (I am using Chrome 84 and Cypress 4.10)
@pcvandamcb @NicholasBoll Please provide a fully reproducible example of a situation where the enter
typing is not triggering the click
event. We'd be more than happy to look into it. I wasn't able to reproduce this behavior.
I'm running into this issue as well on Cypress 5.1.0. Here's a repo that reproduces the issue: https://github.com/LisaManresa/cypress-test-button-enter-press
Edit: I just realized that my issue is most likely related to cypress-plugin-tab
. Tabbing into an element and pressing {enter}
does not work. But cy.get('.my-button').type('{enter}')
does. So my issue might belong over in the cypress-plugin-tab
repo.
For anyone stumbling on this issue: i had the same issue and thanks to this ticket was able to resolve it. I selected the button like so:
cy.get(selector).focus().type('{enter}');
But the .focus()
somehow breaks the enter. What you need to do is simply: cy.get(selector).type('{enter}')
Interesting. It seems to be correct that if an element is first focused, then {enter}
will not work:
cy.get(selector).type('{enter}') // works
cy.get(selector).focus().type('{enter}') // doesn't work
// doesn't work
cy.get(selector).focus()
cy.focused().type('{enter}')
// doesn't work
cy.get(selector).focus()
cy.get(selector).type('{enter}')
// works
cy.get(selector).focus()
cy.get(someOtherSelector).focus()
cy.get(selector).type('{enter}')
It seems the only difference is if the element has focus before .type
is called, it will not work.
This didn't make sense to me because the reason keyboard commands don't work at all are due to Cypress firing synthetic events instead of native events. #311 is the issue for Cypress to support native events. The reason synthetic events don't fire default actions (a click on enter or space bar keys is a default action). Read more about trusted events here. Only a click
event will trigger default actions (activating a button is the default action for a click event).
So why does Cypress seem to click when you do cy.get(selector).type('{enter}')
? I did some digging and this is what I found:
https://github.com/cypress-io/cypress/blob/49db3a685d77655dde17fa39e2211dcacd7d0323/packages/driver/src/cy/commands/actions/type.js#L396-L417
The difference is if the element does not have focus, cy.now('click', ...
is performed. This means you could type literally anything to an unfocused element (a button
, for instance) and it will click the button. This happens to do what we want in the case of cy.get('button').type('{enter}')
.
In reality, this is what happens:
You can also do the following to click a button: cy.get('button').type('foobar')
Whoops! This is certainly not what we want!
@jennifer-shehane I've updated my original test to reflect this new information. You were right that the original code did not trigger the error since I didn't .focus()
first.
I've updated the original issue as well.
Yeah, definitely an oversight on how the events are triggered with enter
keys on special form elements.
@NicholasBoll The second example in your repo is debateable. If the button does not have focus, then there's no way to type into the button without it first being clicked or focused. If you do cy.get("button").focus().type("foobar");
then it correctly does not fire the click event. I guess you could argue that Cypress should just automatically focus when being told to type into a button
, a
, etc.
spec.js
it("should trigger a click action when typing {enter}", () => {
cy.visit("index.html");
cy.get("button").focus().type("{enter}");
cy.get("output").should("contain", "Clicked!");
});
index.html
<html>
<body>
<button id="button">My Button</button>
<output id="output"></output>
<script>
document.getElementById("button").addEventListener("click", function () {
document.getElementById("output").textContent = "Clicked!";
});
</script>
</body>
</html>
This should really be mentioned far more clearly in the docs of the cy.type page. This is a big gotcha for our accessibility tests emulating keyboard navigation!
@NicholasBoll The second example in your repo is debateable. If the button does not have focus, then there's no way to type into the button without it first being clicked or focused. If you do
cy.get("button").focus().type("foobar");
then it correctly does not fire the click event. I guess you could argue that Cypress should just automatically focus when being told to type into abutton
,a
, etc.
I agree that you cannot type without first giving focus. I might disagree that a click
is the way to do it. I probably didn't even notice at first because I always call .focus()
before .type()
, but not everyone does this. Omitting the .focus()
changes the behavior of .type()
I see mention of this here: https://docs.cypress.io/api/commands/type.html#When-element-is-not-in-focus
I think type
is meant for form inputs and not really for other elements. This is true of valid element detection.
I created a new plugin to help make keyboard interaction more realistic: https://github.com/NicholasBoll/cypress-keyboard-plugin. It works by wrapping cy.type
with extra detection and features. It handles this issue as well as spacebar on checkboxes and radio inputs.
I created a new plugin to help make keyboard interaction more realistic: https://github.com/NicholasBoll/cypress-keyboard-plugin. It works by wrapping
cy.type
with extra detection and features. It handles this issue as well as spacebar on checkboxes and radio inputs.
This doesn't resolve the accessibility testing scenario. It uses a click event to emulate an enter, which means i'm not testing entering a button. Instead i'm just writing a second test for the mousebeviour of clicking the button.
It's a good plugin to recommend until such time as native events are incorporated into cypress. Nice work!
This doesn't resolve the accessibility testing scenario. It uses a click event to emulate an enter, which means i'm not testing entering a button. Instead i'm just writing a second test for the mousebeviour of clicking the button.
Agreed. Anything other than native events is simulation.
I disagree that you're just writing a second test for the mouse behavior for a click.
Take this example:
<button id="working-button">My Button</button>
<script>
document
.getElementById("working-button")
.addEventListener("click", function () {
console.log('clicked!')
});
</script>
If you focus on the button without clicking it and then hit either the space bar key or the enter key, "clicked!" will appear in your console. This is because a click
event is also fired in scenario as an activation trigger. There is no such thing as a hidden keydown
+ event.key === 'Enter'
special action. It quite literally fires click
event.
The plugin does its best to simulate the normal behavior. In the button scenario, this is what happens.
cy.get('button').focus().type('{enter}')
click
event listenerkeydown
event listenercy.type
which goes through a series of simulations to simulate a user pressing a key (keydown
, keyup
, keypress
) as well as actionability to ensure a real user could perform the actionclick
event listener was called, the application must have called it manually - there is nothing to do. The default activation trigger was manually called - the user will not know the differenceclick
event listener was not called, it checks the defaultPrevented
boolean on the keydown
event. If it gets here, that means the application did not simulate a click
and prevented the activation trigger with event.preventDefault()
. An accessibility error is thrown in this case warning the user to check out #311 for more infoclick
and keydown
event listeners are removedI ran into this issue when trying to test keyboard accessibility. I wanted to get the body element, tab twice to reach a link, and press enter to test that the link took me to a specific url.
I was already using a 3rd party plugin for tab functionality since this is also not natively supported by Cypress.
cy.get('body').tab().tab().type('{enter}')
cy.url().should('include', '/good_weather')
Currently on Cypress v 8.2.0
I suggest you use cypress-real-events plugin for now to achieve this, read https://glebbahmutov.com/blog/test-app-using-the-keyboard/
Sent from my iPhone
On Aug 8, 2021, at 20:09, Alex Kio @.***> wrote:
I ran into this issue when trying to test keyboard accessibility. I wanted to get the body element, tab twice to reach a link, and press enter to test that the link took me to a specific url.
I was already using a 3rd party plugin for tab functionality since this is also not natively supported by Cypress.
cy.get('body').tab().tab().type('{enter}') cy.url().should('include', '/good_weather') Currently on Cypress v 8.2.0
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.
cy.get("button").type("{enter}") doesn't work in firefox. But works as intended in Chrome and Electron.
I stumbled upon this as well when using Chrome (94) or Electron (91). In Firefox (93) it works as expected. Using Cypress 8.3.1.
cy.contains(accordionContent).should("not.be.visible");
cy.get("@toggleButton").click();
cy.contains(accordionContent).should("be.visible");
cy.get("@toggleButton").focus().type("{enter}");
cy.contains(accordionContent).should("not.be.visible");
There's something really fundamentally broken with how events are simulated. I have an accessible dropdown, which also responds to keyboard inputs and I can't focus the button and hit enter.
If I do it without the focus, it "works", but fires twice.
If I type '{tab}'
(which Cypress claims doesn't exist), it actually works:
It would be great if this system could be prioritized, because it's leading to a lot of issues on our end testing accessibility...
In my case it seems as if the button, when receiving a keyboard command, bubbles the event up to the parent that then closes the dropdown again, instead of triggering a click
event which is how a button handles spacebar in the browser.
Attaching an event handler with stop propagation on the button also doesn't work, so event bubbling is not simulated like how they work in the browser. But I think we already reached that conclusion :)
cy.get("button").type("{enter}") doesn't work in firefox. But works as intended in Chrome and Electron.
I've found the same when using .type("{enter}")
on a text input. It should submit the form. It does in Edge, but not in Firefox.
When a
button
ora
element is focused, hitting theenter
key will trigger aclick
event in all browsers, butcy.type('{enter}')
will not trigger a click event while using Cypress.I've created a plugin that gets around this: https://github.com/NicholasBoll/cypress-enter-plugin
Update: Upon further inspection, Cypress does trigger a click on any non-focused element when typing any characters. This is not realistic. I'm attempting another plugin that tries to be more accurate about keyboard. Another issue
cy.type
has is the detection of valid elements to send keys to. This detection cannot be disabled viaforce: true
which is only disabling actionability checks. I've had to manually usetrigger
which is cumbersome to trigger all related events to be more accurate, but that's for another issue.Current behavior:
The
click
is not firedDesired behavior:
The
click
event should fireTest code to reproduce
https://github.com/NicholasBoll/cypress-test-tiny
cypress/fixtures/index.html
cypress/integration/spec.js
Versions
All