/** * 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, testRule, makeTestCaseError, TestRecommendedRules, } from './shared-utils'; import {allRules} from '../src/rules/ReactCompilerRule'; testRule('plugin-recommended', TestRecommendedRules, { valid: [ { name: 'Basic example with component syntax', code: normalizeIndent` export default component HelloWorld( text: string = 'Hello!', onClick: () => void, ) { return
{text}
; } `, }, { // 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: [ { // TODO: actually return multiple diagnostics in this case name: 'Multiple diagnostic kinds from the same function are surfaced', code: normalizeIndent` import Child from './Child'; function Component() { const result = cond ?? useConditionalHook(); return <> {Child(result)} ; } `, errors: [ makeTestCaseError('Hooks must always be called in a consistent order'), ], }, { name: 'Multiple diagnostics within the same file are surfaced', code: normalizeIndent` function useConditional1() { 'use memo'; return cond ?? useConditionalHook(); } function useConditional2(props) { 'use memo'; return props.cond && useConditionalHook(); }`, errors: [ makeTestCaseError('Hooks must always be called in a consistent order'), makeTestCaseError('Hooks must always be called in a consistent order'), ], }, { name: "'use no forget' does not disable eslint rule", code: normalizeIndent` let count = 0; function Component() { 'use no forget'; return cond ?? useConditionalHook(); } `, errors: [ makeTestCaseError('Hooks must always be called in a consistent order'), ], }, { name: 'Multiple non-fatal useMemo diagnostics are surfaced', code: normalizeIndent` import {useMemo, useState} from 'react'; function Component({item, cond}) { const [prevItem, setPrevItem] = useState(item); const [state, setState] = useState(0); useMemo(() => { if (cond) { setPrevItem(item); setState(0); } }, [cond, item, init]); return ; }`, errors: [makeTestCaseError('useMemo() callbacks must return a value')], }, { name: 'Pipeline errors are reported', code: normalizeIndent` import useMyEffect from 'useMyEffect'; import {AUTODEPS} from 'react'; function Component({a}) { 'use no memo'; useMyEffect(() => console.log(a.b), AUTODEPS); return
Hello world
; } `, options: [ { environment: { inferEffectDependencies: [ { function: { source: 'useMyEffect', importSpecifierName: 'default', }, autodepsIndex: 1, }, ], }, }, ], errors: [ { message: /Cannot infer dependencies of this effect/, }, ], }, ], });