Skip to content

Commit

Permalink
feat: support split component tests (#25)
Browse files Browse the repository at this point in the history
* add a few components

* update dependencies

* feat: add support for component specs split

* add example with component split on github actions

* test-component
  • Loading branch information
bahmutov authored Feb 27, 2023
1 parent 8faef58 commit 47d2ba2
Show file tree
Hide file tree
Showing 12 changed files with 1,042 additions and 978 deletions.
29 changes: 27 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ jobs:
steps:
- name: Checkout 🛎
uses: actions/checkout@v3
- name: Run split Cypress tests 🧪

- name: Run split Cypress E2E tests 🧪
# https://github.com/cypress-io/github-action
uses: cypress-io/github-action@v5
with:
build: npm run test-names
# using operating system process environment variables
env:
SPEC: 'cypress/e2e/spec-b.cy.js,cypress/e2e/spec-e.cy.js'
Expand All @@ -58,6 +61,8 @@ jobs:
- name: Run split Cypress tests 🧪
# https://github.com/cypress-io/github-action
uses: cypress-io/github-action@v5
with:
build: npm run test-names
# using operating system process environment variables
env:
SPLIT: ${{ strategy.job-total }}
Expand All @@ -74,9 +79,29 @@ jobs:
with:
command: npm run empty

test-workflow-e2e:
# https://github.com/bahmutov/cypress-workflows
uses: bahmutov/cypress-workflows/.github/workflows/split.yml@v1
with:
n: 3

test-workflow-component:
# https://github.com/bahmutov/cypress-workflows
uses: bahmutov/cypress-workflows/.github/workflows/split.yml@v1
with:
component: true
n: 2

release:
if: github.ref == 'refs/heads/main'
needs: [test-empty, test-split, test-spec]
needs:
[
test-empty,
test-split,
test-spec,
test-workflow-e2e,
test-workflow-component,
]
runs-on: ubuntu-20.04
steps:
- name: Checkout 🛎
Expand Down
45 changes: 40 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,16 +192,45 @@ If you are running N containers in parallel, pass the zero-based index and the t

```
# using process OS environment variables
job1: SPLIT=3,SPLIT_INDEX=0 npx cypress run
job2: SPLIT=3,SPLIT_INDEX=1 npx cypress run
job3: SPLIT=3,SPLIT_INDEX=2 npx cypress run
job1: SPLIT=3 SPLIT_INDEX=0 npx cypress run
job2: SPLIT=3 SPLIT_INDEX=1 npx cypress run
job3: SPLIT=3 SPLIT_INDEX=2 npx cypress run
# using Cypress env option
job1: npx cypress run --env split=3,splitIndex=0
job2: npx cypress run --env split=3,splitIndex=1
job3: npx cypress run --env split=3,splitIndex=2
```

## Split component specs

Works the same way as splitting E2E specs. Add this plugin to the `setupNodeEvents` callback in the `component` object in the config. See [cypress.config.js](./cypress.config.js) for example:

```js
// cypress.config.js
const { defineConfig } = require('cypress')
const cypressSplit = require('cypress-split')
module.exports = defineConfig({
e2e: {
// baseUrl, etc
},
component: {
devServer: {
framework: 'react',
bundler: 'vite',
},
specPattern: 'components/*.cy.js',
setupNodeEvents(on, config) {
cypressSplit(on, config)
// IMPORTANT: return the config object
return config
},
},
})
```

## How does it work

This plugin finds the Cypress specs using [find-cypress-specs](https://github.com/bahmutov/find-cypress-specs) and then splits the list into chunks using the machine index and the total number of machines. On some CIs (GitLab, Circle), the machine index and the total number of machines are available in the environment variables. On other CIs, you have to be explicit and pass these numbers yourself.
Expand Down Expand Up @@ -232,8 +261,8 @@ You can still split the specs across several machines using `cypress-split`, jus
```
# using process environment variables split all specs across 2 machines
$ SPEC="spec1,spec2,spec3",SPLIT=2,SPLIT_INDEX=0 npx cypress run --spec "spec1,spec2,spec3"
$ SPEC="spec1,spec2,spec3",SPLIT=2,SPLIT_INDEX=1 npx cypress run --spec "spec1,spec2,spec3"
$ SPEC="spec1,spec2,spec3" SPLIT=2 SPLIT_INDEX=0 npx cypress run --spec "spec1,spec2,spec3"
$ SPEC="spec1,spec2,spec3" SPLIT=2 SPLIT_INDEX=1 npx cypress run --spec "spec1,spec2,spec3"

# using Cypress "env" option
$ npx cypress run --env split=2,splitIndex=0,spec="spec1,spec2,spec3"
Expand Down Expand Up @@ -274,6 +303,12 @@ To see diagnostic log messages from this plugin, set the environment variable `D

![Debug output](./images/debug-log.png)

**Tip:** `cypress-split` uses [find-cypress-specs](https://github.com/bahmutov/find-cypress-specs) to discover specs. If something is wrong, it is useful to see debug messages from both modules:

```
DEBUG=cypress-split,find-cypress-specs npx cypress run
```

## Small print

Author: Gleb Bahmutov <gleb.bahmutov@gmail.com> © 2023
Expand Down
3 changes: 3 additions & 0 deletions components/comp1.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe('Component 1', () => {
it('works', () => {})
})
3 changes: 3 additions & 0 deletions components/comp2.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe('Component 2', () => {
it('works', () => {})
})
13 changes: 13 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,17 @@ module.exports = defineConfig({
return config
},
},

component: {
devServer: {
framework: 'react',
bundler: 'vite',
},
specPattern: 'components/*.cy.js',
setupNodeEvents(on, config) {
cypressSplit(on, config)
// IMPORTANT: return the config object
return config
},
},
})
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
25 changes: 25 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
12 changes: 12 additions & 0 deletions cypress/support/component-index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Components App</title>
</head>
<body>
<div data-cy-root></div>
</body>
</html>
27 changes: 27 additions & 0 deletions cypress/support/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// ***********************************************************
// This example support/component.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'

// Alternatively you can use CommonJS syntax:
// require('./commands')

import { mount } from 'cypress/react'

Cypress.Commands.add('mount', mount)

// Example use:
// cy.mount(<MyComponent />)
Loading

0 comments on commit 47d2ba2

Please sign in to comment.