main
ts 135 lines 3.61 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {
9 ErrorCategory,
10 getRuleForCategory,
11 } from 'babel-plugin-react-compiler/src/CompilerError';
12 import {
13 normalizeIndent,
14 testRule,
15 makeTestCaseError,
16 TestRecommendedRules,
17 } from './shared-utils';
18 import {allRules} from '../src/rules/ReactCompilerRule';
19
20 testRule('plugin-recommended', TestRecommendedRules, {
21 valid: [
22 {
23 name: 'Basic example with component syntax',
24 code: normalizeIndent`
25 export default component HelloWorld(
26 text: string = 'Hello!',
27 onClick: () => void,
28 ) {
29 return <div onClick={onClick}>{text}</div>;
30 }
31 `,
32 },
33
34 {
35 // OK because invariants are only meant for the compiler team's consumption
36 name: '[Invariant] Defined after use',
37 code: normalizeIndent`
38 function Component(props) {
39 let y = function () {
40 m(x);
41 };
42
43 let x = { a };
44 m(x);
45 return y;
46 }
47 `,
48 },
49 {
50 name: "Classes don't throw",
51 code: normalizeIndent`
52 class Foo {
53 #bar() {}
54 }
55 `,
56 },
57 ],
58 invalid: [
59 {
60 name: 'Multiple diagnostic kinds from the same function are surfaced',
61 code: normalizeIndent`
62 import Child from './Child';
63 function Component() {
64 const result = cond ?? useConditionalHook();
65 return <>
66 {Child(result)}
67 </>;
68 }
69 `,
70 errors: [
71 makeTestCaseError('Hooks must always be called in a consistent order'),
72 makeTestCaseError('Capitalized functions are reserved for components'),
73 ],
74 },
75 {
76 name: 'Multiple diagnostics within the same file are surfaced',
77 code: normalizeIndent`
78 function useConditional1() {
79 'use memo';
80 return cond ?? useConditionalHook();
81 }
82 function useConditional2(props) {
83 'use memo';
84 return props.cond && useConditionalHook();
85 }`,
86 errors: [
87 makeTestCaseError('Hooks must always be called in a consistent order'),
88 makeTestCaseError('Hooks must always be called in a consistent order'),
89 ],
90 },
91 {
92 name: "'use no forget' does not disable eslint rule",
93 code: normalizeIndent`
94 let count = 0;
95 function Component() {
96 'use no forget';
97 return cond ?? useConditionalHook();
98
99 }
100 `,
101 errors: [
102 makeTestCaseError('Hooks must always be called in a consistent order'),
103 ],
104 },
105 {
106 name: 'Multiple non-fatal useMemo diagnostics are surfaced',
107 code: normalizeIndent`
108 import {useMemo, useState} from 'react';
109
110 function Component({item, cond}) {
111 const [prevItem, setPrevItem] = useState(item);
112 const [state, setState] = useState(0);
113
114 useMemo(() => {
115 if (cond) {
116 setPrevItem(item);
117 setState(0);
118 }
119 }, [cond, item, init]);
120
121 return <Child x={state} />;
122 }`,
123 errors: [
124 makeTestCaseError('useMemo() callbacks must return a value'),
125 makeTestCaseError(
126 'Calling setState from useMemo may trigger an infinite loop',
127 ),
128 makeTestCaseError(
129 'Calling setState from useMemo may trigger an infinite loop',
130 ),
131 makeTestCaseError('Found extra memoization dependencies'),
132 ],
133 },
134 ],
135 });