Execute RN component tests in parallel using cypress-split plugin.
Let's say you are using react-native-web to see your RN components in the browser. In my example, we are bundling the RN code using Next.js + Webpack and we have lots of components. We can write Cypress component tests and develop parts of our application in isolation with very quick feedback loop. This blog post shows how to run all these component tests in parallel for free using my plugin cypress-split.
🎁 You can find the source code shown in this blog post in the repo bahmutov/rn-examples. Check out the Actions tab to see the test runs.
The Switch component test
Let's confirm the RN Switch component is working as expected. We have an example page with bunch of Switch components, one of them flipping back and forth.
The component test imports the Switch example component, mounts it, and confirms the input type=checkbox changes the value. Let's open Cypress in component testing mode
1
$ npx cypress open --component --browser electron
The test shows lots of Switch components from the example page, we are observing the bottom one.
Beautiful.
Spy on the set value call
Let's write another test to confirm the Switch calls onValueChange prop. We can create an example component directly in the component spec file. The component calls an internal function to set the new state value:
We want to spy on setIsEnabled calls. We can create a cy.stub Sinon.js function that returns whatever is passed to it and insert it into setIsEnabled(!isEnabled) call.
it('calls the onValueChange callback', () => { // create a stub function that returns the first argument const enabledSpy = cy.stub().returnsArg(0).as('enabledSpy') constTestSwitch = () => { const [isEnabled, setIsEnabled] = useState(false) consttoggleSwitch = () => { // when "setIsEnabled" is called, call the stub too returnsetIsEnabled(enabledSpy(!isEnabled)) }
cy.mount(<TestSwitch />) // our switch has "input type=checkbox" inside with the actual value const switchSelector = '[data-testid=switch] :checkbox' // confirm the first values and the interaction // that calls the function stub cy.get(switchSelector).should('not.be.checked').click() cy.get('@enabledSpy') .should('have.been.calledWith', true) .invoke('resetHistory') cy.get(switchSelector).should('be.checked').click() cy.get('@enabledSpy').should('have.been.calledWith', false) })
The stub (or spy in this case), is called with expected values. First with true when we flip the switch to "on", then with false when we flip it back.
Component tests
Working on RN components while writing tests is super quick. We can cover a lot of components and go deeper into individual ones to make sure they work. At some point, we want to know what tests we have written. I have installed find-cypress-specs to list all E2E and component tests in the repository.
pages/switch/value-change.cy.js (1 test) └─ calls the onValueChange callback
found 5 specs (6 tests, 1 pending)
Run component tests in parallel
If our component tests are realistic, they might take longer time to finish. An easy optimization is to run the Cypress tests in parallel using my plugin cypress-split. It supports component testing via --component flag.
Install the cypress-split plugin as a dev dependency
We are ready to split. While cypress-split supports any CI, we can use the split GitHub Actions workflow from my bahmutov/cypress-workflows reusable GH workflows to let it configure everything.
.github/workflows/ci.yml
1 2 3 4 5 6 7 8 9 10 11
name:ci on:push jobs: component-tests: # https://github.com/bahmutov/cypress-workflows uses:bahmutov/cypress-workflows/.github/workflows/split.yml@v1 with: # print the test names before-run:'npm run test-names --silent' component:true n:2
This is the entire workflow file. It installs all NPM dependencies, caches them, including Cypress binary, then runs the component tests splitting the tests across 2 machines. If you have more tests ... increment the n parameter.
The split jobs each output their spec and test summary