Skip to content

Commit cdb8941

Browse files
committed
Add tests with apollo-mocked-provider
1 parent c6b39d8 commit cdb8941

File tree

12 files changed

+16359
-11230
lines changed

12 files changed

+16359
-11230
lines changed

.eslintrc.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@ module.exports = {
22
extends: 'react-app',
33
plugins: ['graphql'],
44
parser: 'babel-eslint',
5+
globals: {
6+
wait: 'readonly',
7+
render: 'readonly',
8+
mockedRender: 'readonly',
9+
ApolloMockedProvider: 'readonly',
10+
ApolloErrorProvider: 'readonly',
11+
ApolloLoadingProvider: 'readonly',
12+
},
513
rules: {
614
'graphql/template-strings': [
715
'error',
@@ -15,5 +23,6 @@ module.exports = {
1523
schemaJson: require('./spacex.json'),
1624
},
1725
],
26+
'react/jsx-no-undef': ['error', { allowGlobals: true }],
1827
},
1928
}

package-lock.json

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

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"start": "EXTEND_ESLINT=true react-scripts start",
77
"build": "react-scripts build",
8-
"test": "react-scripts test",
8+
"test": "react-scripts test --env=jest-environment-jsdom-sixteen",
99
"eject": "react-scripts eject",
1010
"lint": "eslint src/",
1111
"update-schema": "apollo schema:download --endpoint https://api.graphql.guide/graphql schema.json",
@@ -14,15 +14,16 @@
1414
},
1515
"dependencies": {
1616
"@apollo/client": "^3.2.5",
17+
"@graphql-tools/wrap": "^7.0.1",
1718
"@material-ui/core": "3.9.3",
1819
"@material-ui/icons": "3.0.2",
19-
"@testing-library/jest-dom": "^4.2.4",
20-
"@testing-library/react": "^9.3.2",
21-
"@testing-library/user-event": "^7.1.2",
20+
"@testing-library/jest-dom": "^5.11.5",
21+
"@testing-library/react": "^11.1.1",
2222
"ajv": "6.12.3",
2323
"apollo": "^2.30.2",
2424
"apollo-cache-persist": "0.1.1",
2525
"apollo-link-rest": "0.8.0-beta.0",
26+
"apollo-mocked-provider": "^5.0.0",
2627
"apollo3-cache-persist": "^0.8.0",
2728
"auth0-helpers": "0.4.3",
2829
"auth0-js": "9.13.4",
@@ -33,6 +34,7 @@
3334
"eslint-plugin-graphql": "4.0.0",
3435
"graphql": "15.3.0",
3536
"graphql-anywhere": "4.2.7",
37+
"jest-environment-jsdom-sixteen": "^1.0.3",
3638
"jss": "^9.8.7",
3739
"lodash": "4.17.19",
3840
"react": "16.13.1",

src/components/App.test.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/components/Review.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export default ({ review }) => {
163163
}
164164
action={
165165
user && (
166-
<IconButton onClick={openMenu}>
166+
<IconButton aria-label="Open menu" onClick={openMenu}>
167167
<MoreVert />
168168
</IconButton>
169169
)

src/components/Reviews.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react'
2+
import { screen, fireEvent } from '@testing-library/react'
3+
4+
import Reviews from './Reviews'
5+
6+
describe('Reviews', () => {
7+
it('alerts when deleting', async () => {
8+
jest.spyOn(window, 'alert').mockImplementation(() => {})
9+
10+
mockedRender(<Reviews />, {
11+
Mutation: () => ({
12+
removeReview: () => {
13+
throw new Error('unauthorized')
14+
},
15+
}),
16+
})
17+
18+
await wait()
19+
fireEvent.click(screen.getAllByRole('button', { name: 'Open menu' })[0])
20+
await wait()
21+
fireEvent.click(screen.getAllByRole('menuitem', { name: 'Delete' })[0])
22+
await wait()
23+
fireEvent.click(screen.getAllByRole('button', { name: 'Sudo delete' })[0])
24+
await wait()
25+
expect(window.alert).toHaveBeenCalled()
26+
})
27+
})

src/components/Section.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ export default () => {
203203
<Skeleton />
204204
</h1>
205205
)
206-
sectionContent = <Skeleton count={7} />
206+
sectionContent = (
207+
<div role="status">
208+
<Skeleton count={7} />
209+
</div>
210+
)
207211
} else if (!section) {
208212
headerContent = (
209213
<h1>

src/components/Section.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react'
2+
import { screen } from '@testing-library/react'
3+
4+
import Section from './Section'
5+
6+
describe('Section', () => {
7+
it('should render loading status', async () => {
8+
render(
9+
<ApolloLoadingProvider>
10+
<Section />
11+
</ApolloLoadingProvider>
12+
)
13+
14+
screen.getByRole('status')
15+
await wait()
16+
screen.getByRole('status')
17+
})
18+
})

src/components/TableOfContents.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ import { SECTION_BY_ID_QUERY } from './Section'
99

1010
const LoadingSkeleton = () => (
1111
<div>
12+
<div className="sr-only" role="status">
13+
Loading...
14+
</div>
1215
<h1>
1316
<Skeleton />
1417
</h1>
1518
<Skeleton count={4} />
1619
</div>
1720
)
1821

19-
const CHAPTER_QUERY = gql`
22+
export const CHAPTER_QUERY = gql`
2023
query ChapterQuery {
2124
chapters {
2225
id
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React from 'react'
2+
import { screen } from '@testing-library/react'
3+
import { MockedProvider } from '@apollo/client/testing'
4+
5+
import TableOfContents, { CHAPTER_QUERY } from './TableOfContents'
6+
7+
const mocks = [
8+
{
9+
request: { query: CHAPTER_QUERY },
10+
result: {
11+
data: {
12+
chapters: [
13+
{
14+
id: 1,
15+
number: 1,
16+
title: 'mocks-title',
17+
sections: [
18+
{
19+
id: '1',
20+
number: 1,
21+
title: 'Hello World',
22+
},
23+
{
24+
id: '2',
25+
number: 2,
26+
title: 'Hello World',
27+
},
28+
],
29+
},
30+
{
31+
id: 2,
32+
number: 2,
33+
title: 'mocks-title',
34+
sections: [
35+
{
36+
id: '3',
37+
number: 3,
38+
title: 'Hello World',
39+
},
40+
{
41+
id: '4',
42+
number: 4,
43+
title: 'Hello World',
44+
},
45+
],
46+
},
47+
],
48+
},
49+
},
50+
},
51+
]
52+
53+
describe('TableOfContents', () => {
54+
it('renders loading status and chapters', async () => {
55+
mockedRender(<TableOfContents />, {
56+
Chapter: () => ({
57+
title: () => 'Chapter-title',
58+
}),
59+
})
60+
61+
screen.getByRole('status')
62+
await wait()
63+
screen.getAllByText('Chapter-title')
64+
})
65+
66+
it('works with MockedProvider', async () => {
67+
render(
68+
<MockedProvider mocks={mocks} addTypename={false}>
69+
<TableOfContents />
70+
</MockedProvider>
71+
)
72+
73+
await wait()
74+
screen.getAllByText('mocks-title')
75+
})
76+
})

src/index.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ code {
9999
padding: 0 5px;
100100
}
101101

102+
/* hidden, for screen readers only */
103+
/* https://stackoverflow.com/a/19758620/627729 */
104+
.sr-only {
105+
position: absolute;
106+
width: 1px;
107+
height: 1px;
108+
padding: 0;
109+
margin: -1px;
110+
overflow: hidden;
111+
clip: rect(0, 0, 0, 0);
112+
border: 0;
113+
}
114+
102115
.App-logo {
103116
height: 80px;
104117
}

src/setupTests.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from 'react'
2+
import {
3+
createApolloErrorProvider,
4+
createApolloMockedProvider,
5+
createApolloLoadingProvider,
6+
} from 'apollo-mocked-provider'
7+
import { ApolloLink } from '@apollo/client'
8+
import { printSchema, buildClientSchema } from 'graphql'
9+
import fs from 'fs'
10+
import { render, waitFor } from '@testing-library/react'
11+
import { createMemoryHistory } from 'history'
12+
import { Router } from 'react-router-dom'
13+
14+
import '@testing-library/jest-dom/extend-expect'
15+
16+
const responseLogger = new ApolloLink((operation, forward) => {
17+
return forward(operation).map((result) => {
18+
console.log(JSON.stringify(result, null, ' '))
19+
return result
20+
})
21+
})
22+
23+
const schema = JSON.parse(fs.readFileSync('schema.json'))
24+
const typeDefs = printSchema(buildClientSchema(schema.data))
25+
const ApolloMockedProvider = createApolloMockedProvider(typeDefs, {
26+
links: () => [responseLogger],
27+
})
28+
29+
global.ApolloMockedProvider = ApolloMockedProvider
30+
global.ApolloErrorProvider = createApolloErrorProvider()
31+
global.ApolloLoadingProvider = createApolloLoadingProvider()
32+
33+
const RouterWrapper = ({ children }) => {
34+
const history = createMemoryHistory()
35+
36+
return <Router history={history}>{children}</Router>
37+
}
38+
39+
global.render = (ui, options) =>
40+
render(ui, { wrapper: RouterWrapper, ...options })
41+
42+
global.mockedRender = (ui, customResolvers, options) => {
43+
let id = 1
44+
45+
const MockedWrapper = ({ children }) => (
46+
<RouterWrapper>
47+
<ApolloMockedProvider
48+
customResolvers={{
49+
Section: () => ({
50+
id: id++,
51+
number: id++,
52+
}),
53+
ObjID: () => id++,
54+
...customResolvers,
55+
}}
56+
>
57+
{children}
58+
</ApolloMockedProvider>
59+
</RouterWrapper>
60+
)
61+
62+
return render(ui, { wrapper: MockedWrapper, ...options })
63+
}
64+
65+
global.wait = () => waitFor(() => {})

0 commit comments

Comments
 (0)