cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.06k stars 3.19k forks source link

Cypress wrongfully reloads page on submit even though it is prevented in Nuxt. #28081

Open lucasfelber opened 1 year ago

lucasfelber commented 1 year ago

Current behavior

When testing a form which is normally being prevented from reloading the page, cypress still does. The library I am using is preventing a page reload in their form component like this.

Desired behavior

Just like in the browser, cypress should not reload the page, keeping the values in the input fields.

Test code to reproduce

Here is a repository with the failing code: https://github.com/lucasfelber/cypress-submit-reload

You have to start up the server with yarn dev before running the test. Then you can go to http://localhost:3000/signup and see in the browser that the page does not reload when submitting. However it does in the test.

Cypress Version

13.3.1

Node version

v18.17.1

Operating System

Windows 10.0.19045

Debug Logs

https://github.com/lucasfelber/cypress-submit-reload/blob/master/test-run.log

Other

No response

ldevoco commented 9 months ago

Happening for me too, bizarre. Manual form submission via enter key or click works normally, Cypress works differently.

jennifer-shehane commented 9 months ago

I can recreate this from the information provided. I haven't seen this reported before. It must be related to something specific with Nuxt's use of this.

SarahLKatz commented 8 months ago

I'm seeing a similar issue with React (specifically using React Hook Form for my form) - if I have type="submit" on my button, Cypress will reload the page even if the browser does not normally reload on form submission. Removing type="submit" gets me the expected behavior (no reload)

Grigorevskiy commented 8 months ago

Hey there! Same issue. Manually clicking on the button and no problems, but when the cypress does click, it reloads the page. if I remove type="submit" then it works fine. When it will be fixed?

RolandLoosz commented 7 months ago

Temporary solution can be to prevent the form's default behaviour with cypress:

cy.get('form').then(($form) => {
  $form.on('submit', e => {
    e.preventDefault();
  });
});
cy.get('button').click();
parkuman commented 6 months ago

We are experiencing the same issue with react-final-form.

I found that by calling .trigger('click') it avoids this weird behaviour for anyone stuck in limbo with this issue.

shye0000 commented 2 months ago

Same issue here, @parkuman 's workaround indeed does the trick

We are experiencing the same issue with react-final-form.

I found that by calling .trigger('click') it avoids this weird behaviour for anyone stuck in limbo with this issue.

Jax-p commented 1 month ago

Surely this is a bug in Cypress? In my case it wasn't a Cypress bug nor a "reload" either. The default behavior of the HTML form is that when submit is clicked, it sends the selected request method to the selected action (by method and action parameters, default is "GET" and "/").

Since Nuxt (and other meta frameworks like Next) can serve server-side rendered page or its parts, the first thing that comes into the browser is static HTML - i.e. a form with native behavior - then only the 'on-load' (or so called 'ready') event takes place and React/Vue starts enchancment of the static document. In other words, you might click submit before the new form events are registered (and preventDefault() the original ones).

This behavior can also have a negative effect on the user, so I take the test as correct. Properly, this behavior should be handled in application (not in the test). For example, so that the form cannot be submitted (submit disabled) until the library is initialized (for example, react-hook-forms).


Personally, I don't like the workaround that overrides the submit callback (we want to test that too, don't we?) and we want to keep calling click(). So in the case of React, I'd rather wait for hydration. I can find out if the element is hydrated, for example, like this:

function isReactComponent(element: HTMLElement) {
    const keys = Object.keys(element);
    return keys.some((key) => key.startsWith('__reactFiber$'))
}

/** @example: cy.get('form').isHydrated() */
Cypress.Commands.add('isHydrated', { prevSubject: true }, (subject) => {
    const isComponent = isReactComponent(subject.get(0));
    expect(isComponent, 'Element is not hydrated.').to.eql(true);
});

With function like that you retry/pool it until it its hydrated and then run your tests / submit.