cypress: cy.request + Callback Queue Race Conditions prevent LocalStorage from being cleared prior to each `it`
Current behavior:
When i have a complex set of conditions (100% reproduced in the Test repository below ๐ ), localStorage is not cleared prior to each it (we do a cy.visit in beforeEach)
One weird condition - cy.request MUST be called before visit and it MUST take some time to respond (Iโve found as little as 1s can cause failures, but in this example i set my mock api to 2s)
Another weird condition - the application code has to be updating the localStorage in a weird way. In my example, I use redux with redux-localstorage and a setTimeout which increases on each iteration.
We assert localStorage item redux_test is null and it fails:

it is 100% reproducible.
Desired behavior:
If we take out the cy.request in the beforeEach, every time it is run, the localStorage is cleared correctly even with all the wacky setTimeout redux stuff done in app code (no other app code changes)
Desired behaviour is, Even when doing cy.request in beforeEach, the output should be all passing:

Steps to reproduce:
You can clone this Repository https://github.com/egucciar/cypress-support/tree/local-storage
On the local-storage branch (linked above)
Run:
git checkout local-storage
yarn
yarn start
In another terminal run:
yarn cypress:open
Observe errors. Also comment out the cy.request to observe passing.
Versions
Cypress v3.1.0, Chrome 70, MacOS 10.13.1
Notes
My mocklab API account will have its free trial expired within the next 2 weeks i think, so please take a look ASAP~~
This has been plaguing us forever and i FINALLY Have a standalone reproducer that is 100% reliable ๐ ๐ญ
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 2
- Comments: 28 (23 by maintainers)
No work has been done on this issue.
K, then this is a proper reproducible example. You can add expectations in the
beforeEach. This does pass when commenting out thecy.request()and fails on the 2nd testโsbeforeEachwhen thecy.request()is present.Sorry for the back and forth. I was just trying to get the lowest reproducible example.
I believe this may be related to this issue -> of an asynchronous function from a previous test setting localStorage after the test is done. We will fix this issue in a later release.
Workaround
Manually clear localStorage in the
onBeforeLoadincy.visit(). The tests pass when below is added.After a closer look, it seems a race condition indeed.
The local storage cleanup happens in the
test:before:runlistener: https://github.com/cypress-io/cypress/blob/1690d41d763704d18f6ab638f9a19a910cd70266/packages/driver/src/cy/commands/local_storage.js#L25-L33A bit down the line, the window object gets updated during the
window:before:loadevent: https://github.com/cypress-io/cypress/blob/1690d41d763704d18f6ab638f9a19a910cd70266/packages/driver/src/cypress/cy.js#L1194-L1198Which is in turn triggered from the proxy inject code: https://github.com/cypress-io/cypress/blob/1690d41d763704d18f6ab638f9a19a910cd70266/packages/proxy/lib/http/util/inject.ts#L13-L22
So, If there was a cross origin request, it sets both events (
test:before:runandwindow:before:load) apart in time, which lets us reliably reproduce the bug. At this point, cleanup happens earlier than it should, only cleaning the window object of the previous test (are they different objects though?). In fact, removing thecy.requestcode and running the tests with an open console somehow gives a similar effect.It looks like the reproducer tests pass only when
window:before:loadis triggered early enough to update the reference to window before the local storage cleanup. However, I couldnโt confirm this with a console.log.This comment describes something similar: https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cypress/cy.js#L919-L926
Its been few months after this issue had been found. Is there any progress on fixing this issue? @jennifer-shehane
Thanks you @egucciar for this bug report. I was facing the same issue in my project (with basically the same setup, just with vue + vuex + vuex-persistedstate) and i have spent ages trying to figure out was is wrong in my specs. +1