Added multi-test setup logic
Brian Vaughn committed
Apr 11, 2019 at 09:07 UTC
9fb794b6ed614b800e1ddd2601e72a7b95fc660c
11 files changed
+142
-92
.eslintrc
+4
@@ -8,5 +8,9 @@
8
},
9
"settings": {
10
"version": "detect"
11
+ },
12
+ "globals": {
13
+ "__DEV__": "readonly",
14
+ "jasmine": "readonly"
15
}
16
}
flow.js
+9
@@ -9,3 +9,12 @@ declare module 'events' {
9
10
declare export default typeof EventEmitter;
11
}
12
+
13
+declare var __DEV__: boolean;
14
+
15
+declare var jasmine: {|
16
+ getEnv: () => {|
17
+ afterEach: (callback: Function) => void,
18
+ beforeEach: (callback: Function) => void,
19
+ |},
20
+|};
package.json
+6
@@ -16,6 +16,12 @@
16
"moduleNameMapper": {
17
"^src/(.*)$": "<rootDir>/src/$1"
18
},
19
+ "setupFiles": [
20
+ "<rootDir>/src/__tests__/setupEnv"
21
+ ],
22
+ "setupFilesAfterEnv": [
23
+ "<rootDir>/src/__tests__/setupTests"
24
+ ],
25
"snapshotSerializers": [
26
"<rootDir>/src/__tests__/storeSerializer"
27
],
src/__tests__/__snapshots__/sanity-test.js.snap
deleted
-11
@@ -1,11 +0,0 @@
1
-// Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
-exports[`sanity should pass 1`] = `
4
-▾ <Grandparent>
5
- ▾ <Parent>
6
- <Child key="one">
7
- <Child key="two">
8
- ▾ <Parent>
9
- <Child key="one">
10
- <Child key="two">
11
-`;
src/__tests__/__snapshots__/store-test.js.snap
new
+20
@@ -0,0 +1,20 @@
1
+// Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+exports[`Store should initialize a multiple root tree 1`] = `
4
+▾ <Parent>
5
+ <Child key="one">
6
+ <Child key="two">
7
+▾ <Parent>
8
+ <Child key="one">
9
+ <Child key="two">
10
+`;
11
+
12
+exports[`Store should initialize a simple tree 1`] = `
13
+▾ <Grandparent>
14
+ ▾ <Parent>
15
+ <Child key="one">
16
+ <Child key="two">
17
+ ▾ <Parent>
18
+ <Child key="one">
19
+ <Child key="two">
20
+`;
src/__tests__/sanity-test.js
deleted
-41
@@ -1,41 +0,0 @@
1
-// @flow
2
-
3
-import { setup } from './utils';
4
-
5
-describe('sanity', () => {
6
- let React;
7
- let ReactDOM;
8
- let store;
9
-
10
- beforeEach(() => {
11
- store = setup();
12
-
13
- React = require('react');
14
- ReactDOM = require('react-dom');
15
- });
16
-
17
- it('should pass', () => {
18
- function Grandparent() {
19
- return (
20
- <React.Fragment>
21
- <Parent />
22
- <Parent />
23
- </React.Fragment>
24
- );
25
- }
26
-
27
- function Parent() {
28
- return [<Child key="one" />, <Child key="two" />];
29
- }
30
-
31
- function Child() {
32
- return <div>Hi!</div>;
33
- }
34
-
35
- ReactDOM.render(<Grandparent />, document.createElement('div'));
36
-
37
- jest.runAllTimers(); // Flush Bridge operations
38
-
39
- expect(store).toMatchSnapshot();
40
- });
41
-});
src/__tests__/setupEnv.js
new
+7
@@ -0,0 +1,7 @@
1
+// @flow
2
+
3
+global.localStorage = {
4
+ getItem: jest.fn(),
5
+ setItem: jest.fn(),
6
+ clear: jest.fn(),
7
+};
src/__tests__/setupTests.js
new
+50
@@ -0,0 +1,50 @@
1
+// @flow
2
+
3
+import Agent from 'src/backend/agent';
4
+import { initBackend } from 'src/backend';
5
+import Bridge from 'src/bridge';
6
+import Store from 'src/devtools/store';
7
+import { installHook } from 'src/hook';
8
+
9
+let agent;
10
+let bridge;
11
+let bridgeListeners;
12
+
13
+// Mimic the global we set with Webpack's DefinePlugin
14
+global.__DEV__ = process.env.NODE_ENV !== 'production';
15
+
16
+const env = jasmine.getEnv();
17
+env.beforeEach(() => {
18
+ // It's important to reset modules between test runs;
19
+ // Without this, ReactDOM won't re-inject itself into the new hook.
20
+ jest.resetModules();
21
+
22
+ // Fake timers let us flush Bridge operations between setup and assertions.
23
+ jest.useFakeTimers();
24
+
25
+ installHook(global);
26
+
27
+ bridgeListeners = [];
28
+
29
+ bridge = new Bridge(
30
+ {
31
+ listen(callback) {
32
+ bridgeListeners.push(callback);
33
+ },
34
+ send(event: string, payload: any, transferable?: Array<any>) {
35
+ bridgeListeners.forEach(callback => callback({ event, payload }));
36
+ },
37
+ },
38
+ { batchDuration: 0 }
39
+ );
40
+
41
+ agent = new Agent();
42
+ agent.addBridge(bridge);
43
+
44
+ initBackend(global.__REACT_DEVTOOLS_GLOBAL_HOOK__, agent, global);
45
+
46
+ global.store = new Store(bridge);
47
+});
48
+env.afterEach(() => {
49
+ delete global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
50
+});
src/__tests__/store-test.js
new
+43
@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+describe('Store', () => {
4
+ let React;
5
+ let ReactDOM;
6
+ let store;
7
+
8
+ beforeEach(() => {
9
+ store = global.store;
10
+
11
+ React = require('react');
12
+ ReactDOM = require('react-dom');
13
+ });
14
+
15
+ it('should initialize a simple tree', () => {
16
+ const Grandparent = () => (
17
+ <React.Fragment>
18
+ <Parent />
19
+ <Parent />
20
+ </React.Fragment>
21
+ );
22
+ const Parent = () => [<Child key="one" />, <Child key="two" />];
23
+ const Child = () => <div>Hi!</div>;
24
+
25
+ ReactDOM.render(<Grandparent />, document.createElement('div'));
26
+
27
+ jest.runAllTimers(); // Flush Bridge operations
28
+
29
+ expect(store).toMatchSnapshot();
30
+ });
31
+
32
+ it('should initialize a multiple root tree', () => {
33
+ const Parent = () => [<Child key="one" />, <Child key="two" />];
34
+ const Child = () => <div>Hi!</div>;
35
+
36
+ ReactDOM.render(<Parent />, document.createElement('div'));
37
+ ReactDOM.render(<Parent />, document.createElement('div'));
38
+
39
+ jest.runAllTimers(); // Flush Bridge operations
40
+
41
+ expect(store).toMatchSnapshot();
42
+ });
43
+});
src/__tests__/utils.js
deleted
-40
@@ -1,40 +0,0 @@
1
-// @flow
2
-
3
-import Agent from 'src/backend/agent';
4
-import { initBackend } from 'src/backend';
5
-import Bridge from 'src/bridge';
6
-import Store from 'src/devtools/store';
7
-import { installHook } from 'src/hook';
8
-
9
-export function setup(): Store {
10
- installHook(global);
11
-
12
- jest.useFakeTimers();
13
-
14
- // TODO Replace this with a polyfill?
15
- global.localStorage = {
16
- getItem: jest.fn(),
17
- setItem: jest.fn(),
18
- clear: jest.fn(),
19
- };
20
-
21
- const listeners = [];
22
- const bridge = new Bridge(
23
- {
24
- listen(callback) {
25
- listeners.push(callback);
26
- },
27
- send(event: string, payload: any, transferable?: Array<any>) {
28
- listeners.forEach(callback => callback({ event, payload }));
29
- },
30
- },
31
- { batchDuration: 0 }
32
- );
33
-
34
- const agent = new Agent();
35
- agent.addBridge(bridge);
36
-
37
- initBackend(global.__REACT_DEVTOOLS_GLOBAL_HOOK__, agent, global);
38
-
39
- return new Store(bridge);
40
-}
src/hook.js
+3
@@ -189,6 +189,9 @@ export function installHook(target: any): DevToolsHook | null {
189
target,
190
'__REACT_DEVTOOLS_GLOBAL_HOOK__',
191
({
192
+ // This property needs to be configurable for the test environment,
193
+ // else we won't be able to delete and recreate it beween tests.
194
+ configurable: __DEV__,
195
enumerable: false,
196
get() {
197
return hook;