From 5caf2e71ac47afc108ea5d30893b8b5a8c4b37db Mon Sep 17 00:00:00 2001 From: Srividya Ramaswamy Date: Mon, 26 Oct 2026 18:26:49 -0700 Subject: [PATCH] test(tag): cover caller-owned dismissal and single-target anatomy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4b66f3ef-85ac-4405-bd35-dcc167a077b1 --- .changeset/twenty-rooms-smile.md | 5 ++ .../src/components/tag/tag.stories.tsx | 24 +++++- .../src/components/tag/tag.test.tsx | 73 +++++++++++++++++++ .../agentic/components/tsconfig.stories.json | 1 + 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 .changeset/twenty-rooms-smile.md diff --git a/.changeset/twenty-rooms-smile.md b/.changeset/twenty-rooms-smile.md new file mode 100644 index 0000000000..064435dc68 --- /dev/null +++ b/.changeset/twenty-rooms-smile.md @@ -0,0 +1,5 @@ +--- + +--- + + diff --git a/packages/agentic/components/src/components/tag/tag.stories.tsx b/packages/agentic/components/src/components/tag/tag.stories.tsx index db18865563..b90f5aa9b0 100644 --- a/packages/agentic/components/src/components/tag/tag.stories.tsx +++ b/packages/agentic/components/src/components/tag/tag.stories.tsx @@ -3,6 +3,7 @@ import type { ReactNode } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import type { Meta, StoryObj } from '@storybook/react-native'; +import type { WdioStory } from '@fluentui-react-native/storybook-desktop/testing'; import { Tag } from './tag'; import type { TagAppearance, TagLayout, TagShape, TagSize } from './tag.types'; @@ -73,9 +74,28 @@ const meta: Meta = { export default meta; -type Story = StoryObj; +type Story = WdioStory>; -export const Default: Story = {}; +export const Default: Story = { + wdio: { + 'TAG-004 TAG-008 exposes the whole enabled tag as a native button': async ({ browser, expect }) => { + const tag = await browser.$('~agentic-storybook-tag'); + expect(await tag.getTagName()).toBe('button'); + await expect(tag).toBeEnabled(); + }, + }, +}; + +export const NativeDisabled: Story = { + args: { content: 'Unavailable filter', disabled: true }, + wdio: { + 'TAG-008 exposes disabled native button semantics': async ({ browser, expect }) => { + const tag = await browser.$('~agentic-storybook-tag'); + expect(await tag.getTagName()).toBe('button'); + await expect(tag).toBeDisabled(); + }, + }, +}; export const Overview: Story = { render: () => ( diff --git a/packages/agentic/components/src/components/tag/tag.test.tsx b/packages/agentic/components/src/components/tag/tag.test.tsx index 44639c211b..efc6bc4fd9 100644 --- a/packages/agentic/components/src/components/tag/tag.test.tsx +++ b/packages/agentic/components/src/components/tag/tag.test.tsx @@ -23,6 +23,79 @@ function getRootStyle(component: RenderResult): ViewStyle { } describe('Tag', () => { + it('TAG-004 leaves removal to the caller after repeated whole-tag activation', async () => { + const onPress = jest.fn(); + const component = await renderTag({ content: 'Engineering', onPress }); + + await fireEvent.press(getRoot(component)); + await fireEvent.press(getRoot(component)); + + expect(onPress).toHaveBeenCalledTimes(2); + expect(component.getByText('Engineering')).toBeOnTheScreen(); + expect(component.getAllByRole('button')).toHaveLength(1); + await component.rerender(<>); + expect(component.queryByRole('button')).toBeNull(); + }); + + it.each(['dismiss=false', 'dismissIcon=null'] as const)( + 'TAG-002 TAG-004 %s suppresses only the glyph, not whole-tag activation', + async (suppression) => { + const onPress = jest.fn(); + const component = await renderTag({ + content: { children: 'Engineering', testID: 'tag-spec-content' }, + dismiss: suppression !== 'dismiss=false', + dismissIcon: + suppression === 'dismissIcon=null' + ? null + : { fontSource: { codepoint: 0x2715, fontFamily: 'Arial' }, testID: 'tag-spec-dismiss' }, + onPress, + }); + + expect(getRoot(component).children).toHaveLength(1); + expect(getRoot(component).children[0]).toBe(component.getByTestId('tag-spec-content')); + expect(component.queryByTestId('tag-spec-dismiss')).toBeNull(); + await fireEvent.press(getRoot(component)); + expect(onPress).toHaveBeenCalledTimes(1); + expect(component.getByText('Engineering')).toBeOnTheScreen(); + }, + ); + + it('TAG-003 TAG-004 orders decorative leading and dismiss icons around the label in one target', async () => { + const component = await renderTag({ + content: { children: 'Engineering', testID: 'tag-spec-content' }, + dismissIcon: { fontSource: { codepoint: 0x2715, fontFamily: 'Arial' }, testID: 'tag-spec-dismiss' }, + leadingIcon: { fontSource: { codepoint: 0x2605, fontFamily: 'Arial' }, testID: 'tag-spec-leading' }, + }); + + expect(getRoot(component).children).toEqual([ + component.getByTestId('tag-spec-leading'), + component.getByTestId('tag-spec-content'), + component.getByTestId('tag-spec-dismiss'), + ]); + expect(component.getAllByRole('button')).toHaveLength(1); + for (const id of ['tag-spec-leading', 'tag-spec-dismiss']) { + expect(component.getByTestId(id).props.accessible).toBe(false); + } + }); + + it('TAG-002 explicitly null content suppresses the placeholder while retaining the default dismiss glyph', async () => { + const component = await renderTag({ accessibilityLabel: 'Remove filter', content: null }); + expect(component.queryByText('Tag text')).toBeNull(); + expect(getRoot(component).children).toHaveLength(1); + expect(getRoot(component).props.accessibilityLabel).toBe('Remove filter'); + }); + + it.each([false, true])('TAG-008 owned disabled=%s overrides contradictory caller state while preserving busy', async (disabled) => { + const component = await renderTag({ + accessibilityState: { busy: true, disabled: !disabled }, + content: 'Engineering', + disabled, + }); + + expect(getRoot(component).props.accessibilityState).toMatchObject({ busy: true, disabled }); + expect(getRoot(component).props.focusable).toBe(!disabled); + }); + it('renders default dismissible tag accessibility and styling', async () => { const component = await renderTag({ content: 'Engineering' }); diff --git a/packages/agentic/components/tsconfig.stories.json b/packages/agentic/components/tsconfig.stories.json index 3c3f82336e..2dfa2d3afc 100644 --- a/packages/agentic/components/tsconfig.stories.json +++ b/packages/agentic/components/tsconfig.stories.json @@ -21,6 +21,7 @@ "src/components/spinner/spinner.stories.tsx", "src/components/switch/switch.stories.tsx", "src/components/tablist/tablist.stories.tsx", + "src/components/tag/tag.stories.tsx", "src/primitives/focus-zone/focus-zone.stories.tsx", "src/primitives/layout-stable-text/layout-stable-text.stories.tsx", "src/**/*.story-helpers.tsx",