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

Commit

Permalink
feat: add fetch polyfill if needed (#348)
Browse files Browse the repository at this point in the history
  • Loading branch information
bahmutov authored Jul 20, 2020
1 parent 1dcc167 commit ff4bdcc
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 3 deletions.
3 changes: 2 additions & 1 deletion cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
"**/__snapshots__/*",
"**/__image_snapshots__/*"
],
"experimentalComponentTesting": true
"experimentalComponentTesting": true,
"experimentalFetchPolyfill": true
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="cypress" />
/// <reference types="../../lib" />
import { Users } from './users.jsx'
import { Users } from './1-users.jsx'
import React from 'react'
import { mount } from 'cypress-react-unit-test'

Expand Down
67 changes: 67 additions & 0 deletions cypress/component/basic/network/2-users-fetch-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/// <reference types="cypress" />
/// <reference types="../../lib" />
import { Users } from './2-users-fetch.jsx'
import React from 'react'
import { mount } from 'cypress-react-unit-test'

describe('Users with Fetch', () => {
it('fetches 3 users from remote API', () => {
mount(<Users />)
// fetching users can take a while
cy.get('li', { timeout: 20000 }).should('have.length', 3)
})

// https://github.com/bahmutov/cypress-react-unit-test/issues/347
context('mocking', () => {
beforeEach(() => {
cy.server()
// mount the component after defining routes in tests
// preventing race conditions where you wait on untouched routes
})

it('can inspect real data from the server', () => {
// spy on the request
cy.route('/users?_limit=3').as('users')
mount(<Users />)
cy.wait('@users')
.its('response.body')
.should('have.length', 3)
.its('0')
.should('include.keys', ['id', 'name', 'username', 'email'])
})

it('can stub and display mock network response', () => {
const users = [{ id: 1, name: 'foo' }]
// stub the request
cy.route('GET', '/users?_limit=3', users).as('users')
mount(<Users />)
cy.get('li')
.should('have.length', 1)
.first()
.contains('foo')
})

it('can inspect mocked network reaponse', () => {
const users = [{ id: 1, name: 'foo' }]
cy.route('GET', '/users?_limit=3', users).as('users')
mount(<Users />)
cy.wait('@users')
.its('response.body')
.should('deep.equal', users)
})

it('can delay and wait on Ajax call', () => {
const users = [{ id: 1, name: 'foo' }]
cy.route({
method: 'GET',
url: '/users?_limit=3',
response: users,
delay: 1000,
}).as('users')
mount(<Users />)
cy.get('li').should('have.length', 0)
cy.wait('@users')
cy.get('li').should('have.length', 1)
})
})
})
34 changes: 34 additions & 0 deletions cypress/component/basic/network/2-users-fetch.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react'

export class Users extends React.Component {
constructor(props) {
super(props)
this.state = {
users: [],
}
}

componentDidMount() {
fetch('https://jsonplaceholder.cypress.io/users?_limit=3')
.then(response => {
return response.json()
})
.then(list => {
this.setState({
users: list,
})
})
}

render() {
return (
<div>
{this.state.users.map(user => (
<li key={user.id}>
<strong>{user.id}</strong> - {user.name}
</li>
))}
</div>
)
}
}
4 changes: 4 additions & 0 deletions cypress/component/basic/network/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Mocking network

- [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
- [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/)
20 changes: 20 additions & 0 deletions lib/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// @ts-ignore
const unfetch = require('unfetch/dist/unfetch.js')
// @ts-ignore
const isComponentSpec = () => Cypress.spec.specType === 'component'

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

/**
* Replaces window.fetch with a polyfill based on XMLHttpRequest
* that Cypress can spy on and stub
* @see https://www.cypress.io/blog/2020/06/29/experimental-fetch-polyfill/
*/
function polyfillFetchIfNeeded() {
// @ts-ignore
if (Cypress.config('experimentalFetchPolyfill')) {
if (!cy.state('fetchPolyfilled')) {
delete window.fetch
window.fetch = unfetch
// @ts-ignore
cy.state('fetchPolyfilled', true)
}
}
}

before(() => {
if (!isComponentSpec()) {
return
}

polyfillFetchIfNeeded()
renderTestingPlatform()
})

Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@
"babel-plugin-istanbul": "6.0.0",
"debug": "4.1.1",
"find-webpack": "2.0.0",
"mime-types": "2.1.26"
"mime-types": "2.1.26",
"unfetch": "4.1.0"
},
"release": {
"branches": [
Expand Down

0 comments on commit ff4bdcc

Please sign in to comment.