Skip to content

Commit 9477cc3

Browse files
committed
remove duplicate cleanup functions
1 parent 8439e70 commit 9477cc3

File tree

3 files changed

+128
-118
lines changed

3 files changed

+128
-118
lines changed

client/modules/App/App.test.jsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import configureStore from 'redux-mock-store';
3+
import thunk from 'redux-thunk';
4+
import axios from 'axios';
5+
import { unmountComponentAtNode } from 'react-dom';
6+
import { act } from 'react-dom/test-utils';
7+
import App from './App';
8+
import {
9+
reduxRender,
10+
fireEvent,
11+
screen,
12+
within,
13+
prettyDOM
14+
} from '../../test-utils';
15+
import { initialTestState } from '../../redux_test_stores/test_store';
16+
17+
jest.mock('../../i18n');
18+
19+
describe('<App />', () => {
20+
// to attach the rendered DOM element to
21+
let container;
22+
23+
const mockStore = configureStore([thunk]);
24+
const store = mockStore(initialTestState);
25+
26+
const subject = () =>
27+
reduxRender(<App />, {
28+
store,
29+
container
30+
});
31+
32+
beforeEach(() => {
33+
// setup a DOM element as a render target
34+
container = document.createElement('div');
35+
document.body.appendChild(container);
36+
// axios.get.mockImplementationOnce((x) => Promise.resolve({ data: 'foo' }));
37+
});
38+
39+
afterEach(() => {
40+
// cleanup on exiting
41+
unmountComponentAtNode(container);
42+
container.remove();
43+
container = null;
44+
store.clearActions();
45+
});
46+
47+
it('renders', () => {
48+
act(() => {
49+
subject();
50+
});
51+
console.log(prettyDOM(container));
52+
// expect(screen.getByText('testsketch1')).toBeInTheDocument();
53+
// expect(screen.getByText('testsketch2')).toBeInTheDocument();
54+
});
55+
});

client/modules/IDE/components/SketchList.test.jsx

Lines changed: 58 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,129 +2,113 @@ import React from 'react';
22
import configureStore from 'redux-mock-store';
33
import thunk from 'redux-thunk';
44
import axios from 'axios';
5-
import { unmountComponentAtNode } from 'react-dom';
65
import { act } from 'react-dom/test-utils';
76
import SketchList from './SketchList';
8-
import { reduxRender, fireEvent, screen } from '../../../test-utils';
97
import {
10-
initialTestState,
11-
mockProjects
12-
} from '../../../redux_test_stores/test_store';
8+
reduxRender,
9+
fireEvent,
10+
screen,
11+
within,
12+
prettyDOM
13+
} from '../../../test-utils';
14+
import { initialTestState } from '../../../redux_test_stores/test_store';
1315

1416
jest.mock('../../../i18n');
1517

16-
/*
17-
* there seem to be polarizing opinions about whether or not
18-
* we should test the unconnected component or the
19-
* connected one. For the sake of not editing the original SketchList file
20-
* with an unneccessary export statement, I'm testing
21-
* the connected component with redux-mock-store.
22-
* this approach is outlined here -
23-
* https://www.robinwieruch.de/react-connected-component-test
24-
*/
25-
2618
describe('<Sketchlist />', () => {
27-
let container;
2819
const mockStore = configureStore([thunk]);
2920
const store = mockStore(initialTestState);
3021

22+
let subjectProps = { username: initialTestState.user.username };
23+
24+
const subject = () =>
25+
reduxRender(<SketchList {...subjectProps} />, { store });
26+
3127
beforeEach(() => {
32-
// setup a DOM element as a render target
33-
container = document.createElement('div');
34-
document.body.appendChild(container);
3528
axios.get.mockImplementationOnce((x) => Promise.resolve({ data: 'foo' }));
3629
});
3730

3831
afterEach(() => {
39-
// cleanup on exiting
40-
unmountComponentAtNode(container);
41-
container.remove();
42-
container = null;
4332
store.clearActions();
4433
});
4534

4635
it('has sample projects', () => {
47-
let component;
4836
act(() => {
49-
component = reduxRender(<SketchList username="happydog1" />, {
50-
store,
51-
container
52-
});
37+
subject();
5338
});
5439
expect(screen.getByText('testsketch1')).toBeInTheDocument();
5540
expect(screen.getByText('testsketch2')).toBeInTheDocument();
5641
});
5742

5843
it('clicking on date created row header dispatches a reordering action', () => {
59-
let component;
6044
act(() => {
61-
component = reduxRender(<SketchList username="happydog2" />, {
62-
store,
63-
container
64-
});
45+
subject();
6546
});
47+
6648
act(() => {
67-
fireEvent.click(screen.getByTestId('toggle-direction-createdAt'));
49+
fireEvent.click(screen.getByText(/date created/i));
6850
});
51+
6952
const expectedAction = [{ type: 'TOGGLE_DIRECTION', field: 'createdAt' }];
7053
expect(store.getActions()).toEqual(expect.arrayContaining(expectedAction));
7154
});
7255

73-
it('clicking on dropdown arrow opens sketch options', () => {
74-
let component;
56+
it('clicking on dropdown arrow opens sketch options - sketches belong to user', () => {
7557
act(() => {
76-
component = reduxRender(<SketchList username="happydog2" />, {
77-
store,
78-
container
79-
});
58+
subject();
59+
});
60+
61+
const row = screen.getByRole('row', {
62+
name: /testsketch1/
63+
});
64+
65+
const dropdown = within(row).getByRole('button', {
66+
name: 'Toggle Open/Close Sketch Options'
67+
});
68+
69+
act(() => {
70+
fireEvent.click(dropdown);
71+
});
72+
73+
expect(screen.queryByText('Rename')).toBeInTheDocument();
74+
expect(screen.queryByText('Duplicate')).toBeInTheDocument();
75+
expect(screen.queryByText('Download')).toBeInTheDocument();
76+
expect(screen.queryByText('Add to collection')).toBeInTheDocument();
77+
expect(screen.queryByText('Delete')).toBeInTheDocument();
78+
});
79+
80+
it('snapshot testing', () => {
81+
const { asFragment } = subject();
82+
expect(asFragment()).toMatchSnapshot();
83+
});
84+
85+
describe('different user than the one who created the sketches', () => {
86+
beforeAll(() => {
87+
subjectProps = { username: 'notthesameusername' };
8088
});
81-
const dropdown = screen.queryAllByTestId(
82-
'sketch-list-toggle-options-arrow'
83-
);
8489

85-
if (dropdown.length > 0) {
90+
it('clicking on dropdown arrow opens sketch options without Rename or Delete option', () => {
8691
act(() => {
87-
fireEvent.click(dropdown[0]);
92+
subject();
8893
});
8994

90-
expect(screen.queryByText('Rename')).not.toBeInTheDocument();
91-
expect(screen.queryByText('Duplicate')).toBeInTheDocument();
92-
expect(screen.queryByText('Download')).toBeInTheDocument();
93-
expect(screen.queryByText('Add to collection')).toBeInTheDocument();
94-
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
95-
}
96-
});
95+
const row = screen.getByRole('row', {
96+
name: /testsketch1/
97+
});
9798

98-
it('clicking on dropdown arrow opens sketch options - sketches belong to user', () => {
99-
let component;
100-
act(() => {
101-
component = reduxRender(<SketchList username="happydog" />, {
102-
store,
103-
container
99+
const dropdown = within(row).getByRole('button', {
100+
name: 'Toggle Open/Close Sketch Options'
104101
});
105-
});
106-
const dropdown = screen.queryAllByTestId(
107-
'sketch-list-toggle-options-arrow'
108-
);
109102

110-
if (dropdown.length > 0) {
111103
act(() => {
112-
fireEvent.click(dropdown[0]);
104+
fireEvent.click(dropdown);
113105
});
114106

115-
expect(screen.queryByText('Rename')).toBeInTheDocument();
107+
expect(screen.queryByText('Rename')).not.toBeInTheDocument();
116108
expect(screen.queryByText('Duplicate')).toBeInTheDocument();
117109
expect(screen.queryByText('Download')).toBeInTheDocument();
118110
expect(screen.queryByText('Add to collection')).toBeInTheDocument();
119-
expect(screen.queryByText('Delete')).toBeInTheDocument();
120-
}
121-
});
122-
123-
it('snapshot testing', () => {
124-
const { asFragment } = reduxRender(<SketchList username="happydog2" />, {
125-
store,
126-
container
111+
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
127112
});
128-
expect(asFragment()).toMatchSnapshot();
129113
});
130114
});

developer_docs/testing.md

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ For any type of component, you might want to consider testing:
119119
expect(screen.queryByText('Does not exist')).not.toBeInTheDocument();
120120
```
121121
- If it's an integration test, you could consider testing the "happy path" flow. For example, in a login form, you would test how a user might enter their username and password and then enter that information.
122+
- If it's a unit test, you could test possible error cases to ensure that the module being tested is robust and resistant to user or developer error.
122123
- Generally, you want to focus your testing on "user input" -> "expected output" instead of making sure the middle steps work as you would expect. This might mean that you don't need to check that the state changes or class-specific methods occur. This is so that if some of the small details in the implementation of the component changes in the future, the tests can remain the same.
123124
- more details on testing behavior in the component-specific sections
124125
@@ -173,7 +174,7 @@ You can also see it used in the context of a test [in the SketchList.test.jsx fi
173174
All tests are directly adjacent to the files that they are testing, as described in the [React docs](https://reactjs.org/docs/faq-structure.html#grouping-by-file-type). For example, if you're testing ``examplefolder/Sketchlist.test.jsx``, the test would be in ``examplefolder/Sketchlist.test.jsx``. This is so that the tests are as close as possible to the files. This also means that any snapshot files will be stored in the same folder, such as ``examplefolder/__snapshots__/Sketchlist.test.jsx.snap``
174175

175176
CASSIE - WHERE DO WE PUT THE INTEGRATION TESTS?
176-
Integration tests can be placed in the ``__tests__`` folder that's at the root of the client folder. They should be called ``ComponentName.test.integration.jsx``
177+
Integration tests should be adjacent to the components they're testing. They should be called ``ComponentName.integration.test.jsx``
177178
178179
Manual mocks are in ``__mocks__`` folders are adjacent to the modules that they're mocking.
179180

@@ -271,13 +272,11 @@ If it doesn't contain ``connect(mapStateToProps, mapDispatchToProps)(ComponentNa
271272
*MyComponent.test.jsx*
272273
```js
273274
import React from 'react';
274-
import { unmountComponentAtNode } from 'react-dom';
275275
import { act } from 'react-dom/test-utils';
276276
import { fireEvent, render, screen } from '../../../../test-utils';
277277
import MyComponent from './MyComponent';
278278
279279
describe('<MyComponent />', () => {
280-
let container = null;
281280
282281
let subjectProps = {
283282
t: jest.fn(),
@@ -286,21 +285,10 @@ describe('<MyComponent />', () => {
286285
};
287286
288287
const subject = () => {
289-
render(<MyComponent {...subjectProps} />, { container });
288+
render(<MyComponent {...subjectProps} />);
290289
};
291290
292-
beforeEach(() => {
293-
// setup a DOM element as a render target
294-
container = document.createElement('div');
295-
document.body.appendChild(container);
296-
});
297-
298291
afterEach(() => {
299-
// cleanup on exiting
300-
unmountComponentAtNode(container);
301-
container.remove();
302-
container = null;
303-
304292
//reset the mocks in subjectProps
305293
jest.clearAllMocks();
306294
});
@@ -319,7 +307,10 @@ describe('<MyComponent />', () => {
319307
});
320308
321309
describe('test with a different prop', () => {
322-
subjectProps = {...subjectProps, fontSize: 14}
310+
311+
beforeAll(() => {
312+
subjectProps = {...subjectProps, fontSize: 14}
313+
});
323314
324315
it("here's that test with a different prop", () => {
325316
act(() => {
@@ -371,7 +362,7 @@ store = mockStore(initialTestState);
371362
```
372363
3. Render the component with reduxRender and the store that you just created.
373364
```js
374-
reduxRender(<SketchList username="happydog1" />, {store, container});
365+
reduxRender(<SketchList username="happydog1" />, {store});
375366
```
376367
4. Test things! You may need to use jest to mock certain functions if the component is making API calls.
377368

@@ -383,14 +374,12 @@ All together, it might look something like this.
383374
import React from 'react';
384375
import configureStore from 'redux-mock-store';
385376
import thunk from 'redux-thunk';
386-
import { unmountComponentAtNode } from 'react-dom';
387377
import { act } from 'react-dom/test-utils';
388378
import MyReduxComponent from './MyReduxComponent';
389379
import { reduxRender, fireEvent, screen } from '../../../test-utils';
390380
import { initialTestState } from '../../../redux_test_stores/test_store';
391381

392382
describe('<MyReduxComponent />', () => {
393-
let container = null;
394383
const mockStore = configureStore([thunk]);
395384
const store = mockStore(initialTestState);
396385

@@ -399,27 +388,10 @@ describe('<MyReduxComponent />', () => {
399388
};
400389

401390
const subject = () => {
402-
reduxRender(<MyComponent {...subjectProps} />, {
403-
store,
404-
container
405-
});
391+
reduxRender(<MyComponent {...subjectProps} />, {store});
406392
};
407393

408-
beforeEach(() => {
409-
// setup a DOM element as a render target
410-
container = document.createElement('div');
411-
document.body.appendChild(container);
412-
});
413-
414394
afterEach(() => {
415-
// cleanup on exiting
416-
unmountComponentAtNode(container);
417-
container.remove();
418-
container = null;
419-
420-
//reset the mocks in subjectProps
421-
jest.clearAllMocks();
422-
423395
//clear the mock store too
424396
store.clearActions();
425397
});
@@ -438,10 +410,11 @@ describe('<MyReduxComponent />', () => {
438410
});
439411

440412
describe('test with a different prop', () => {
441-
subjectProps = {
442-
sampleprop: "boo!"
443-
}
444413

414+
beforeAll(() => {
415+
subjectProps = {...subjectProps, fontSize: 14}
416+
});
417+
445418
it("here's that test with a different prop", () => {
446419
act(() => {
447420
subject();
@@ -457,10 +430,7 @@ Some things to consider testing:
457430
- User input results in the expected redux action.
458431
```js
459432
act(() => {
460-
component = reduxRender(<SketchList username="happydog2" />, {
461-
store,
462-
container
463-
});
433+
component = reduxRender(<SketchList username="happydog2" />, {store});
464434
});
465435
act(() => {
466436
fireEvent.click(screen.getByTestId('toggle-direction-createdAt'));
@@ -509,6 +479,7 @@ This project uses i18next for internationalization. If you import the render fun
509479
510480
## More Resources
511481
- [React Testing Library Cheatsheet](https://testing-library.com/docs/react-testing-library/cheatsheet/)
482+
- [React connected component test](https://www.robinwieruch.de/react-connected-component-test)
512483
513484
## References
514485
1. [Best practices for unit testing with a react redux approach](https://willowtreeapps.com/ideas/best-practices-for-unit-testing-with-a-react-redux-approach)

0 commit comments

Comments
 (0)