Skip to content
This repository was archived by the owner on Mar 5, 2022. It is now read-only.

Commit b315795

Browse files
authored
feat: Use custom Babel module to enable named imports mocking (#265)
1 parent de07da9 commit b315795

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+358
-14
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ Folder Name | Description
174174
[visual-testing-with-percy](examples/visual-testing-with-percy) | [Visual testing](#visual-testing) for components using 3rd party service [Percy.io](https://percy.io/)
175175
[visual-testing-with-happo](examples/visual-testing-with-happo) | [Visual testing](#visual-testing) for components using 3rd party service [Happo](https://happo.io/)
176176
[using-babel](examples/using-babel) | Bundling specs and loaded source files using project's existing `.babelrc` file
177+
[webpack-file](examples/webpack-file) | Load existing `webpack.config.js` file
177178
[webpack-options](examples/webpack-options) | Using the default Webpack options from `@cypress/webpack-preprocessor` to transpile JSX specs
178179
<!-- prettier-ignore-end -->
179180

circle.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ executors:
66
base-12-16-2:
77
docker:
88
- image: 'cypress/base:12.16.2'
9+
environment:
10+
DEBUG: find-webpack,cypress-react-unit-test
911

1012
workflows:
1113
build:
@@ -117,6 +119,26 @@ workflows:
117119
npm run only-covered
118120
working_directory: examples/tailwind
119121

122+
- cypress/run:
123+
name: Example Webpack file
124+
executor: base-12-16-2
125+
requires:
126+
- Install
127+
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
128+
install-command: npm install
129+
verify-command: echo 'Already verified'
130+
no-workspace: true
131+
working_directory: examples/webpack-file
132+
command: npm test
133+
store_artifacts: true
134+
post-steps:
135+
- run:
136+
name: Check coverage 📈
137+
command: |
138+
npm run check-coverage
139+
npm run only-covered
140+
working_directory: examples/webpack-file
141+
120142
- cypress/run:
121143
name: Example Webpack options
122144
executor: cypress/base-12
@@ -271,6 +293,7 @@ workflows:
271293
- Example Sass
272294
- Example Snapshots
273295
- Example Tailwind
296+
- Example Webpack file
274297
- Example Webpack options
275298
- Visual Sudoku
276299
- Visual with Percy

examples/react-scripts-folder/cypress.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"fixturesFolder": false,
33
"testFiles": "**/*cy-spec.js",
44
"viewportWidth": 500,
5-
"viewportHeight": 500,
5+
"viewportHeight": 800,
66
"experimentalComponentTesting": true,
77
"componentFolder": "cypress/component"
88
}

examples/react-scripts-folder/cypress/component/App.cy-spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import React from 'react'
44
import App from '../../src/App'
55
import { mount } from 'cypress-react-unit-test'
6+
import * as calc from '../../src/calc'
7+
import * as child from '../../src/Child'
68

79
describe('App', () => {
810
it('renders learn react link', () => {
@@ -15,4 +17,26 @@ describe('App', () => {
1517
mount(<div>JSX</div>)
1618
cy.contains('JSX')
1719
})
20+
21+
it('controls the random number by stubbing named import', () => {
22+
// we are stubbing "getRandomNumber" exported by "calc.js"
23+
// and imported into "App.js" and called.
24+
cy.stub(calc, 'getRandomNumber')
25+
.as('lucky')
26+
.returns(777)
27+
mount(<App />)
28+
cy.contains('.random', '777')
29+
cy.get('@lucky').should('be.calledOnce')
30+
})
31+
32+
it('stubs an imported child component', () => {
33+
cy.stub(child, 'Child')
34+
.as('child')
35+
.returns(<div className="mock-child">Mock child component</div>)
36+
mount(<App />)
37+
// App component rendered our mock child component!
38+
cy.contains('Mock child component')
39+
cy.get('@child').should('have.been.calledTwice')
40+
cy.get('.mock-child').should('have.length', 2)
41+
})
1842
})

examples/react-scripts-folder/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"scripts": {
66
"test": "../../node_modules/.bin/cypress run",
77
"cy:open": "../../node_modules/.bin/cypress open",
8-
"check-coverage": "../../node_modules/.bin/check-coverage src/App.js",
9-
"only-covered": "../../node_modules/.bin/only-covered src/App.js"
8+
"check-coverage": "../../node_modules/.bin/check-coverage src/App.js src/calc.js src/Child.js",
9+
"only-covered": "../../node_modules/.bin/only-covered src/App.js src/calc.js src/Child.js"
1010
},
1111
"devDependencies": {
1212
"cypress-react-unit-test": "file:../.."

examples/react-scripts-folder/src/App.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import React from 'react'
33
import './App.css'
44
import logo from './logo.svg' // => "/__root/src/logo.svg"
55
import cypressLogo from './cypress-logo-dark.png' // => "/__root/src/cypress-logo-dark.png"
6+
import { getRandomNumber } from './calc'
7+
import { Child } from './Child'
68

79
// large image will be transformed into
810
// a different url static/media/vans.25e5784d.jpg
@@ -22,6 +24,7 @@ function App() {
2224
<p>
2325
Edit <code>src/App.js</code> and save to reload.
2426
</p>
27+
<p className="random">This is a random number {getRandomNumber()}</p>
2528
<a
2629
className="App-link"
2730
href="https://reactjs.org"
@@ -31,6 +34,8 @@ function App() {
3134
Learn React
3235
</a>
3336
</header>
37+
<Child />
38+
<Child />
3439
</div>
3540
)
3641
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import React from 'react'
2+
3+
export const Child = () => <div>Real child component</div>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const getRandomNumber = () => Math.round(Math.random() * 1000)

examples/react-scripts/cypress.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"fixturesFolder": false,
33
"testFiles": "**/*cy-spec.js",
44
"viewportWidth": 500,
5-
"viewportHeight": 500,
5+
"viewportHeight": 800,
66
"experimentalComponentTesting": true,
77
"componentFolder": "src"
88
}

examples/react-scripts/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"scripts": {
66
"test": "../../node_modules/.bin/cypress run",
77
"cy:open": "../../node_modules/.bin/cypress open",
8-
"check-coverage": "../../node_modules/.bin/check-coverage src/App.js",
9-
"only-covered": "../../node_modules/.bin/only-covered src/App.js"
8+
"check-coverage": "../../node_modules/.bin/check-coverage src/App.js src/calc.js src/Child.js",
9+
"only-covered": "../../node_modules/.bin/only-covered src/App.js src/calc.js src/Child.js"
1010
},
1111
"devDependencies": {
1212
"cypress-react-unit-test": "file:../.."

examples/react-scripts/src/App.cy-spec.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,33 @@
33
import React from 'react'
44
import App from './App'
55
import { mount } from 'cypress-react-unit-test'
6+
import * as calc from './calc'
7+
import * as Child from './Child'
68

79
describe('App', () => {
810
it('renders learn react link', () => {
911
mount(<App />)
1012
cy.contains(/Learn React/)
1113
})
14+
15+
it('controls the random number by stubbing named import', () => {
16+
// we are stubbing "getRandomNumber" exported by "calc.js"
17+
// and imported into "App.js" and called.
18+
cy.stub(calc, 'getRandomNumber').returns(777)
19+
mount(<App />)
20+
cy.contains('.random', '777')
21+
22+
// getRandomNumber was also used by the Child component
23+
// let's check that it was mocked too
24+
cy.contains('.child', 'Real child component, random 777')
25+
})
26+
27+
it('can mock the child component', () => {
28+
// Child component we want to stub is the default export
29+
cy.stub(Child, 'default')
30+
.as('child')
31+
.returns(<div className="mock-child">Mock Child component</div>)
32+
mount(<App />)
33+
cy.contains('.mock-child', 'Mock Child')
34+
})
1235
})

examples/react-scripts/src/App.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import React from 'react'
33
import './App.css'
44
import logo from './logo.svg' // => "/__root/src/logo.svg"
55
import cypressLogo from './cypress-logo-dark.png' // => "/__root/src/cypress-logo-dark.png"
6+
import { getRandomNumber } from './calc'
7+
import Child from './Child'
68

79
// large image will be transformed into
810
// a different url static/media/vans.25e5784d.jpg
@@ -22,6 +24,8 @@ function App() {
2224
<p>
2325
Edit <code>src/App.js</code> and save to reload.
2426
</p>
27+
<p className="random">This is a random number {getRandomNumber()}</p>
28+
<Child />
2529
<a
2630
className="App-link"
2731
href="https://reactjs.org"

examples/react-scripts/src/Child.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react'
2+
const calc = require('./calc')
3+
4+
const Child = () => (
5+
<div className="child">
6+
Real child component, random {calc.getRandomNumber()}
7+
</div>
8+
)
9+
10+
export default Child

examples/react-scripts/src/calc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const getRandomNumber = () => Math.round(Math.random() * 1000)

examples/using-babel/.babelrc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,20 @@
88
"@emotion/babel-preset-css-prop"
99
],
1010
"env": {
11+
// TODO switch this to "development" name
1112
"test": {
1213
"plugins": [
13-
"babel-plugin-istanbul"
14+
// during Cypress tests we want to instrument source code
15+
// to get code coverage from tests
16+
"babel-plugin-istanbul",
17+
// we also want to export ES6 modules as objects
18+
// to allow mocking named imports
19+
[
20+
"@babel/plugin-transform-modules-commonjs",
21+
{
22+
"loose": true
23+
}
24+
]
1425
]
1526
}
1627
}

examples/using-babel/src/Mock.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference types="cypress" />
2+
import React from 'react'
3+
import { mount } from 'cypress-react-unit-test'
4+
import Post from './Post'
5+
import * as calc from './calc'
6+
7+
describe('Mocking', () => {
8+
// https://github.com/bahmutov/cypress-react-unit-test/issues/266
9+
it.skip('mocks import used by the Post', () => {
10+
cy.stub(calc, 'getRandomNumber')
11+
.as('lucky')
12+
.returns(777)
13+
mount(<Post title="post title" children="post text" />)
14+
cy.contains('.random', '777')
15+
})
16+
})

examples/using-babel/src/Post.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
33
import Skeleton from 'react-loading-skeleton'
4+
import { getRandomNumber } from './calc'
45

56
export default class Post extends Component {
67
static propTypes = {
@@ -30,6 +31,7 @@ export default class Post extends Component {
3031
<div style={this.getStyle()}>
3132
<h1>{this.props.title || <Skeleton />}</h1>
3233
<p>{this.props.children || <Skeleton count={5} />}</p>
34+
<p className="random">random id {getRandomNumber()}</p>
3335
</div>
3436
)
3537
}

examples/using-babel/src/calc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const getRandomNumber = () => Math.round(Math.random() * 1000)

examples/webpack-file/.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["@babel/preset-env", "@babel/preset-react"]
3+
}

examples/webpack-file/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

examples/webpack-file/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# example: webpack-file
2+
3+
> Component tests for projects using existing [webpack.config.js](webpack.config.js) file
4+
5+
Note: run `npm install` in this folder to symlink `cypress-react-unit-test` dependency.
6+
7+
```shell
8+
npm run cy:open
9+
# or run headless tests
10+
npm test
11+
```
12+
13+
See tests in the [cypress/component](cypress/component) folder.

examples/webpack-file/cypress.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"fixturesFolder": false,
3+
"testFiles": "**/*cy-spec.js",
4+
"viewportWidth": 500,
5+
"viewportHeight": 500,
6+
"experimentalComponentTesting": true
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react'
2+
import { getRandomNumber } from './calc'
3+
4+
const ChildComponent = () => (
5+
<div>
6+
Child component <p className="random">Random number {getRandomNumber()}</p>
7+
</div>
8+
)
9+
10+
export default ChildComponent
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference types="cypress" />
2+
import React from 'react'
3+
import { mount } from 'cypress-react-unit-test'
4+
import ParentComponent from './ParentComponent'
5+
import * as calc from './calc'
6+
import * as ChildComponent from './ChildComponent'
7+
8+
describe('Mocking', () => {
9+
it('named getRandomNumber imported in the child component', () => {
10+
cy.stub(calc, 'getRandomNumber')
11+
.as('lucky')
12+
.returns(777)
13+
mount(<ParentComponent />)
14+
cy.contains('.random', '777')
15+
})
16+
17+
it('entire child component exported as default', () => {
18+
cy.stub(ChildComponent, 'default')
19+
.as('child')
20+
.returns(<div className="mock-child">Mock child component</div>)
21+
mount(<ParentComponent />)
22+
cy.contains('.mock-child', 'Mock child component')
23+
})
24+
})
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react'
2+
import ChildComponent from './ChildComponent'
3+
4+
const ParentComponent = () => (
5+
<div>
6+
Parent component, child component below
7+
<br />
8+
<ChildComponent />
9+
</div>
10+
)
11+
12+
export default ParentComponent
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react'
2+
import { mount } from 'cypress-react-unit-test'
3+
import Test from './Test'
4+
5+
describe('components', () => {
6+
it('works', () => {
7+
mount(<Test />)
8+
cy.contains('Text')
9+
})
10+
11+
it('works with plain div', () => {
12+
mount(<div>Text</div>)
13+
cy.contains('Text')
14+
})
15+
})
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import React from 'react'
2+
3+
const Test = () => <div>Text</div>
4+
5+
export default Test
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const getRandomNumber = () => Math.round(Math.random() * 1000)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// <reference types="cypress" />
2+
describe('integration spec', () => {
3+
it('works', () => {
4+
expect(1).to.equal(1)
5+
})
6+
})
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = (on, config) => {
2+
// from the root of the project (folder with cypress.json file)
3+
config.env.webpackFilename = 'webpack.config.js'
4+
require('cypress-react-unit-test/plugins/load-webpack')(on, config)
5+
// IMPORTANT to return the config object
6+
// with the any changed environment variables
7+
return config
8+
}

0 commit comments

Comments
 (0)