@samitouri / QOS-React / commits / 540207901d

Added some component filtering tests

Brian Vaughn committed May 1, 2019 at 13:31 UTC 540207901d4af2ed894b76b6693f9d9c84f2711a
9 files changed +318 -9
babel.config.js
+1
@@ -29,6 +29,7 @@ module.exports = api => {
29 plugins: [
30 ['@babel/plugin-transform-flow-strip-types'],
31 ['@babel/plugin-proposal-class-properties', { loose: false }],
32 + ['@babel/plugin-transform-react-jsx-source'],
33 ],
34 presets: [
35 ['@babel/preset-env', { targets }],
package.json
+1
@@ -70,6 +70,7 @@
70 "@babel/core": "^7.1.6",
71 "@babel/plugin-proposal-class-properties": "^7.1.0",
72 "@babel/plugin-transform-flow-strip-types": "^7.1.6",
73 + "@babel/plugin-transform-react-jsx-source": "^7.2.0",
74 "@babel/preset-env": "^7.1.6",
75 "@babel/preset-flow": "^7.0.0",
76 "@babel/preset-react": "^7.0.0",
src/__tests__/__snapshots__/storeComponentFilters-test.js.snap new
+98
@@ -0,0 +1,98 @@
1 +// Jest Snapshot v1, https://goo.gl/fbAQLP
2 +
3 +exports[`Store component filters should filter by display name: 1: mount 1`] = `
4 +[root]
5 + ▾ <Foo>
6 + <Text>
7 + ▾ <Bar>
8 + <Text>
9 + ▾ <Baz>
10 + <Text>
11 +`;
12 +
13 +exports[`Store component filters should filter by display name: 2: filter "Foo" 1`] = `
14 +[root]
15 + <Text>
16 + ▾ <Bar>
17 + <Text>
18 + ▾ <Baz>
19 + <Text>
20 +`;
21 +
22 +exports[`Store component filters should filter by display name: 3: filter "Ba" 1`] = `
23 +[root]
24 + ▾ <Foo>
25 + <Text>
26 + <Text>
27 + <Text>
28 +`;
29 +
30 +exports[`Store component filters should filter by display name: 4: filter "B.z" 1`] = `
31 +[root]
32 + ▾ <Foo>
33 + <Text>
34 + ▾ <Bar>
35 + <Text>
36 + <Text>
37 +`;
38 +
39 +exports[`Store component filters should filter by path: 1: mount 1`] = `
40 +[root]
41 + ▾ <Component>
42 + <div>
43 +`;
44 +
45 +exports[`Store component filters should filter by path: 2: hide all components declared within this test filed 1`] = `[root]`;
46 +
47 +exports[`Store component filters should filter by path: 3: hide components in a made up fake path 1`] = `
48 +[root]
49 + ▾ <Component>
50 + <div>
51 +`;
52 +
53 +exports[`Store component filters should ignore invalid ElementTypeRoot filter: 1: mount 1`] = `
54 +[root]
55 + ▾ <Root>
56 + <div>
57 +`;
58 +
59 +exports[`Store component filters should ignore invalid ElementTypeRoot filter: 2: add invalid filter 1`] = `
60 +[root]
61 + ▾ <Root>
62 + <div>
63 +`;
64 +
65 +exports[`Store component filters should support filtering by element type: 1: mount 1`] = `
66 +[root]
67 + ▾ <Root>
68 + ▾ <div>
69 + ▾ <Component>
70 + <div>
71 +`;
72 +
73 +exports[`Store component filters should support filtering by element type: 2: hide host components 1`] = `
74 +[root]
75 + ▾ <Root>
76 + <Component>
77 +`;
78 +
79 +exports[`Store component filters should support filtering by element type: 3: hide class components 1`] = `
80 +[root]
81 + ▾ <div>
82 + ▾ <Component>
83 + <div>
84 +`;
85 +
86 +exports[`Store component filters should support filtering by element type: 4: hide class and function components 1`] = `
87 +[root]
88 + ▾ <div>
89 + <div>
90 +`;
91 +
92 +exports[`Store component filters should support filtering by element type: 5: disable all filters 1`] = `
93 +[root]
94 + ▾ <Root>
95 + ▾ <div>
96 + ▾ <Component>
97 + <div>
98 +`;
src/__tests__/storeComponentFilters-test.js new
+191
@@ -0,0 +1,191 @@
1 +// @flow
2 +
3 +describe('Store component filters', () => {
4 + let React;
5 + let ReactDOM;
6 + let TestUtils;
7 + let Types;
8 + let store;
9 +
10 + const createElementTypeFilter = (elementType, isEnabled = true) => ({
11 + type: Types.ComponentFilterElementType,
12 + isEnabled,
13 + value: elementType,
14 + });
15 +
16 + const createDisplayNameFilter = (source, isEnabled = true) => {
17 + let isValid = true;
18 + try {
19 + new RegExp(source);
20 + } catch (error) {
21 + isValid = false;
22 + }
23 + return {
24 + type: Types.ComponentFilterDisplayName,
25 + isEnabled,
26 + isValid,
27 + value: source,
28 + };
29 + };
30 +
31 + const createLocationFilter = (source, isEnabled = true) => {
32 + let isValid = true;
33 + try {
34 + new RegExp(source);
35 + } catch (error) {
36 + isValid = false;
37 + }
38 + return {
39 + type: Types.ComponentFilterLocation,
40 + isEnabled,
41 + isValid,
42 + value: source,
43 + };
44 + };
45 +
46 + const act = (callback: Function) => {
47 + TestUtils.act(() => {
48 + callback();
49 + });
50 + jest.runAllTimers(); // Flush Bridge operations
51 + };
52 +
53 + beforeEach(() => {
54 + store = global.store;
55 + store.collapseNodesByDefault = false;
56 + store.componentFilters = [];
57 +
58 + React = require('react');
59 + ReactDOM = require('react-dom');
60 + TestUtils = require('react-dom/test-utils');
61 + Types = require('src/types');
62 + });
63 +
64 + it('should support filtering by element type', () => {
65 + class Root extends React.Component<{| children: React$Node |}> {
66 + render() {
67 + return <div>{this.props.children}</div>;
68 + }
69 + }
70 + const Component = () => <div>Hi</div>;
71 +
72 + act(() =>
73 + ReactDOM.render(
74 + <Root>
75 + <Component />
76 + </Root>,
77 + document.createElement('div')
78 + )
79 + );
80 + expect(store).toMatchSnapshot('1: mount');
81 +
82 + act(
83 + () =>
84 + (store.componentFilters = [
85 + createElementTypeFilter(Types.ElementTypeHostComponent),
86 + ])
87 + );
88 +
89 + expect(store).toMatchSnapshot('2: hide host components');
90 +
91 + act(
92 + () =>
93 + (store.componentFilters = [
94 + createElementTypeFilter(Types.ElementTypeClass),
95 + ])
96 + );
97 +
98 + expect(store).toMatchSnapshot('3: hide class components');
99 +
100 + act(
101 + () =>
102 + (store.componentFilters = [
103 + createElementTypeFilter(Types.ElementTypeClass),
104 + createElementTypeFilter(Types.ElementTypeFunction),
105 + ])
106 + );
107 +
108 + expect(store).toMatchSnapshot('4: hide class and function components');
109 +
110 + act(
111 + () =>
112 + (store.componentFilters = [
113 + createElementTypeFilter(Types.ElementTypeClass, false),
114 + createElementTypeFilter(Types.ElementTypeFunction, false),
115 + ])
116 + );
117 +
118 + expect(store).toMatchSnapshot('5: disable all filters');
119 + });
120 +
121 + it('should ignore invalid ElementTypeRoot filter', () => {
122 + const Root = () => <div>Hi</div>;
123 +
124 + act(() => ReactDOM.render(<Root />, document.createElement('div')));
125 + expect(store).toMatchSnapshot('1: mount');
126 +
127 + act(
128 + () =>
129 + (store.componentFilters = [
130 + createElementTypeFilter(Types.ElementTypeRoot),
131 + ])
132 + );
133 +
134 + expect(store).toMatchSnapshot('2: add invalid filter');
135 + });
136 +
137 + it('should filter by display name', () => {
138 + const Text = ({ label }) => label;
139 + const Foo = () => <Text label="foo" />;
140 + const Bar = () => <Text label="bar" />;
141 + const Baz = () => <Text label="baz" />;
142 +
143 + act(() =>
144 + ReactDOM.render(
145 + <React.Fragment>
146 + <Foo />
147 + <Bar />
148 + <Baz />
149 + </React.Fragment>,
150 + document.createElement('div')
151 + )
152 + );
153 + expect(store).toMatchSnapshot('1: mount');
154 +
155 + act(() => (store.componentFilters = [createDisplayNameFilter('Foo')]));
156 + expect(store).toMatchSnapshot('2: filter "Foo"');
157 +
158 + act(() => (store.componentFilters = [createDisplayNameFilter('Ba')]));
159 + expect(store).toMatchSnapshot('3: filter "Ba"');
160 +
161 + act(() => (store.componentFilters = [createDisplayNameFilter('B.z')]));
162 + expect(store).toMatchSnapshot('4: filter "B.z"');
163 + });
164 +
165 + it('should filter by path', () => {
166 + const Component = () => <div>Hi</div>;
167 +
168 + act(() => ReactDOM.render(<Component />, document.createElement('div')));
169 + expect(store).toMatchSnapshot('1: mount');
170 +
171 + act(
172 + () =>
173 + (store.componentFilters = [
174 + createLocationFilter(__filename.replace(__dirname, '')),
175 + ])
176 + );
177 +
178 + expect(store).toMatchSnapshot(
179 + '2: hide all components declared within this test filed'
180 + );
181 +
182 + act(
183 + () =>
184 + (store.componentFilters = [
185 + createLocationFilter('this:is:a:made:up:path'),
186 + ])
187 + );
188 +
189 + expect(store).toMatchSnapshot('3: hide components in a made up fake path');
190 + });
191 +});
src/backend/renderer.js
+6 -3
@@ -4,7 +4,7 @@ import { gte } from 'semver';
4 import {
5 ComponentFilterDisplayName,
6 ComponentFilterElementType,
7 - ComponentFilterPath,
7 + ComponentFilterLocation,
8 ElementTypeClass,
9 ElementTypeContext,
10 ElementTypeEventComponent,
@@ -290,7 +290,7 @@ export function attach(
290 case ComponentFilterElementType:
291 hideElementsWithTypes.add(componentFilter.value);
292 break;
293 - case ComponentFilterPath:
293 + case ComponentFilterLocation:
294 if (componentFilter.isValid && componentFilter.value !== '') {
295 hideElementsWithPaths.add(new RegExp(componentFilter.value, 'i'));
296 }
@@ -354,6 +354,9 @@ export function attach(
354 case HostText:
355 case Fragment:
356 return true;
357 + case HostRoot:
358 + // It is never valid to filter the root element.
359 + return false;
360 default:
361 const typeSymbol = getTypeSymbol(type);
362
@@ -383,7 +386,7 @@ export function attach(
386 }
387 }
388
386 - if (_debugSource !== null && hideElementsWithPaths.size > 0) {
389 + if (_debugSource != null && hideElementsWithPaths.size > 0) {
390 const { fileName } = _debugSource;
391 for (let pathRegExp of hideElementsWithPaths) {
392 if (pathRegExp.test(fileName)) {
src/devtools/views/Components/ComponentFiltersModal.css
+1 -1
@@ -66,7 +66,7 @@
66 }
67
68 .Input {
69 - border: none;
69 + border: 1px solid var(--color-border);
70 border-radius: 0.125rem;
71 padding: 0.125rem;
72 }
src/devtools/views/Components/ComponentFiltersModal.js
+4 -4
@@ -17,7 +17,7 @@ import Store from 'src/devtools/store';
17 import {
18 ComponentFilterElementType,
19 ComponentFilterDisplayName,
20 - ComponentFilterPath,
20 + ComponentFilterLocation,
21 ElementTypeClass,
22 ElementTypeContext,
23 ElementTypeEventTarget,
@@ -164,9 +164,9 @@ function ComponentFiltersModal({ store, setIsModalShowing }: Props) {
164 )
165 }
166 >
167 - <option value={ComponentFilterElementType}>type</option>
167 + <option value={ComponentFilterLocation}>location</option>
168 <option value={ComponentFilterDisplayName}>name</option>
169 - <option value={ComponentFilterPath}>path</option>
169 + <option value={ComponentFilterElementType}>type</option>
170 </select>
171 </td>
172 <td className={styles.TableCell}>
@@ -295,7 +295,7 @@ function useComponentFilters() {
295 }: ElementTypeComponentFilter);
296 } else if (
297 type === ComponentFilterDisplayName ||
298 - type === ComponentFilterPath
298 + type === ComponentFilterLocation
299 ) {
300 // $FlowFixMe TODO (filters)
301 cloned[index] = ({
src/types.js
+1 -1
@@ -40,7 +40,7 @@ export type ElementType = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
40 // If new filter types are added, use new numbers rather than re-ordering existing ones.
41 export const ComponentFilterElementType = 1;
42 export const ComponentFilterDisplayName = 2;
43 -export const ComponentFilterPath = 3;
43 +export const ComponentFilterLocation = 3;
44
45 export type FilterType = 1 | 2 | 3;
46
yarn.lock
+15
@@ -383,6 +383,13 @@
383 dependencies:
384 "@babel/helper-plugin-utils" "^7.0.0"
385
386 +"@babel/plugin-syntax-jsx@^7.2.0":
387 + version "7.2.0"
388 + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7"
389 + integrity sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==
390 + dependencies:
391 + "@babel/helper-plugin-utils" "^7.0.0"
392 +
393 "@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0":
394 version "7.2.0"
395 resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e"
@@ -605,6 +612,14 @@
612 "@babel/helper-plugin-utils" "^7.0.0"
613 "@babel/plugin-syntax-jsx" "^7.0.0"
614
615 +"@babel/plugin-transform-react-jsx-source@^7.2.0":
616 + version "7.2.0"
617 + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz#20c8c60f0140f5dd3cd63418d452801cf3f7180f"
618 + integrity sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==
619 + dependencies:
620 + "@babel/helper-plugin-utils" "^7.0.0"
621 + "@babel/plugin-syntax-jsx" "^7.2.0"
622 +
623 "@babel/plugin-transform-react-jsx@^7.0.0":
624 version "7.1.6"
625 resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.1.6.tgz#e6188e7d2a2dcd2796d45a87f8b0a8c906f57d1a"