Imagine you are building an online shopping site. Your goal is to build the best customer-to-customer site, similar to mercari.com 😉. When the user enters a new listing details. the system tries to suggest the best shipping option; the online commerce lives and dies by the shipping rates. So you want to suggest to the user the shipping dimensions and options that make sense. But sometimes there is no guess, so the shipping dimensions might be missing. Here is how it looks for our example test site:

The dimensions predictions data is returned by the backend in response to POST /dimensions call

If the backend cannot generate the dimensions predictions, the call returns { "dimensions": null }. Let's test it.
Loading element
The first thing I test is the loading element to confirm the user sees something meaningful while the backend is crunching numbers.
1 | it('shows the loading element', () => { |
We delay the app's POST /dimensions call by 2 seconds and confirm the loading spinner is shown. By using cy.wait('@dimensions') command we confirm the network stub is used - the application isn't using something else to load the prediction.
Great.
No data
Let's test what happens when the backend returns dimensions: null property in the response. We are not interested in completely stubbing the network call with the fixture; there might be other fields in the response that are not related to the dimensions guess. We will stub the network call and delete the dimensions property.
1 | it('sends no dimensions', () => { |

Tip: end-to-end tests should be focused on the concrete subject, do not test everything in every test to avoid having to change lots of tests even on the smallest app changes.
Dimensions prediction
Now let's confirm the app shows the dimensions if the server returns an object. We want to return the mock dimensions: { ... } object, but we want to make sure it matches what the server normally returns. So to "catch" the schema changes, we will validate the real server response, while swapping it with our mock object.
1 | import spok from 'cy-spok' |

Notice how we "substitute" the dimensions object and validating both the real server response and our mock object to make sure nothing changes without the test knowing about it.
1 | req.continue((res) => { |
I am using cy-spok plugin for checking objects against simple schemas. We can be more precise when checking the dimensions properties. For example, we know that the dimensions can only be inches or centimeters. Similarly, we know the likely range for model predictions:
1 | import spok from 'cy-spok' |

Beautiful.