microsoft / microsoft/fluentui-react-native
Components: Component tests for the agentic component library
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 179
- Avg merge
- 16h 17m
- Merged PRs (30d)
- 30
Description
Summary
Establish and enforce one minimum coverage contract for every agentic component and primitive, close the current gaps, and document how generated components satisfy it. Existing tests and stories provide a strong base, but their depth is inconsistent and no repository gate currently prevents an under-tested component from shipping.
Observed. Coverage already exists and is colocated, so this is not a green-field
task: 18 components and 5 primitives each have a runtime test and a story, and 22 of
23 have a type test. What is missing is a contract: nothing states what coverage a
component must have, nothing enforces it, and the depth varies by a factor of five
between components. The canonical component, button, is itself the one file set with
no type test.
Goal
Define and enforce a single minimum coverage contract for every component and
primitive in packages/agentic/components, close the measured gaps against that
contract in the existing library, and publish authoring instructions so a newly
generated component arrives with the same coverage as button without an author
having to infer it.
Stage
Stage 1 (beta foundations). The readiness model and every missing-component task
depend on this contract existing.
Why it matters
Observed. .github/skills/agentic-component-authoring/references/tests-and-stories.md
describes what good coverage looks like in prose and points at button as the
canonical example, but it is a skill reference loaded by an agent, not a gate. A
component can be generated, exported, and published with three test cases and no
snapshot, and nothing in lint, build, or test objects.
Observed. Runtime case counts across the 18 components range from 3
(divider.test.tsx) to 15 (button.test.tsx). The spread is not explained by
component complexity alone: progress-bar has three variant axes and six cases;
spinner has one axis and four.
Observed. Only button, list-item, and skeleton have __snapshots__
directories. The other 15 components have no committed record of resolved output, so a
token or theme regression that changes every component's flattened style is invisible
to the package test run.
Inferred. Because readiness-model.md intends to publish a
readiness level per component, and because a readiness level is only meaningful if the
evidence behind it is uniform, an un-enforced coverage contract makes every readiness
claim self-reported.
Observed current state
Inventory
All counts observed from packages/agentic/components/src on
user/jasonvmo/furn-plan.
| Component | Runtime cases | Type test | Story | Snapshots |
|---|---|---|---|---|
accordion |
10 | accordion.types.test.tsx |
yes | no |
avatar |
9 | avatar.types.test.ts |
yes | no |
badge |
6 | badge.types.test.ts |
yes | no |
button |
15 | none | yes | yes |
card |
7 | card.types.test.tsx |
yes | no |
checkbox |
13 | checkbox.types.test.ts |
yes | no |
divider |
3 | divider.types.test.ts |
yes | no |
input |
9 | input.types.test.tsx |
yes | no |
list-item |
12 | list-item.types.test.ts |
yes | yes |
listbox-item |
9 | listbox-item.types.test.ts |
yes | no |
menu-item |
10 | menu-item.types.test.ts |
yes | no |
progress-bar |
6 | progress-bar.types.test.ts |
yes | no |
radio |
9 | radio.types.test.ts |
yes | no |
skeleton |
4 | skeleton.types.test.ts |
yes | yes |
spinner |
4 | spinner.types.test.ts |
yes | no |
switch |
12 | switch.types.test.ts |
yes | no |
tab |
10 | tab.types.test.ts |
yes | no |
tag |
9 | tag.types.test.ts |
yes | no |
Observed. Primitives (checkbox-indicator, compound-item-layout, focus-visual,
icon, layout-stable-text) each have a runtime test, a type test, and a story, and
none has a SPEC.md.
Execution
Observed. jest.config.cjs
extends @fluentui-react-native/scripts/jest-config and sets testTimeout: 10000.
package.json declares furn.jestPlatform: "macos", so the package's unit tests
resolve React Native modules through the macOS preset only. There is no Windows or
Win32 unit-test pass for this package.
Observed. src/index.test.ts
is an export-surface guard: it references each use*_unstable, use*Styles_unstable,
and render*_unstable symbol. It is maintained by hand, so it can silently fall behind
src/index.ts.
Observed. On-device coverage is broader than the render smoke list.
apps/storybook/windows-tests/storybook-smoke.test.cjs
selects 14 story IDs: the 3 render cases data-driven from
scripts/smoke-stories.json
(components-button--default, primitives-icon--default,
primitives-callout--default), a keyboard-movement case on
components-button--overview, and 10 focus-regression cases covering tag,
accordion, tab, listbox-item, checkbox, menu-item, list-item, radio,
switch, and the interactive card. Counting Button Overview, that is 11 focus
assertions, each checking HasKeyboardFocus after a click and that the app has not
terminated.
Observed. On-device touchpoints therefore exist for 11 of the 18 components plus
the icon primitive and Callout. avatar, badge, divider, input,
progress-bar, skeleton, and spinner have none, and neither do the
checkbox-indicator, compound-item-layout, focus-visual, and
layout-stable-text primitives.
Observed. That harness is Windows-only (testEnvironment: '@react-native-windows/automation' via
jest.windows.config.cjs), has no
macOS equivalent, and is invoked by no workflow.
Inferred. The on-device problem this task has to address is not absence of
coverage but its shape: real Windows focus coverage exists, is unenforced, single
platform, concentrated on one axis, and silent about seven components and four
primitives.
Scope
- Write the minimum coverage contract for a higher-order component and for a
primitive, as a durable document under
packages/agentic/components(or as a section in the existing authoring reference,
if that is the preferred home). - Decide, per requirement, whether it is required, required when the component has
the relevant axis, or recommended, so the contract can be checked rather than
argued. - Close the concrete gaps in the existing library:
- add
button.types.test.ts; - add snapshot coverage for the components whose visual contract is
state-dependent, or record why a component is exempt; - raise the low-coverage components to the contract, driven by their
SPEC.md
variant axes rather than by a target number; - raise primitive coverage from the axes in each colocated
CONTRACT.md, its public
types, and its renderer branches. Public primitives do not require an upstream
SPEC.md.
- add
- Add enforcement: a check that fails when a component directory is missing a
required artifact, and a check thatsrc/index.tsandsrc/index.test.tsagree. - Write the "how to create component tests" instructions, including the table-driven
pattern for finite axes, the self-driving versus externally driven axis
distinction, and when a snapshot is the right tool instead of an assertion. - Decide whether a second Jest platform pass (Windows) is in scope for beta, and
record the decision either way. - After the retain-or-retire decision in
storybook-e2e.md, add the
uncovered components and primitives through the portable story-test format.
Only extendstorybook-smoke.test.cjswhen that decision explicitly retains
it; otherwise preserve its existing focus regressions until the replacement
demonstrates parity. State whether stable roottestIDvalues are required
by the portable coverage contract.
Out of scope
- Building the on-device end-to-end pipeline; that is
research/infrastructure/tasks/storybook-e2e.md. - Adding a visual-regression service.
- Changing component behavior to make it easier to test. A test that requires a
behavior change should raise the behavior change as its own item. - Coverage for
packages/components,packages/experimental, andpackages/native.
Deliverables
- A written coverage contract, with each requirement marked required, conditional, or
recommended, and with the condition stated for conditional requirements. button.types.test.tscovering thebuttonslot acceptance and public prop
contract, matching the depth of the other 17 type tests.- Snapshot coverage decisions applied: added where the visual contract is
state-dependent, and a recorded exemption where it is not. - Raised runtime coverage for items below the contract, with each new component case
traceable to aSPEC.mdaxis and each new primitive case traceable to its
CONTRACT.md, public types, or renderer branches. - An automated structural check that a component directory contains its required
files, wired into the package's declaredlintortestscript. - An automated check that every symbol exported from
src/index.tsis exercised by
src/index.test.ts, replacing the hand-maintained list. - Authoring instructions for creating component tests, discoverable from
packages/agentic/components/AGENTS.md. - Portable on-device story tests for the components and primitives the current
Windows harness does not touch, plus a stated position on whethertestID
conventions are contract-required for every component.
Acceptance criteria
- A coverage contract document exists and is linked from
packages/agentic/components/AGENTS.md. - Every requirement in the contract is either mechanically checkable or explicitly
marked as a review-time judgement. -
packages/agentic/components/src/components/button/button.types.test.tsexists
and covers slot acceptance and mutually exclusive props. - Every one of the 18 components either has a
__snapshots__directory or a
recorded exemption in the contract document. - No component's runtime test omits an axis declared in its
SPEC.mdvariant
table; where an axis is deliberately untested, the reason is recorded. - No primitive's runtime test omits a behavioral, prop, accessibility, or renderer
axis declared by itsCONTRACT.mdand public types; where an axis is deliberately
untested, the reason is recorded. - A structural coverage check fails when a component directory is missing a
required file, and it runs as part of a declared package script. - The
src/index.ts/src/index.test.tsagreement is machine-verified. -
yarn workspace @fluentui-react-native/components format,lint,build, and
testall pass after the changes. - The authoring instructions are sufficient for a new component to be generated
with contract-satisfying coverage without reading an existing component's tests. - A decision on a Windows Jest pass is recorded, with its rationale.
- Every component and primitive has a portable on-device story test or a
recorded exemption, closing the current gap foravatar,badge,
divider,input,progress-bar,skeleton,spinner, and the four
uncovered primitives. - Existing Windows focus regressions remain covered until the portable
replacement passes the same cases; no new work is committed to the legacy
harness before its retain-or-retire decision. - The contract states whether a stable root
testIDis required for every
component or only for the on-device validated subset.
Dependencies and ordering
- Blocks readiness-model.md: the readiness levels assert
coverage, so the coverage contract must exist first. - Blocks, softly, every task in
missing-components/: each new component should be
generated against the finished contract rather than retrofitted. - Independent of focus-zone.md and
spec-ingestion-and-generation.md. - Consumes the Infrastructure workstream's on-device pipeline and its
legacy-harness decision for the platform-validation half of the contract.
Risks and open decisions
- Snapshot churn. Snapshots over flattened resolved styles are sensitive to theme
and token changes. Open decision: snapshot the resolved output of a small,
named set of states per component (thebuttonapproach) rather than whole trees. - Contract as ceiling. A mechanical contract can become the maximum rather than
the minimum. Open decision: whether the structural check should also assert a
floor on axis coverage, or leave depth to review. - Second Jest platform cost. A Windows preset pass doubles unit-test runtime and
may surface platform-fork type conflicts that
AGENTS.mdwarns about. Open decision: whether beta
requires it or whether on-device Windows coverage from the Storybook pipeline is
sufficient. - Primitives have no
SPEC.md. Resolved in
#4250: public
primitives use a colocated lightweightCONTRACT.md, public types, and renderer
branches as their coverage source instead of an upstream design-system spec. - On-device coverage is single-platform and single-axis. The existing 11 focus
assertions run only under@react-native-windows/automationand only check
HasKeyboardFocusafter a click. Open decision: whether extending them is this
task's job or belongs entirely to
storybook-e2e.md; the boundary
should be agreed before either task starts, so the coverage is not written twice or
not at all.
Evidence and references
packages/agentic/components/src/components
andsrc/primitives- file
inventory behind the table above.packages/agentic/components/src/components/button/button.test.tsx- the canonical runtime test.
packages/agentic/components/src/index.test.ts- the hand-maintained export guard.
packages/agentic/components/jest.config.cjs
andpackage.json- test
execution andfurn.jestPlatform..github/skills/agentic-component-authoring/references/tests-and-stories.md- existing prose guidance, the starting point for the contract.
packages/agentic/components/src/components/AGENTS.md- the required-structure and testing invariants that the contract should formalize.
apps/storybook/windows-tests/storybook-smoke.test.cjs
andapps/storybook/scripts/smoke-stories.json- the actual on-device coverage: 3 render cases plus 11 focus assertions across 14
story IDs, run by
jest.windows.config.cjs.
- the actual on-device coverage: 3 render cases plus 11 focus assertions across 14
Sources retrieved 2026-08-20.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the existing tests-and-stories.md reference, packages/agentic/components/AGENTS.md, jest.config.cjs, src/index.ts, and src/index.test.ts. Inventory the component SPEC.md files, primitive CONTRACT.md files, runtime/type tests, snapshots, and story-test entry points before defining the contract. Done means the documented requirements, missing coverage, structural checks, export check, authoring guidance, and portable story tests are implemented and acceptance criteria are verifiable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github, react-native, typescript
- Domain
- developer-experience, documentation, frontend, mobile-dev, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100