Skip to content

Commit e842329

Browse files
committed
feat: replace use of enzyme with react-testing-library
- added @testing-library/react to graphiql package - added @testing-libary/jest-dom to graphiql package - removed usage of ENZYM env variable in test script in graphiql packaget - removed enzyme adapter setup from enzyme.config.js file and renamed it to test.config.js - removed use of enzyme and replaced with react-testing-library in all graphiql package test files and updated tests to use react-testing-library patterns - moved mockStorage to own file so it can be reused in other test files and added other methods to it - added a CodeMirror mock to be used in tests - mocked out codemirror addon modules - moved QueryHistory tests from own file into GraphiQL.spec.js file
1 parent e90f243 commit e842329

File tree

13 files changed

+613
-591
lines changed

13 files changed

+613
-591
lines changed

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module.exports = {
1010
},
1111
clearMocks: true,
1212
collectCoverage: true,
13-
setupFiles: [path.join(__dirname, '/resources/enzyme.config.js')],
13+
setupFiles: [path.join(__dirname, '/resources/test.config.js')],
1414
testMatch: [
1515
'<rootDir>/packages/*/src/**/*-test.{js,ts}',
1616
'<rootDir>/packages/*/src/**/*.spec.{js,ts}',

packages/graphiql/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"cypress-open": "yarn e2e-server 'cypress open'",
3939
"e2e": "yarn e2e-server 'cypress run'",
4040
"e2e-server": "start-server-and-test 'cross-env PORT=8080 node test/e2e-server' 'http-get://localhost:8080/graphql?query={test { id }}'",
41-
"test": "cross-env ENZYME=true node ../../resources/runTests"
41+
"test": "cross-env node ../../resources/runTests"
4242
},
4343
"dependencies": {
4444
"codemirror": "^5.47.0",
@@ -55,11 +55,11 @@
5555
"react-dom": "^16.8.0"
5656
},
5757
"devDependencies": {
58+
"@testing-library/jest-dom": "4.2.4",
59+
"@testing-library/react": "9.4.0",
5860
"cross-env": "^6.0.3",
5961
"css-loader": "3.4.0",
6062
"cssnano": "^4.1.10",
61-
"enzyme": "^3.10.0",
62-
"enzyme-adapter-react-16": "^1.15.1",
6363
"express": "5.0.0-alpha.5",
6464
"express-graphql": "0.9.0",
6565
"graphql": "14.5.8",

packages/graphiql/src/components/DocExplorer/__tests__/FieldDoc.spec.js

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
*/
77

88
import React from 'react';
9-
import { mount } from 'enzyme';
9+
import { render } from '@testing-library/react';
10+
import '@testing-library/jest-dom/extend-expect';
1011

1112
import FieldDoc from '../FieldDoc';
1213

@@ -35,47 +36,58 @@ const exampleObject = new GraphQLObjectType({
3536

3637
describe('FieldDoc', () => {
3738
it('should render a simple string field', () => {
38-
const W = mount(
39+
const { container } = render(
3940
<FieldDoc
4041
field={exampleObject.getFields().string}
4142
onClickType={jest.fn()}
4243
/>,
4344
);
44-
expect(W.find('MarkdownContent').text()).toEqual('No Description\n');
45-
expect(W.find('TypeLink').text()).toEqual('String');
46-
expect(W.find('Argument').length).toEqual(0);
45+
expect(container.querySelector('.doc-type-description')).toHaveTextContent(
46+
'No Description',
47+
);
48+
expect(container.querySelector('.type-name')).toHaveTextContent('String');
49+
expect(container.querySelector('.arg')).not.toBeInTheDocument();
4750
});
4851

4952
it('should re-render on field change', () => {
50-
const W = mount(
53+
const { container, rerender } = render(
5154
<FieldDoc
5255
field={exampleObject.getFields().string}
5356
onClickType={jest.fn()}
5457
/>,
5558
);
56-
expect(W.find('MarkdownContent').text()).toEqual('No Description\n');
57-
expect(W.find('TypeLink').text()).toEqual('String');
58-
expect(W.find('Argument').length).toEqual(0);
59+
expect(container.querySelector('.doc-type-description')).toHaveTextContent(
60+
'No Description',
61+
);
62+
expect(container.querySelector('.type-name')).toHaveTextContent('String');
63+
expect(container.querySelector('.arg')).not.toBeInTheDocument();
64+
65+
rerender(
66+
<FieldDoc
67+
field={exampleObject.getFields().stringWithArgs}
68+
onClickType={jest.fn()}
69+
/>,
70+
);
71+
expect(container.querySelector('.type-name')).toHaveTextContent('String');
72+
expect(container.querySelector('.doc-type-description')).toHaveTextContent(
73+
'Example String field with arguments',
74+
);
5975
});
6076

6177
it('should render a string field with arguments', () => {
62-
const W = mount(
78+
const { container } = render(
6379
<FieldDoc
6480
field={exampleObject.getFields().stringWithArgs}
6581
onClickType={jest.fn()}
6682
/>,
6783
);
68-
expect(
69-
W.find('TypeLink')
70-
.at(0)
71-
.text(),
72-
).toEqual('String');
73-
expect(
74-
W.find('.doc-type-description')
75-
.at(0)
76-
.text(),
77-
).toEqual('Example String field with arguments\n');
78-
expect(W.find('Argument').length).toEqual(1);
79-
expect(W.find('Argument').text()).toEqual('stringArg: String');
84+
expect(container.querySelector('.type-name')).toHaveTextContent('String');
85+
expect(container.querySelector('.doc-type-description')).toHaveTextContent(
86+
'Example String field with arguments',
87+
);
88+
expect(container.querySelectorAll('.arg')).toHaveLength(1);
89+
expect(container.querySelector('.arg')).toHaveTextContent(
90+
'stringArg: String',
91+
);
8092
});
8193
});

packages/graphiql/src/components/DocExplorer/__tests__/TypeDoc.spec.js

Lines changed: 55 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
*/
77

88
import React from 'react';
9-
import { mount } from 'enzyme';
9+
import { render, fireEvent } from '@testing-library/react';
10+
import '@testing-library/jest-dom/extend-expect';
1011

1112
import { GraphQLString } from 'graphql';
1213

@@ -21,115 +22,107 @@ import {
2122

2223
describe('TypeDoc', () => {
2324
it('renders a top-level query object type', () => {
24-
const W = mount(
25+
const { container } = render(
2526
<TypeDoc
2627
schema={ExampleSchema}
2728
type={ExampleQuery}
2829
onClickType={jest.fn()}
2930
/>,
3031
);
31-
const cats = W.find('.doc-category-item');
32-
expect(cats.at(0).text()).toEqual('string: String');
33-
expect(cats.at(1).text()).toEqual('union: exampleUnion');
34-
expect(cats.at(2).text()).toEqual(
32+
const cats = container.querySelectorAll('.doc-category-item');
33+
expect(cats[0]).toHaveTextContent('string: String');
34+
expect(cats[1]).toHaveTextContent('union: exampleUnion');
35+
expect(cats[2]).toHaveTextContent(
3536
'fieldWithArgs(stringArg: String): String',
3637
);
3738
});
3839

3940
it('handles onClickField and onClickType', () => {
4041
const onClickType = jest.fn();
4142
const onClickField = jest.fn();
42-
const W = mount(
43+
const { container } = render(
4344
<TypeDoc
4445
schema={ExampleSchema}
4546
type={ExampleQuery}
4647
onClickType={onClickType}
4748
onClickField={onClickField}
4849
/>,
4950
);
50-
W.find('TypeLink')
51-
.at(0)
52-
.simulate('click');
51+
fireEvent.click(container.querySelector('.type-name'));
5352
expect(onClickType.mock.calls.length).toEqual(1);
5453
expect(onClickType.mock.calls[0][0]).toEqual(GraphQLString);
5554

56-
W.find('.field-name')
57-
.at(0)
58-
.simulate('click');
59-
55+
fireEvent.click(container.querySelector('.field-name'));
6056
expect(onClickField.mock.calls.length).toEqual(1);
6157
expect(onClickField.mock.calls[0][0].name).toEqual('string');
6258
expect(onClickField.mock.calls[0][0].type).toEqual(GraphQLString);
6359
expect(onClickField.mock.calls[0][1]).toEqual(ExampleQuery);
6460
});
6561

6662
it('renders deprecated fields when you click to see them', () => {
67-
const W = mount(
63+
const { container } = render(
6864
<TypeDoc
6965
schema={ExampleSchema}
7066
type={ExampleQuery}
7167
onClickType={jest.fn()}
7268
/>,
7369
);
74-
let cats = W.find('.doc-category-item');
75-
expect(cats.length).toEqual(3);
70+
let cats = container.querySelectorAll('.doc-category-item');
71+
expect(cats).toHaveLength(3);
7672

77-
W.find('.show-btn').simulate('click');
73+
fireEvent.click(container.querySelector('.show-btn'));
7874

79-
cats = W.find('.doc-category-item');
80-
expect(cats.length).toEqual(4);
81-
expect(
82-
W.find('.field-name')
83-
.at(3)
84-
.text(),
85-
).toEqual('deprecatedField');
86-
expect(
87-
W.find('.doc-deprecation')
88-
.at(0)
89-
.text(),
90-
).toEqual('example deprecation reason\n');
75+
cats = container.querySelectorAll('.doc-category-item');
76+
expect(cats).toHaveLength(4);
77+
expect(container.querySelectorAll('.field-name')[3]).toHaveTextContent(
78+
'deprecatedField',
79+
);
80+
expect(container.querySelector('.doc-deprecation')).toHaveTextContent(
81+
'example deprecation reason',
82+
);
9183
});
9284

9385
it('renders a Union type', () => {
94-
const W = mount(<TypeDoc schema={ExampleSchema} type={ExampleUnion} />);
95-
expect(
96-
W.find('.doc-category-title')
97-
.at(0)
98-
.text(),
99-
).toEqual('possible types');
86+
const { container } = render(
87+
<TypeDoc schema={ExampleSchema} type={ExampleUnion} />,
88+
);
89+
expect(container.querySelector('.doc-category-title')).toHaveTextContent(
90+
'possible types',
91+
);
10092
});
10193

10294
it('renders an Enum type', () => {
103-
const W = mount(<TypeDoc schema={ExampleSchema} type={ExampleEnum} />);
104-
expect(
105-
W.find('.doc-category-title')
106-
.at(0)
107-
.text(),
108-
).toEqual('values');
109-
const enums = W.find('EnumValue');
110-
expect(enums.at(0).props().value.value).toEqual('Value 1');
111-
expect(enums.at(1).props().value.value).toEqual('Value 2');
95+
const { container } = render(
96+
<TypeDoc schema={ExampleSchema} type={ExampleEnum} />,
97+
);
98+
expect(container.querySelector('.doc-category-title')).toHaveTextContent(
99+
'values',
100+
);
101+
const enums = container.querySelectorAll('.enum-value');
102+
expect(enums[0]).toHaveTextContent('value1');
103+
expect(enums[1]).toHaveTextContent('value2');
112104
});
113105

114106
it('shows deprecated enum values on click', () => {
115-
const W = mount(<TypeDoc schema={ExampleSchema} type={ExampleEnum} />);
116-
expect(W.state().showDeprecated).toEqual(false);
117-
const titles = W.find('.doc-category-title');
118-
expect(titles.at(0).text()).toEqual('values');
119-
expect(titles.at(1).text()).toEqual('deprecated values');
120-
let enums = W.find('EnumValue');
121-
expect(enums.length).toEqual(2);
107+
const { getByText, container } = render(
108+
<TypeDoc schema={ExampleSchema} type={ExampleEnum} />,
109+
);
110+
const showBtn = getByText('Show deprecated values...');
111+
expect(showBtn).toBeInTheDocument();
112+
const titles = container.querySelectorAll('.doc-category-title');
113+
expect(titles[0]).toHaveTextContent('values');
114+
expect(titles[1]).toHaveTextContent('deprecated values');
115+
let enums = container.querySelectorAll('.enum-value');
116+
expect(enums).toHaveLength(2);
122117

123118
// click button to show deprecated enum values
124-
W.find('.show-btn').simulate('click');
125-
expect(W.state().showDeprecated).toEqual(true);
126-
enums = W.find('EnumValue');
127-
expect(enums.length).toEqual(3);
128-
expect(enums.at(2).props().value.value).toEqual('Value 3');
129-
expect(
130-
W.find('.doc-deprecation')
131-
.at(1)
132-
.text(),
133-
).toEqual('Only two are needed\n');
119+
fireEvent.click(showBtn);
120+
expect(showBtn).not.toBeInTheDocument();
121+
enums = container.querySelectorAll('.enum-value');
122+
expect(enums).toHaveLength(3);
123+
expect(enums[2]).toHaveTextContent('value3');
124+
expect(container.querySelector('.doc-deprecation')).toHaveTextContent(
125+
'Only two are needed',
126+
);
134127
});
135128
});

packages/graphiql/src/components/DocExplorer/__tests__/TypeLink.spec.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
*/
77

88
import React from 'react';
9-
import { mount } from 'enzyme';
9+
import { render, fireEvent } from '@testing-library/react';
10+
import '@testing-library/jest-dom/extend-expect';
1011

1112
import TypeLink from '../TypeLink';
1213

@@ -17,32 +18,32 @@ const listType = new GraphQLList(GraphQLString);
1718

1819
describe('TypeLink', () => {
1920
it('should render a string', () => {
20-
const instance = mount(<TypeLink type={GraphQLString} />);
21-
expect(instance.text()).toEqual('String');
22-
expect(instance.find('a').length).toEqual(1);
23-
expect(instance.find('a').hasClass('type-name')).toEqual(true);
21+
const { container } = render(<TypeLink type={GraphQLString} />);
22+
expect(container).toHaveTextContent('String');
23+
expect(container.querySelectorAll('a')).toHaveLength(1);
24+
expect(container.querySelector('a')).toHaveClass('type-name');
2425
});
2526
it('should render a nonnull type', () => {
26-
const instance = mount(<TypeLink type={nonNullType} />);
27-
expect(instance.text()).toEqual('String!');
28-
expect(instance.find('span').length).toEqual(1);
27+
const { container } = render(<TypeLink type={nonNullType} />);
28+
expect(container).toHaveTextContent('String!');
29+
expect(container.querySelectorAll('span')).toHaveLength(1);
2930
});
3031
it('should render a list type', () => {
31-
const instance = mount(<TypeLink type={listType} />);
32-
expect(instance.text()).toEqual('[String]');
33-
expect(instance.find('span').length).toEqual(1);
32+
const { container } = render(<TypeLink type={listType} />);
33+
expect(container).toHaveTextContent('[String]');
34+
expect(container.querySelectorAll('span')).toHaveLength(1);
3435
});
3536
it('should handle a click event', () => {
3637
const op = jest.fn();
37-
const instance = mount(<TypeLink type={listType} onClick={op} />);
38-
instance.find('a').simulate('click');
38+
const { container } = render(<TypeLink type={listType} onClick={op} />);
39+
fireEvent.click(container.querySelector('a'));
3940
expect(op.mock.calls.length).toEqual(1);
4041
expect(op.mock.calls[0][0]).toEqual(GraphQLString);
4142
});
4243
it('should re-render on type change', () => {
43-
const instance = mount(<TypeLink type={listType} />);
44-
expect(instance.text()).toEqual('[String]');
45-
instance.setProps({ type: GraphQLString });
46-
expect(instance.text()).toEqual('String');
44+
const { container, rerender } = render(<TypeLink type={listType} />);
45+
expect(container).toHaveTextContent('[String]');
46+
rerender(<TypeLink type={GraphQLString} />);
47+
expect(container).toHaveTextContent('String');
4748
});
4849
});

packages/graphiql/src/components/__tests__/DocExplorer.spec.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77
import React from 'react';
8-
import { mount } from 'enzyme';
8+
import { render } from '@testing-library/react';
9+
import '@testing-library/jest-dom/extend-expect';
910
import { DocExplorer } from '../DocExplorer';
1011

1112
describe('DocExplorer', () => {
1213
it('renders spinner when no schema prop is present', () => {
13-
const W = mount(<DocExplorer />);
14-
const spinner = W.find('.spinner-container');
15-
expect(spinner.length).toEqual(1);
14+
const { container } = render(<DocExplorer />);
15+
const spinner = container.querySelectorAll('.spinner-container');
16+
expect(spinner).toHaveLength(1);
1617
});
1718
it('renders with null schema', () => {
18-
const W = mount(<DocExplorer schema={null} />);
19-
const error = W.find('.error-container');
20-
expect(error.length).toEqual(1);
21-
expect(error.text()).toEqual('No Schema Available');
19+
const { container } = render(<DocExplorer schema={null} />);
20+
const error = container.querySelectorAll('.error-container');
21+
expect(error).toHaveLength(1);
22+
expect(error[0]).toHaveTextContent('No Schema Available');
2223
});
2324
});

0 commit comments

Comments
 (0)