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

Commit ff4bdcc

Browse files
authored
feat: add fetch polyfill if needed (#348)
1 parent 1dcc167 commit ff4bdcc

File tree

9 files changed

+135
-3
lines changed

9 files changed

+135
-3
lines changed

cypress.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
"**/__snapshots__/*",
1515
"**/__image_snapshots__/*"
1616
],
17-
"experimentalComponentTesting": true
17+
"experimentalComponentTesting": true,
18+
"experimentalFetchPolyfill": true
1819
}

cypress/component/basic/network/users-spec.js renamed to cypress/component/basic/network/1-users-spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="cypress" />
22
/// <reference types="../../lib" />
3-
import { Users } from './users.jsx'
3+
import { Users } from './1-users.jsx'
44
import React from 'react'
55
import { mount } from 'cypress-react-unit-test'
66

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/// <reference types="cypress" />
2+
/// <reference types="../../lib" />
3+
import { Users } from './2-users-fetch.jsx'
4+
import React from 'react'
5+
import { mount } from 'cypress-react-unit-test'
6+
7+
describe('Users with Fetch', () => {
8+
it('fetches 3 users from remote API', () => {
9+
mount(<Users />)
10+
// fetching users can take a while
11+
cy.get('li', { timeout: 20000 }).should('have.length', 3)
12+
})
13+
14+
// https://github.com/bahmutov/cypress-react-unit-test/issues/347
15+
context('mocking', () => {
16+
beforeEach(() => {
17+
cy.server()
18+
// mount the component after defining routes in tests
19+
// preventing race conditions where you wait on untouched routes
20+
})
21+
22+
it('can inspect real data from the server', () => {
23+
// spy on the request
24+
cy.route('/users?_limit=3').as('users')
25+
mount(<Users />)
26+
cy.wait('@users')
27+
.its('response.body')
28+
.should('have.length', 3)
29+
.its('0')
30+
.should('include.keys', ['id', 'name', 'username', 'email'])
31+
})
32+
33+
it('can stub and display mock network response', () => {
34+
const users = [{ id: 1, name: 'foo' }]
35+
// stub the request
36+
cy.route('GET', '/users?_limit=3', users).as('users')
37+
mount(<Users />)
38+
cy.get('li')
39+
.should('have.length', 1)
40+
.first()
41+
.contains('foo')
42+
})
43+
44+
it('can inspect mocked network reaponse', () => {
45+
const users = [{ id: 1, name: 'foo' }]
46+
cy.route('GET', '/users?_limit=3', users).as('users')
47+
mount(<Users />)
48+
cy.wait('@users')
49+
.its('response.body')
50+
.should('deep.equal', users)
51+
})
52+
53+
it('can delay and wait on Ajax call', () => {
54+
const users = [{ id: 1, name: 'foo' }]
55+
cy.route({
56+
method: 'GET',
57+
url: '/users?_limit=3',
58+
response: users,
59+
delay: 1000,
60+
}).as('users')
61+
mount(<Users />)
62+
cy.get('li').should('have.length', 0)
63+
cy.wait('@users')
64+
cy.get('li').should('have.length', 1)
65+
})
66+
})
67+
})
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react'
2+
3+
export class Users extends React.Component {
4+
constructor(props) {
5+
super(props)
6+
this.state = {
7+
users: [],
8+
}
9+
}
10+
11+
componentDidMount() {
12+
fetch('https://jsonplaceholder.cypress.io/users?_limit=3')
13+
.then(response => {
14+
return response.json()
15+
})
16+
.then(list => {
17+
this.setState({
18+
users: list,
19+
})
20+
})
21+
}
22+
23+
render() {
24+
return (
25+
<div>
26+
{this.state.users.map(user => (
27+
<li key={user.id}>
28+
<strong>{user.id}</strong> - {user.name}
29+
</li>
30+
))}
31+
</div>
32+
)
33+
}
34+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Mocking network
2+
3+
- [1-users-spec.js](1-users-spec.js) tests [1-users.jsx](1-users.jsx) that uses Axios to GET a list of users. Axios uses XMLHttpRequest to receive the data
4+
- [2-users-fetch-spec.js](2-users-fetch-spec.js) tests [2-users-fetch.jsx](2-users-fetch.jsx) that uses `fetch` directly, assuming `"experimentalFetchPolyfill": true` in `cypress.json`, read [Experimental Fetch Polyfill](https://www.cypress.io/blog/2020/06/29/experimental-fetch-polyfill/)

lib/hooks.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// @ts-ignore
2+
const unfetch = require('unfetch/dist/unfetch.js')
3+
// @ts-ignore
24
const isComponentSpec = () => Cypress.spec.specType === 'component'
35

46
// When running component specs, we cannot allow "cy.visit"
@@ -34,11 +36,29 @@ function renderTestingPlatform() {
3436
return cy.get(selector, { log: false })
3537
}
3638

39+
/**
40+
* Replaces window.fetch with a polyfill based on XMLHttpRequest
41+
* that Cypress can spy on and stub
42+
* @see https://www.cypress.io/blog/2020/06/29/experimental-fetch-polyfill/
43+
*/
44+
function polyfillFetchIfNeeded() {
45+
// @ts-ignore
46+
if (Cypress.config('experimentalFetchPolyfill')) {
47+
if (!cy.state('fetchPolyfilled')) {
48+
delete window.fetch
49+
window.fetch = unfetch
50+
// @ts-ignore
51+
cy.state('fetchPolyfilled', true)
52+
}
53+
}
54+
}
55+
3756
before(() => {
3857
if (!isComponentSpec()) {
3958
return
4059
}
4160

61+
polyfillFetchIfNeeded()
4262
renderTestingPlatform()
4363
})
4464

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@
131131
"babel-plugin-istanbul": "6.0.0",
132132
"debug": "4.1.1",
133133
"find-webpack": "2.0.0",
134-
"mime-types": "2.1.26"
134+
"mime-types": "2.1.26",
135+
"unfetch": "4.1.0"
135136
},
136137
"release": {
137138
"branches": [

0 commit comments

Comments
 (0)