Let me get back to the testing of negative states one more time. Recently, I have read a pretty good blog post How to test that cache works with Cypress by Walmyr.

A piece of Cypress test syntax caught my eye:
1 | cy.search(randomWord).then(() => { |
The test above confirms that the web page caches the search requests and does NOT send the second request when we search for the random string using cy.search(randomWord). Do you see the problem here?
No, it is not using the local variable count to keep track of the number of intercepted network calls
1 | // instead of this |
There is a bigger problem with the test. It confuses "thing X does not happen" with "thing X did not happen yet". When do we know for sure that the thing X does not happen in response to some action? Either when there is a clear indication that the system has finished processing the action; reaching some final state Y for example would be ideal.
1 | cy.intercept(`**/search?query=${randomWord}**`, { fixture: 'empty' }) |
If the application sets the class "results" on some element, then we know the network calls have been made, and it is safe to check the number of intercepted network calls. We check something positive first, and then run the "negative" assertion that confirms the number of network calls remains the same.
Often, the application does not set the state, causing confusion. In that case, we cannot check just the negative assertion, since it will pass really quickly and the application might still do the network call 10ms later. Thus we need to add a timeout:
1 | cy.intercept(`**/search?query=${randomWord}**`, { fixture: 'empty' }) |
So remember when dealing with negative assertions "something X does not happen" to always check when something does not happen. You should either "know" when to check, or wait for N milliseconds and then check. The former is faster, while the later is simpler.
For more Cypress network testing goodness, check out my course Cypress Network Testing Exercises.