From 9e2884fdf04a32372e290f414aa80ab9e2305128 Mon Sep 17 00:00:00 2001 From: Srividya Ramaswamy Date: Mon, 26 Oct 2026 18:07:26 -0700 Subject: [PATCH] test(input): cover value ownership and accessibility precedence Exercise INP-001, INP-002 and INP-005 through controlled and uncontrolled edits and root/editor state merging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4b66f3ef-85ac-4405-bd35-dcc167a077b1 --- .changeset/four-states-shine.md | 5 ++ .../src/components/input/input.test.tsx | 71 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 .changeset/four-states-shine.md diff --git a/.changeset/four-states-shine.md b/.changeset/four-states-shine.md new file mode 100644 index 0000000000..064435dc68 --- /dev/null +++ b/.changeset/four-states-shine.md @@ -0,0 +1,5 @@ +--- + +--- + + diff --git a/packages/agentic/components/src/components/input/input.test.tsx b/packages/agentic/components/src/components/input/input.test.tsx index 0cb64d3508..00e7a06a4d 100644 --- a/packages/agentic/components/src/components/input/input.test.tsx +++ b/packages/agentic/components/src/components/input/input.test.tsx @@ -26,6 +26,77 @@ function flattenStyle(style: unknown) { } describe('Input', () => { + it('INP-002 retains internally owned edits across defaultValue changes and reports each edit once', async () => { + const onChangeText = jest.fn(); + const component = await render(); + + expect(getTextbox(component)).toHaveDisplayValue('Seed'); + await fireEvent.changeText(getTextbox(component), 'Edited'); + expect(getTextbox(component)).toHaveDisplayValue('Edited'); + expect(onChangeText.mock.calls).toEqual([['Edited']]); + + await component.rerender(); + expect(getTextbox(component)).toHaveDisplayValue('Edited'); + expect(onChangeText).toHaveBeenCalledTimes(1); + + await fireEvent.changeText(getTextbox(component), ''); + expect(getTextbox(component)).toHaveDisplayValue(''); + expect(onChangeText.mock.calls).toEqual([['Edited'], ['']]); + }); + + it('INP-002 leaves controlled text unchanged until the owner writes back, including an empty string', async () => { + const onChangeText = jest.fn(); + const component = await render(); + + expect(getTextbox(component)).toHaveDisplayValue(''); + await fireEvent.changeText(getTextbox(component), 'Proposed'); + expect(onChangeText.mock.calls).toEqual([['Proposed']]); + expect(getTextbox(component)).toHaveDisplayValue(''); + + await component.rerender(); + expect(getTextbox(component)).toHaveDisplayValue('Accepted'); + expect(onChangeText).toHaveBeenCalledTimes(1); + + await component.rerender(); + expect(getTextbox(component)).toHaveDisplayValue(''); + expect(onChangeText).toHaveBeenCalledTimes(1); + }); + + it('INP-001 INP-005 merges root and editor accessibility state without overriding owned semantics', async () => { + const component = await render( + , + ); + const textbox = component.getByRole('textbox', { name: 'Editor name' }); + + expect(textbox.props.accessibilityHint).toBe('Editor hint'); + expect(textbox.props.accessibilityState).toEqual({ + busy: true, + expanded: true, + selected: true, + disabled: false, + invalid: true, + readOnly: true, + }); + expect(textbox.props.testID).toBe('editor-identifier'); + expect(component.queryByTestId('root-identifier')).toBeNull(); + expect(component.getByTestId('input-root').props.accessible).toBe(false); + expect(textbox.props.editable).toBe(false); + expect(textbox.props.focusable).toBe(true); + }); + it('forwards its ref prop through phased rendering to the native root', async () => { const ref = React.createRef>();