diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/e2e/rule-of-react-violations/inner-mutation-state.e2e.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/e2e/rule-of-react-violations/inner-mutation-state.e2e.tsx new file mode 100644 index 0000000000000..5a417843f4f56 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/e2e/rule-of-react-violations/inner-mutation-state.e2e.tsx @@ -0,0 +1,144 @@ +/** + * 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 {render, fireEvent} from '@testing-library/react'; +import * as React from 'react'; +import {useState} from 'react'; + +type Data = { + isDataFetched: boolean; + fieldData: { + username: { + errorMessage: string | null; + value: string | null; + }; + address: { + errorMessage: string | null; + value: string | null; + }; + }; +}; +function useRoRViolation(): [ + Data, + ( + field: 'username' | 'address', + kind: 'errorMessage' | 'value', + newValue: string, + ) => void, +] { + 'use no forget'; + const [count, setCount] = useState(0); + const [state, setState] = useState({ + isDataFetched: false, + fieldData: { + username: { + errorMessage: null, + value: null, + }, + address: { + errorMessage: null, + value: null, + }, + }, + }); + const update = ( + field: 'username' | 'address', + kind: 'errorMessage' | 'value', + ) => { + setState((prevState: Data) => { + const newState = {...prevState}; + const data = + field === 'username' + ? newState.fieldData.username + : newState.fieldData.address; + if (kind === 'errorMessage') { + data.errorMessage = `value${count}`; + } else { + data.errorMessage = `value${count}`; + } + return newState; + }); + setCount(count + 1); + }; + + return [state, update]; +} + +function Component({ + label, + showFields, +}: { + label: keyof Data['fieldData']; + showFields: boolean; +}) { + const [state, update] = useRoRViolation(); + function readState(label: keyof Data['fieldData']) { + return state.fieldData[label]; + } + const field = readState(label); + return ( + <> + {showFields ? ( +
+ {field.errorMessage ?? '(none)'} {field.value ?? '(none)'} +
+ ) : ( +
no data
+ )} + + + ); +} + +test('update-button', () => { + const label: 'username' = 'username'; + const {asFragment, rerender, getByTestId} = render( + , + ); + + expect(asFragment()).toMatchInlineSnapshot(` + +
+ (none) (none) +
+