0

I have a Cypress (12.9.0) setup for E2E testing, where every file in the e2e folder is a single e2e scenario with one describe() and many it() tests.

Each scenario and its tests all rely on a number of intercept() stubs (same stubs for every scenario) and do not need to reset between each it() test - I want them to be set once for the suite.

I had thought that setting the testIsolation config value to false would do this, but it seems like that does not prevent the intercept stubs from getting cleared - it only preserves the browser context.

Is there a way to accomplish this, to prevent having to re-create intercept() mocks for every test and instead be able to create them just once per test-suite (describe())?

Ben
  • 5,079
  • 2
  • 20
  • 26

1 Answers1

3

The easiest way would be to use the beforeEach() hook. It runs before every test, so will recreate your intercept route each time.

context('This is your test suite title', () => {
  beforeEach(() => {
    cy.intercept('**/api/*', { some: 'value' }).as('api')
  })

  it('This is your test case one title', () => {
    cy.visit('/')
    cy.wait('@api')           // passes
  })

  it('This is your test case two title', () => {
    cy.visit('/')
    cy.wait('@api')           // passes
  })
})

Tested with a simple HTML fragment

<script>
  fetch('https://some-domain/api/1')
</script>

To see it fail the 2nd test change the hook from beforeEach() to before().

user16695029
  • 3,365
  • 5
  • 21
  • This is what I currently have in place, and is the opposite of what I'm trying to do. I want to be able to create my mocks in the `before()` hook (or similar) and have them preserved throughout all the tests in that suite without being recreated every time. – Ben Apr 07 '23 at 22:29
  • Why is that? I thought you said you didn't want to define them in each `it()` and I took that to mean you don't want to re-type the code in each `it()`. What is the problem using `beforeEach()` rather than `before()`? – user16695029 Apr 07 '23 at 22:31
  • Sorry if that was unclear, what I don't want is for them to be defined/reset for every `it()` test regardless of whether thats using a `beforeEach` or inline. The reason has to do with underlying code & network calls that leak inbetween tests in our (very slow) CI pipeline, causing flaky test failures. This ability in Cypress would be an easy solution, rather than undertaking a larger refactor of the code (that works fine in practice, just not in tests) – Ben Apr 07 '23 at 22:35
  • 1
    Thanks for the further info, but I wonder - would changing the test code (the intercept) affect the leak in between tests? And how do you know if that is the solution? Did you try it in an older version of Cypress or something? – user16695029 Apr 07 '23 at 22:44
  • I would like to learn more about the leak, may be able to help you overcome the problem. – user16695029 Apr 07 '23 at 22:45
  • It's a call that gets fired on a timer, and when it gets past the intercept (timer fires between when stubs are cleared & stubs are recreated) it returns a `401` which breaks the UI. So if the intercept was created before all tests, and then cleared after all tests finished it wouldn't be an issue. – Ben Apr 07 '23 at 22:56
  • 1
    I can see that would be tricky (and the test flaky). One way to try would be to set `cy.clock()` to stop the timer and `cy.tick()` in each test. Another suggestion - also perform `cy.visit()` in the `beforeEach()` - that should clear the page and start the timer fresh for each test - which is the main idea for Test Isolation. – user16695029 Apr 07 '23 at 23:06
  • If you are trying to test the timer itself, e.g that 2nd, 3rd, 4th calls do something, you should do a sequence of assertions all in one test. – user16695029 Apr 07 '23 at 23:08
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253043/discussion-between-ben-and-user16695029). – Ben Apr 07 '23 at 23:20