Cypress Testing: Pointer CSS media feature
This post aims to provide a few methods for debugging issues you might run into during testing with the Cypress environment.
Since Cypress is a full end-to-end framework for web test automation, we often expect it to behave exactly like our browser, and for the most part it does. If you fire up the Cypress test GUI(Graphical User Interface), it opens up a new chrome window and performs all the tasks you instructed it to do. But it’s a slightly different story when you run those same tests in a headless or GUI-less version of Cypress.
This headless version is often used to run tests within a CI pipeline and if you’re not aware of the potential differences, you can wind up running into a series of obscure issues you were not anticipating. This is exactly what happened to our team while integrating one of the most popular React UI frameworks: MUI's DatePicker component.
Pointer CSS media feature
Before we dive into the specific issue we ran into and how we solved it, we need to talk about the pointer CSS media feature which, upon queried, tests what kind of pointing device a user is employing.
This media feature will return one of three values:
one: The primary input mechanism does not include a pointing device, such as smartphones or tablets
Coarse: The primary input mechanism includes a pointing device of limited accuracy, such as smart TVs or video game consoles.
Fine: The primary input mechanism includes an accurate pointing device, such as a mouse or touchpad.
This is important because MUI's DatePicker component uses this media feature to determine whether to render a 'Desktop' or 'Mobile' version of the DatePicker.
What we did
When creating our Cypress tests to try our DatePicker component, we first ran the tests locally. Upon seeing the DesktopDatePicker component rendered, we wrote our tests against that expected component with all the relevant DOM selections.
However, upon running the tests within our CI pipeline, the test would fail.
Without prior knowledge of the pointer media feature, we were stuck not knowing why it would succeed locally and not within our CI pipeline.
It wasn’t until we pulled the Cypress screenshots did we realize that the headless Cypress test runner within the CI pipeline was actually rendering the MobileDatePicker component. See below.
We are able to pull the screenshots because when we set up Cypress within our CI, we configured it to save screenshots onto a Google Cloud bucket. We then used the Google Cloud storage CLI(Command Line Interface) tool gsutil to download the screenshots stored onto the bucket.
We quickly realized that the headless Cypress was returning 'none' for the pointer media query. This, therefore, was the reason for rendering a different component than what our local Cypress test runner (which would report 'fine' for the pointer media query) was rendering.
To solve this, we had a couple of choices:
- Update the Cypress tests to check the pointer media query and perform branching tests depending on what it returned
- Update the MUI DatePicker heuristic as to how it decides to render Desktop or Mobile version of the DatePicker based on viewport (The component provides a prop to adjust this)
- Default to using either Desktop or Mobile DatePicker always
For our use case, we decided to go with the last option since our application is designed for Desktop use.