@samitouri / QOS-React-2 / commits / ac0022bf4a

Added more tree context tests

Brian Vaughn committed May 10, 2019 at 08:07 UTC ac0022bf4a32f8c464e59f8b71dec12f141619b3
4 files changed +444 -8
src/__tests__/__snapshots__/treeContext-test.js.snap
+310
@@ -1,5 +1,251 @@
1 // Jest Snapshot v1, https://goo.gl/fbAQLP
2
3 +exports[`TreeListContext owners state should exit the owners list if the current owner is unmounted: 0: mount 1`] = `
4 +[root]
5 + ▾ <Parent>
6 + <Child>
7 +`;
8 +
9 +exports[`TreeListContext owners state should exit the owners list if the current owner is unmounted: 1: initial state 1`] = `
10 +Object {
11 + "inspectedElementID": null,
12 + "numElements": 2,
13 + "ownerFlatTree": null,
14 + "ownerID": null,
15 + "searchIndex": null,
16 + "searchResults": Array [],
17 + "searchText": "",
18 + "selectedElementID": null,
19 + "selectedElementIndex": null,
20 +}
21 +`;
22 +
23 +exports[`TreeListContext owners state should exit the owners list if the current owner is unmounted: 2: child owners tree 1`] = `
24 +Object {
25 + "inspectedElementID": 3,
26 + "numElements": 1,
27 + "ownerFlatTree": Array [
28 + Object {
29 + "children": Array [],
30 + "depth": 0,
31 + "displayName": "Child",
32 + "id": 3,
33 + "isCollapsed": false,
34 + "key": null,
35 + "ownerID": 0,
36 + "parentID": 2,
37 + "type": 5,
38 + "weight": 1,
39 + },
40 + ],
41 + "ownerID": 3,
42 + "searchIndex": null,
43 + "searchResults": Array [],
44 + "searchText": "",
45 + "selectedElementID": 3,
46 + "selectedElementIndex": 0,
47 +}
48 +`;
49 +
50 +exports[`TreeListContext owners state should exit the owners list if the current owner is unmounted: 3: remove child 1`] = `
51 +Object {
52 + "inspectedElementID": null,
53 + "numElements": 1,
54 + "ownerFlatTree": null,
55 + "ownerID": null,
56 + "searchIndex": null,
57 + "searchResults": Array [],
58 + "searchText": "",
59 + "selectedElementID": null,
60 + "selectedElementIndex": 0,
61 +}
62 +`;
63 +
64 +exports[`TreeListContext owners state should exit the owners list if the current owner is unmounted: 4: parent owners tree 1`] = `
65 +Object {
66 + "inspectedElementID": 2,
67 + "numElements": 1,
68 + "ownerFlatTree": Array [
69 + Object {
70 + "children": Array [],
71 + "depth": 0,
72 + "displayName": "Parent",
73 + "id": 2,
74 + "isCollapsed": false,
75 + "key": null,
76 + "ownerID": 0,
77 + "parentID": 1,
78 + "type": 5,
79 + "weight": 1,
80 + },
81 + ],
82 + "ownerID": 2,
83 + "searchIndex": null,
84 + "searchResults": Array [],
85 + "searchText": "",
86 + "selectedElementID": 2,
87 + "selectedElementIndex": 0,
88 +}
89 +`;
90 +
91 +exports[`TreeListContext owners state should exit the owners list if the current owner is unmounted: 5: unmount root 1`] = `
92 +Object {
93 + "inspectedElementID": null,
94 + "numElements": 0,
95 + "ownerFlatTree": null,
96 + "ownerID": null,
97 + "searchIndex": null,
98 + "searchResults": Array [],
99 + "searchText": "",
100 + "selectedElementID": null,
101 + "selectedElementIndex": 0,
102 +}
103 +`;
104 +
105 +exports[`TreeListContext owners state should remove an element from the owners list if it is unmounted: 0: mount 1`] = `
106 +[root]
107 + ▾ <Grandparent>
108 + ▾ <Parent>
109 + <Child key="0">
110 + <Child key="1">
111 +`;
112 +
113 +exports[`TreeListContext owners state should remove an element from the owners list if it is unmounted: 1: initial state 1`] = `
114 +Object {
115 + "inspectedElementID": null,
116 + "numElements": 4,
117 + "ownerFlatTree": null,
118 + "ownerID": null,
119 + "searchIndex": null,
120 + "searchResults": Array [],
121 + "searchText": "",
122 + "selectedElementID": null,
123 + "selectedElementIndex": null,
124 +}
125 +`;
126 +
127 +exports[`TreeListContext owners state should remove an element from the owners list if it is unmounted: 2: parent owners tree 1`] = `
128 +Object {
129 + "inspectedElementID": 3,
130 + "numElements": 3,
131 + "ownerFlatTree": Array [
132 + Object {
133 + "children": Array [
134 + 4,
135 + 5,
136 + ],
137 + "depth": 0,
138 + "displayName": "Parent",
139 + "id": 3,
140 + "isCollapsed": false,
141 + "key": null,
142 + "ownerID": 2,
143 + "parentID": 2,
144 + "type": 5,
145 + "weight": 3,
146 + },
147 + Object {
148 + "children": Array [],
149 + "depth": 1,
150 + "displayName": "Child",
151 + "id": 4,
152 + "isCollapsed": false,
153 + "key": "0",
154 + "ownerID": 3,
155 + "parentID": 3,
156 + "type": 5,
157 + "weight": 1,
158 + },
159 + Object {
160 + "children": Array [],
161 + "depth": 1,
162 + "displayName": "Child",
163 + "id": 5,
164 + "isCollapsed": false,
165 + "key": "1",
166 + "ownerID": 3,
167 + "parentID": 3,
168 + "type": 5,
169 + "weight": 1,
170 + },
171 + ],
172 + "ownerID": 3,
173 + "searchIndex": null,
174 + "searchResults": Array [],
175 + "searchText": "",
176 + "selectedElementID": 3,
177 + "selectedElementIndex": 0,
178 +}
179 +`;
180 +
181 +exports[`TreeListContext owners state should remove an element from the owners list if it is unmounted: 3: remove second child 1`] = `
182 +Object {
183 + "inspectedElementID": 3,
184 + "numElements": 2,
185 + "ownerFlatTree": Array [
186 + Object {
187 + "children": Array [
188 + 4,
189 + ],
190 + "depth": 0,
191 + "displayName": "Parent",
192 + "id": 3,
193 + "isCollapsed": false,
194 + "key": null,
195 + "ownerID": 2,
196 + "parentID": 2,
197 + "type": 5,
198 + "weight": 2,
199 + },
200 + Object {
201 + "children": Array [],
202 + "depth": 1,
203 + "displayName": "Child",
204 + "id": 4,
205 + "isCollapsed": false,
206 + "key": "0",
207 + "ownerID": 3,
208 + "parentID": 3,
209 + "type": 5,
210 + "weight": 1,
211 + },
212 + ],
213 + "ownerID": 3,
214 + "searchIndex": null,
215 + "searchResults": Array [],
216 + "searchText": "",
217 + "selectedElementID": 3,
218 + "selectedElementIndex": 0,
219 +}
220 +`;
221 +
222 +exports[`TreeListContext owners state should remove an element from the owners list if it is unmounted: 4: remove first child 1`] = `
223 +Object {
224 + "inspectedElementID": 3,
225 + "numElements": 1,
226 + "ownerFlatTree": Array [
227 + Object {
228 + "children": Array [],
229 + "depth": 0,
230 + "displayName": "Parent",
231 + "id": 3,
232 + "isCollapsed": false,
233 + "key": null,
234 + "ownerID": 2,
235 + "parentID": 2,
236 + "type": 5,
237 + "weight": 1,
238 + },
239 + ],
240 + "ownerID": 3,
241 + "searchIndex": null,
242 + "searchResults": Array [],
243 + "searchText": "",
244 + "selectedElementID": 3,
245 + "selectedElementIndex": 0,
246 +}
247 +`;
248 +
249 exports[`TreeListContext owners state should support entering and existing the owners tree view: 0: mount 1`] = `
250 [root]
251 ▾ <Grandparent>
@@ -430,6 +676,70 @@ Object {
676 }
677 `;
678
679 +exports[`TreeListContext tree state should clear selection if the selected element is unmounted: 0: mount 1`] = `
680 +[root]
681 + ▾ <Grandparent>
682 + ▾ <Parent>
683 + <Child>
684 + <Child>
685 +`;
686 +
687 +exports[`TreeListContext tree state should clear selection if the selected element is unmounted: 1: initial state 1`] = `
688 +Object {
689 + "inspectedElementID": null,
690 + "numElements": 4,
691 + "ownerFlatTree": null,
692 + "ownerID": null,
693 + "searchIndex": null,
694 + "searchResults": Array [],
695 + "searchText": "",
696 + "selectedElementID": null,
697 + "selectedElementIndex": null,
698 +}
699 +`;
700 +
701 +exports[`TreeListContext tree state should clear selection if the selected element is unmounted: 2: select second child 1`] = `
702 +Object {
703 + "inspectedElementID": 5,
704 + "numElements": 4,
705 + "ownerFlatTree": null,
706 + "ownerID": null,
707 + "searchIndex": null,
708 + "searchResults": Array [],
709 + "searchText": "",
710 + "selectedElementID": 5,
711 + "selectedElementIndex": 3,
712 +}
713 +`;
714 +
715 +exports[`TreeListContext tree state should clear selection if the selected element is unmounted: 3: remove children (parent should now be selected) 1`] = `
716 +Object {
717 + "inspectedElementID": 3,
718 + "numElements": 2,
719 + "ownerFlatTree": null,
720 + "ownerID": null,
721 + "searchIndex": null,
722 + "searchResults": Array [],
723 + "searchText": "",
724 + "selectedElementID": 3,
725 + "selectedElementIndex": 1,
726 +}
727 +`;
728 +
729 +exports[`TreeListContext tree state should clear selection if the selected element is unmounted: 4: unmount root (nothing should be selected) 1`] = `
730 +Object {
731 + "inspectedElementID": null,
732 + "numElements": 0,
733 + "ownerFlatTree": null,
734 + "ownerID": null,
735 + "searchIndex": null,
736 + "searchResults": Array [],
737 + "searchText": "",
738 + "selectedElementID": null,
739 + "selectedElementIndex": null,
740 +}
741 +`;
742 +
743 exports[`TreeListContext tree state should select child elements: 0: mount 1`] = `
744 [root]
745 ▾ <Grandparent>
src/__tests__/ownersListContext-test.js
-2
@@ -205,6 +205,4 @@ describe('OwnersListContext', () => {
205
206 done();
207 });
208 -
209 - // TODO (owners) Verify that if an Element in the list is unmounted the stack is updated.
208 });
src/__tests__/treeContext-test.js
+122
@@ -213,6 +213,56 @@ describe('TreeListContext', () => {
213 utils.act(() => renderer.update(<Contexts />));
214 expect(state).toEqual(previousState);
215 });
216 +
217 + it('should clear selection if the selected element is unmounted', async done => {
218 + const Grandparent = props => props.children || null;
219 + const Parent = props => props.children || null;
220 + const Child = () => null;
221 +
222 + const container = document.createElement('div');
223 + utils.act(() =>
224 + ReactDOM.render(
225 + <Grandparent>
226 + <Parent>
227 + <Child />
228 + <Child />
229 + </Parent>
230 + </Grandparent>,
231 + container
232 + )
233 + );
234 +
235 + expect(store).toMatchSnapshot('0: mount');
236 +
237 + let renderer;
238 + utils.act(() => (renderer = TestRenderer.create(<Contexts />)));
239 + expect(state).toMatchSnapshot('1: initial state');
240 +
241 + utils.act(() =>
242 + dispatch({ type: 'SELECT_ELEMENT_AT_INDEX', payload: 3 })
243 + );
244 + utils.act(() => renderer.update(<Contexts />));
245 + expect(state).toMatchSnapshot('2: select second child');
246 +
247 + await utils.actSuspense(() =>
248 + ReactDOM.render(
249 + <Grandparent>
250 + <Parent />
251 + </Grandparent>,
252 + container
253 + )
254 + );
255 + expect(state).toMatchSnapshot(
256 + '3: remove children (parent should now be selected)'
257 + );
258 +
259 + await utils.actSuspense(() => ReactDOM.unmountComponentAtNode(container));
260 + expect(state).toMatchSnapshot(
261 + '4: unmount root (nothing should be selected)'
262 + );
263 +
264 + done();
265 + });
266 });
267
268 describe('search state', () => {
@@ -424,5 +474,77 @@ describe('TreeListContext', () => {
474 utils.act(() => renderer.update(<Contexts />));
475 expect(state).toMatchSnapshot('3: final state');
476 });
477 +
478 + it('should remove an element from the owners list if it is unmounted', async done => {
479 + const Grandparent = ({ count }) => <Parent count={count} />;
480 + const Parent = ({ count }) =>
481 + new Array(count).fill(true).map((_, index) => <Child key={index} />);
482 + const Child = () => null;
483 +
484 + const container = document.createElement('div');
485 + utils.act(() => ReactDOM.render(<Grandparent count={2} />, container));
486 +
487 + expect(store).toMatchSnapshot('0: mount');
488 +
489 + let renderer;
490 + utils.act(() => (renderer = TestRenderer.create(<Contexts />)));
491 + expect(state).toMatchSnapshot('1: initial state');
492 +
493 + let parentID = ((store.getElementIDAtIndex(1): any): number);
494 + utils.act(() => dispatch({ type: 'SELECT_OWNER', payload: parentID }));
495 + utils.act(() => renderer.update(<Contexts />));
496 + expect(state).toMatchSnapshot('2: parent owners tree');
497 +
498 + await utils.actSuspense(() =>
499 + ReactDOM.render(<Grandparent count={1} />, container)
500 + );
501 + expect(state).toMatchSnapshot('3: remove second child');
502 +
503 + await utils.actSuspense(() =>
504 + ReactDOM.render(<Grandparent count={0} />, container)
505 + );
506 + expect(state).toMatchSnapshot('4: remove first child');
507 +
508 + done();
509 + });
510 +
511 + it('should exit the owners list if the current owner is unmounted', async done => {
512 + const Parent = props => props.children || null;
513 + const Child = () => null;
514 +
515 + const container = document.createElement('div');
516 + utils.act(() =>
517 + ReactDOM.render(
518 + <Parent>
519 + <Child />
520 + </Parent>,
521 + container
522 + )
523 + );
524 +
525 + expect(store).toMatchSnapshot('0: mount');
526 +
527 + let renderer;
528 + utils.act(() => (renderer = TestRenderer.create(<Contexts />)));
529 + expect(state).toMatchSnapshot('1: initial state');
530 +
531 + let childID = ((store.getElementIDAtIndex(1): any): number);
532 + utils.act(() => dispatch({ type: 'SELECT_OWNER', payload: childID }));
533 + utils.act(() => renderer.update(<Contexts />));
534 + expect(state).toMatchSnapshot('2: child owners tree');
535 +
536 + await utils.actSuspense(() => ReactDOM.render(<Parent />, container));
537 + expect(state).toMatchSnapshot('3: remove child');
538 +
539 + let parentID = ((store.getElementIDAtIndex(0): any): number);
540 + utils.act(() => dispatch({ type: 'SELECT_OWNER', payload: parentID }));
541 + utils.act(() => renderer.update(<Contexts />));
542 + expect(state).toMatchSnapshot('4: parent owners tree');
543 +
544 + await utils.actSuspense(() => ReactDOM.unmountComponentAtNode(container));
545 + expect(state).toMatchSnapshot('5: unmount root');
546 +
547 + done();
548 + });
549 });
550 });
src/devtools/views/Components/TreeContext.js
+12 -6
@@ -447,12 +447,18 @@ function reduceOwnersState(store: Store, state: State, action: Action): State {
447 switch (action.type) {
448 case 'HANDLE_STORE_MUTATION':
449 if (ownerID !== null) {
450 - ownerFlatTree = store.getOwnersListForElement(ownerID);
451 - if (selectedElementID !== null) {
452 - // Mutation might have caused the index of this ID to shift.
453 - selectedElementIndex = ownerFlatTree.findIndex(
454 - element => element.id === selectedElementID
455 - );
450 + if (!store.containsElement(ownerID)) {
451 + ownerID = null;
452 + ownerFlatTree = null;
453 + selectedElementID = null;
454 + } else {
455 + ownerFlatTree = store.getOwnersListForElement(ownerID);
456 + if (selectedElementID !== null) {
457 + // Mutation might have caused the index of this ID to shift.
458 + selectedElementIndex = ownerFlatTree.findIndex(
459 + element => element.id === selectedElementID
460 + );
461 + }
462 }
463 } else {
464 if (selectedElementID !== null) {