Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,15 @@
"contributions": [
"code"
]
},
{
"login": "suddenlyGiovanni",
"name": "Giovanni Ravalico",
"avatar_url": "https://avatars2.githubusercontent.com/u/15946771?v=4",
"profile": "https://suddenlyGiovanni.dev",
"contributions": [
"ideas"
]
}
],
"contributorsPerLine": 7,
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ Thanks goes to these wonderful people
</tr>
<tr>
<td align="center"><a href="https://github.com/jwm0"><img src="https://avatars0.githubusercontent.com/u/28310983?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jakub Majorek</b></sub></a><br /><a href="https://github.com/kentcdodds/advanced-react-hooks/commits?author=jwm0" title="Code">💻</a></td>
<td align="center"><a href="https://suddenlyGiovanni.dev"><img src="https://avatars2.githubusercontent.com/u/15946771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Giovanni Ravalico</b></sub></a><br /><a href="#ideas-suddenlyGiovanni" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
</table>

Expand Down
1,258 changes: 636 additions & 622 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 15 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
"npm": ">=6"
},
"dependencies": {
"@kentcdodds/react-workshop-app": "^2.20.0",
"@testing-library/react": "^11.2.2",
"@testing-library/user-event": "^12.5.0",
"@kentcdodds/react-workshop-app": "^3.0.0",
"@testing-library/react": "^11.2.3",
"@testing-library/user-event": "^12.6.2",
"chalk": "^4.1.0",
"codegen.macro": "^4.0.0",
"codegen.macro": "^4.1.0",
"mq-polyfill": "^1.1.8",
"react": "^17.0.1",
"react-dom": "^17.0.1",
Expand All @@ -26,10 +26,11 @@
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"husky": "^4.3.5",
"husky": "^4.3.8",
"npm-run-all": "^4.1.5",
"prettier": "^2.2.1",
"react-scripts": "^4.0.1"
"react-scripts": "^4.0.1",
"typescript": "^4.1.3"
},
"scripts": {
"start": "react-scripts start",
Expand All @@ -53,7 +54,14 @@
]
},
"eslintConfig": {
"extends": "react-app"
"extends": [
"react-app",
"react-app/jest",
"plugin:jsx-a11y/recommended"
],
"plugins": [
"jsx-a11y"
]
},
"babel": {
"presets": [
Expand Down
72 changes: 54 additions & 18 deletions public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/* eslint-disable */
/* tslint:disable */

const INTEGRITY_CHECKSUM = 'd1e0e502f550d40a34bee90822e4bf98'
const INTEGRITY_CHECKSUM = '7a54d6f8bbbda3fb393dcd9176d1fd19'
const bypassHeaderName = 'x-msw-bypass'

let clients = {}
Expand Down Expand Up @@ -74,11 +74,23 @@ self.addEventListener('message', async function (event) {
}
})

self.addEventListener('fetch', async function (event) {
self.addEventListener('fetch', function (event) {
const { clientId, request } = event
const requestId = uuidv4()
const requestClone = request.clone()
const getOriginalResponse = () => fetch(requestClone)

// Bypass navigation requests.
if (request.mode === 'navigate') {
return
}

// Bypass mocking if the current client isn't present in the internal clients map
// (i.e. has the mocking disabled).
if (!clients[clientId]) {
return
}

// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
Expand All @@ -89,20 +101,15 @@ self.addEventListener('fetch', async function (event) {
new Promise(async (resolve, reject) => {
const client = await event.target.clients.get(clientId)

if (
// Bypass mocking when no clients active
!client ||
// Bypass mocking if the current client has mocking disabled
!clients[clientId] ||
// Bypass mocking for navigation requests
request.mode === 'navigate'
) {
// Bypass mocking when the request client is not active.
if (!client) {
return resolve(getOriginalResponse())
}

// Bypass requests with the explicit bypass header
if (requestClone.headers.get(bypassHeaderName) === 'true') {
const modifiedHeaders = serializeHeaders(requestClone.headers)

// Remove the bypass header to comply with the CORS preflight check
delete modifiedHeaders[bypassHeaderName]

Expand All @@ -119,6 +126,7 @@ self.addEventListener('fetch', async function (event) {
const rawClientMessage = await sendToClient(client, {
type: 'REQUEST',
payload: {
id: requestId,
url: request.url,
method: request.method,
headers: reqHeaders,
Expand Down Expand Up @@ -180,14 +188,34 @@ If you wish to mock an error response, please refer to this guide: https://mswjs
return resolve(createResponse(clientMessage))
}
}
}).catch((error) => {
console.error(
'[MSW] Failed to mock a "%s" request to "%s": %s',
request.method,
request.url,
error,
)
}),
})
.then(async (response) => {
const client = await event.target.clients.get(clientId)
const clonedResponse = response.clone()

sendToClient(client, {
type: 'RESPONSE',
payload: {
requestId,
ok: clonedResponse.ok,
status: clonedResponse.status,
statusText: clonedResponse.statusText,
body: await clonedResponse.text(),
headers: serializeHeaders(clonedResponse.headers),
redirected: clonedResponse.redirected,
},
})

return response
})
.catch((error) => {
console.error(
'[MSW] Failed to mock a "%s" request to "%s": %s',
request.method,
request.url,
error,
)
}),
)
})

Expand Down Expand Up @@ -233,3 +261,11 @@ function ensureKeys(keys, obj) {
return acc
}, {})
}

function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (Math.random() * 16) | 0
const v = c == 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
}
6 changes: 5 additions & 1 deletion src/__tests__/01.js → src/__tests__/01.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import * as React from 'react'
import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/01'
import App from '../final/01.js'
// import App from '../final-ts/01'
// import App from '../exercise/01'

test('clicking the button increments the count with useReducer', () => {
jest.spyOn(React, 'useReducer')

const {container} = render(<App />)
const button = container.querySelector('button')
if (!button) {
throw new Error('button node is null')
}
userEvent.click(button)
expect(button).toHaveTextContent('1')
userEvent.click(button)
Expand Down
18 changes: 11 additions & 7 deletions src/__tests__/02.extra-3.js → src/__tests__/02.extra-3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/02.extra-3'
// import App from '../final-ts/02.extra-3'
// import App from '../exercise/02'

let fetchSpy: jest.SpyInstance
let consoleErrorSpy: jest.SpyInstance

beforeEach(() => {
jest.spyOn(window, 'fetch')
jest.spyOn(console, 'error')
fetchSpy = jest.spyOn(window, 'fetch')
consoleErrorSpy = jest.spyOn(console, 'error')
})

afterEach(() => {
window.fetch.mockRestore()
console.error.mockRestore()
fetchSpy.mockRestore()
consoleErrorSpy.mockRestore()
})

test('displays the pokemon', async () => {
Expand All @@ -34,7 +38,7 @@ test('displays the pokemon', async () => {
await screen.findByRole('heading', {name: /ditto/i})

// verify that when props remain the same a request is not made
window.fetch.mockClear()
fetchSpy.mockClear()

userEvent.click(submit)

Expand All @@ -46,7 +50,7 @@ test('displays the pokemon', async () => {
)

// verify error handling
console.error.mockImplementation(() => {})
consoleErrorSpy.mockImplementation(() => {})

userEvent.clear(input)
userEvent.type(input, 'george')
Expand All @@ -56,7 +60,7 @@ test('displays the pokemon', async () => {
)
expect(console.error).toHaveBeenCalledTimes(2)

console.error.mockReset()
consoleErrorSpy.mockReset()

userEvent.type(input, 'mew')
userEvent.click(submit)
Expand Down
20 changes: 12 additions & 8 deletions src/__tests__/02.js → src/__tests__/02.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import * as React from 'react'
import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/02'
// import App from '../final/02'
import App from '../final-ts/02'
// import App from '../exercise/02'

let spyFetch: jest.SpyInstance
let spyConsoleError: jest.SpyInstance

beforeEach(() => {
jest.spyOn(window, 'fetch')
jest.spyOn(console, 'error')
spyFetch = jest.spyOn(window, 'fetch')
spyConsoleError = jest.spyOn(console, 'error')
})

afterEach(() => {
window.fetch.mockRestore()
console.error.mockRestore()
spyFetch.mockRestore()
spyConsoleError.mockRestore()
})

test('displays the pokemon', async () => {
Expand All @@ -34,7 +38,7 @@ test('displays the pokemon', async () => {
await screen.findByRole('heading', {name: /ditto/i})

// verify that when props remain the same a request is not made
window.fetch.mockClear()
spyFetch.mockClear()

userEvent.click(submit)

Expand All @@ -46,7 +50,7 @@ test('displays the pokemon', async () => {
)

// verify error handling
console.error.mockImplementation(() => {})
spyConsoleError.mockImplementation(() => {})

userEvent.clear(input)
userEvent.type(input, 'george')
Expand All @@ -56,5 +60,5 @@ test('displays the pokemon', async () => {
)
expect(console.error).toHaveBeenCalledTimes(2)

console.error.mockReset()
spyConsoleError.mockReset()
})
20 changes: 12 additions & 8 deletions src/__tests__/03.extra-2.js → src/__tests__/03.extra-2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/03.extra-2'
// import App from '../final-ts/03.extra-2'
// import App from '../exercise/03.extra-2'

let fetchSpy: jest.SpyInstance
let consoleErrorSpy: jest.SpyInstance

beforeEach(() => {
jest.spyOn(window, 'fetch')
jest.spyOn(console, 'error')
fetchSpy = jest.spyOn(window, 'fetch')
consoleErrorSpy = jest.spyOn(console, 'error')
})

afterEach(() => {
window.fetch.mockRestore()
console.error.mockRestore()
fetchSpy.mockRestore()
consoleErrorSpy.mockRestore()
})

test('displays the pokemon', async () => {
Expand All @@ -34,7 +38,7 @@ test('displays the pokemon', async () => {
await screen.findByRole('heading', {name: /ditto/i})

// verify that when props remain the same a request is not made
window.fetch.mockClear()
fetchSpy.mockClear()

userEvent.click(submit)

Expand All @@ -46,7 +50,7 @@ test('displays the pokemon', async () => {
)

// verify error handling
console.error.mockImplementation(() => {})
consoleErrorSpy.mockImplementation(() => {})

userEvent.clear(input)
userEvent.type(input, 'george')
Expand All @@ -56,8 +60,8 @@ test('displays the pokemon', async () => {
)
expect(console.error).toHaveBeenCalledTimes(2)

console.error.mockReset()
window.fetch.mockClear()
consoleErrorSpy.mockReset()
fetchSpy.mockClear()

// use the cached value
userEvent.click(screen.getByRole('button', {name: /ditto/i}))
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/03.js → src/__tests__/03.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/03'
// import App from '../final-ts/03'
// import App from '../exercise/03'

test('clicking the button increments the count', () => {
Expand Down
5 changes: 3 additions & 2 deletions src/__tests__/04.js → src/__tests__/04.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react'
import {render} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/04'
// import App from '../final-ts/04'
// import App from '../exercise/04'

test('adds and removes children from the log', () => {
Expand All @@ -24,12 +25,12 @@ test('scrolls to the bottom', () => {
const scrollTopSetter = jest.fn()
Object.defineProperties(log, {
scrollHeight: {
get() {
get(): number {
return 100
},
},
scrollTop: {
get() {
get(): number {
return 0
},
set: scrollTopSetter,
Expand Down
Loading