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)

Most upvoted comments

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.

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: image

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 😃

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:

  • Cypress recognizes that the element is not focused and clicks on it
  • ‘click’ events fire
  • Cypress sends the enter key to the button, but the browser doesn’t ‘click’ on the element, because it is an untrusted event and the default action is prevented

You can also do the following to click a button: cy.get('button').type('foobar')

Whoops! This is certainly not what we want!