/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {
ErrorCategory,
getRuleForCategory,
} from 'babel-plugin-react-compiler/src/CompilerError';
import {normalizeIndent, makeTestCaseError, testRule} from './shared-utils';
import {allRules} from '../src/rules/ReactCompilerRule';
testRule(
'rules-of-hooks',
allRules[getRuleForCategory(ErrorCategory.Hooks).name].rule,
{
valid: [
{
name: 'Basic example',
code: normalizeIndent`
function Component() {
useHook();
return
Hello world
;
}
`,
},
{
name: 'Violation with Flow suppression',
code: `
// Valid since error already suppressed with flow.
function useHook() {
if (cond) {
// $FlowFixMe[react-rule-hook]
useConditionalHook();
}
}
`,
},
{
// OK because invariants are only meant for the compiler team's consumption
name: '[Invariant] Defined after use',
code: normalizeIndent`
function Component(props) {
let y = function () {
m(x);
};
let x = { a };
m(x);
return y;
}
`,
},
{
name: "Classes don't throw",
code: normalizeIndent`
class Foo {
#bar() {}
}
`,
},
],
invalid: [
{
name: 'Simple violation',
code: normalizeIndent`
function useConditional() {
if (cond) {
useConditionalHook();
}
}
`,
errors: [
makeTestCaseError(
'Hooks must always be called in a consistent order',
),
],
},
{
name: 'Multiple diagnostics within the same function are surfaced',
code: normalizeIndent`
function useConditional() {
cond ?? useConditionalHook();
props.cond && useConditionalHook();
return Hello world
;
}`,
errors: [
makeTestCaseError(
'Hooks must always be called in a consistent order',
),
makeTestCaseError(
'Hooks must always be called in a consistent order',
),
],
},
],
},
);