cypress: cy.type + enter doesn't trigger a `click` on a button or anchor element
When a button or a element is focused, hitting the enter key will trigger a click event in all browsers, but cy.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 via force: true which is only disabling actionability checks. I’ve had to manually use trigger which is cumbersome to trigger all related events to be more accurate, but that’s for another issue.
Current behavior:
The click is not fired
Desired behavior:
The click event should fire
Test code to reproduce
https://github.com/NicholasBoll/cypress-test-tiny
cypress/fixtures/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Test</title>
<meta name="description" content="Test" />
</head>
<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>
cypress/integration/spec.js
describe("page", () => {
beforeEach(() => {
cy.visit("cypress/fixtures/index.html");
});
it("should trigger a click action when typing {enter}", () => {
cy.get("button").focus().type("{enter}"); // this doesn't trigger a click
cy.get("output").should("contain", "Clicked!");
});
it("should not trigger a click action when typing random characters", () => {
cy.get("button").type("foobar"); // this does trigger a click
cy.get("output").should("not.contain", "Clicked!");
});
});
Versions
All
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 11
- Comments: 18 (8 by maintainers)
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.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
clickevent 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 😃
Interesting. It seems to be correct that if an element is first focused, then
{enter}will not work:It seems the only difference is if the element has focus before
.typeis 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
clickevent 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-L417The 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 (abutton, for instance) and it will click the button. This happens to do what we want in the case ofcy.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!