You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 enforcement: a check that fails when a component directory is missing a
required artifact, and a check that src/index.ts and src/index.test.ts agree.
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 extend storybook-smoke.test.cjs when that decision explicitly retains
it; otherwise preserve its existing focus regressions until the replacement
demonstrates parity. State whether stable root testID values are required
by the portable coverage contract.
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, and packages/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.ts covering the button slot 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 a SPEC.md axis 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 declared lint or test script.
An automated check that every symbol exported from src/index.ts is 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 whether testID
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.ts exists
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.md variant
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 its CONTRACT.md and 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.ts agreement is machine-verified.
yarn workspace @fluentui-react-native/components format, lint, build, and test all 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 for avatar, 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 testID is required for every
component or only for the on-device validated subset.
Dependencies and ordering
Blocksreadiness-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.
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 (the button approach) 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.md warns 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 lightweight CONTRACT.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/automation and only check HasKeyboardFocus after 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.
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 withno 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 thatcontract in the existing library, and publish authoring instructions so a newly
generated component arrives with the same coverage as
buttonwithout an authorhaving 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.mddescribes what good coverage looks like in prose and points at
buttonas thecanonical 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, ortestobjects.Observed. Runtime case counts across the 18 components range from 3
(
divider.test.tsx) to 15 (button.test.tsx). The spread is not explained bycomponent complexity alone:
progress-barhas three variant axes and six cases;spinnerhas one axis and four.Observed. Only
button,list-item, andskeletonhave__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/srconuser/jasonvmo/furn-plan.accordionaccordion.types.test.tsxavataravatar.types.test.tsbadgebadge.types.test.tsbuttoncardcard.types.test.tsxcheckboxcheckbox.types.test.tsdividerdivider.types.test.tsinputinput.types.test.tsxlist-itemlist-item.types.test.tslistbox-itemlistbox-item.types.test.tsmenu-itemmenu-item.types.test.tsprogress-barprogress-bar.types.test.tsradioradio.types.test.tsskeletonskeleton.types.test.tsspinnerspinner.types.test.tsswitchswitch.types.test.tstabtab.types.test.tstagtag.types.test.tsObserved. Primitives (
checkbox-indicator,compound-item-layout,focus-visual,icon,layout-stable-text) each have a runtime test, a type test, and a story, andnone has a
SPEC.md.Execution
Observed.
jest.config.cjsextends
@fluentui-react-native/scripts/jest-configand setstestTimeout: 10000.package.jsondeclaresfurn.jestPlatform: "macos", so the package's unit testsresolve React Native modules through the macOS preset only. There is no Windows or
Win32 unit-test pass for this package.
Observed.
src/index.test.tsis an export-surface guard: it references each
use*_unstable,use*Styles_unstable,and
render*_unstablesymbol. It is maintained by hand, so it can silently fall behindsrc/index.ts.Observed. On-device coverage is broader than the render smoke list.
apps/storybook/windows-tests/storybook-smoke.test.cjsselects 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 oncomponents-button--overview, and 10 focus-regression cases coveringtag,accordion,tab,listbox-item,checkbox,menu-item,list-item,radio,switch, and the interactivecard. Counting Button Overview, that is 11 focusassertions, each checking
HasKeyboardFocusafter a click and that the app has notterminated.
Observed. On-device touchpoints therefore exist for 11 of the 18 components plus
the
iconprimitive andCallout.avatar,badge,divider,input,progress-bar,skeleton, andspinnerhave none, and neither do thecheckbox-indicator,compound-item-layout,focus-visual, andlayout-stable-textprimitives.Observed. That harness is Windows-only (
testEnvironment: '@react-native-windows/automation'viajest.windows.config.cjs), has nomacOS 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
primitive, as a durable document under
packages/agentic/components(or as a section in the existing authoring reference,if that is the preferred home).
the relevant axis, or recommended, so the contract can be checked rather than
argued.
button.types.test.ts;state-dependent, or record why a component is exempt;
SPEC.mdvariant axes rather than by a target number;
CONTRACT.md, its publictypes, and its renderer branches. Public primitives do not require an upstream
SPEC.md.required artifact, and a check that
src/index.tsandsrc/index.test.tsagree.pattern for finite axes, the self-driving versus externally driven axis
distinction, and when a snapshot is the right tool instead of an assertion.
record the decision either way.
storybook-e2e.md, add theuncovered components and primitives through the portable story-test format.
Only extend
storybook-smoke.test.cjswhen that decision explicitly retainsit; otherwise preserve its existing focus regressions until the replacement
demonstrates parity. State whether stable root
testIDvalues are requiredby the portable coverage contract.
Out of scope
research/infrastructure/tasks/storybook-e2e.md.behavior change should raise the behavior change as its own item.
packages/components,packages/experimental, andpackages/native.Deliverables
recommended, and with the condition stated for conditional requirements.
button.types.test.tscovering thebuttonslot acceptance and public propcontract, matching the depth of the other 17 type tests.
state-dependent, and a recorded exemption where it is not.
traceable to a
SPEC.mdaxis and each new primitive case traceable to itsCONTRACT.md, public types, or renderer branches.files, wired into the package's declared
lintortestscript.src/index.tsis exercised bysrc/index.test.ts, replacing the hand-maintained list.packages/agentic/components/AGENTS.md.Windows harness does not touch, plus a stated position on whether
testIDconventions are contract-required for every component.
Acceptance criteria
packages/agentic/components/AGENTS.md.marked as a review-time judgement.
packages/agentic/components/src/components/button/button.types.test.tsexistsand covers slot acceptance and mutually exclusive props.
__snapshots__directory or arecorded exemption in the contract document.
SPEC.mdvarianttable; where an axis is deliberately untested, the reason is recorded.
axis declared by its
CONTRACT.mdand public types; where an axis is deliberatelyuntested, the reason is recorded.
required file, and it runs as part of a declared package script.
src/index.ts/src/index.test.tsagreement is machine-verified.yarn workspace @fluentui-react-native/components format,lint,build, andtestall pass after the changes.with contract-satisfying coverage without reading an existing component's tests.
recorded exemption, closing the current gap for
avatar,badge,divider,input,progress-bar,skeleton,spinner, and the fouruncovered primitives.
replacement passes the same cases; no new work is committed to the legacy
harness before its retain-or-retire decision.
testIDis required for everycomponent or only for the on-device validated subset.
Dependencies and ordering
coverage, so the coverage contract must exist first.
missing-components/: each new component should be
generated against the finished contract rather than retrofitted.
spec-ingestion-and-generation.md.
legacy-harness decision for the platform-validation half of the contract.
Risks and open decisions
and token changes. Open decision: snapshot the resolved output of a small,
named set of states per component (the
buttonapproach) rather than whole trees.the minimum. Open decision: whether the structural check should also assert a
floor on axis coverage, or leave depth to review.
may surface platform-fork type conflicts that
AGENTS.mdwarns about. Open decision: whether betarequires it or whether on-device Windows coverage from the Storybook pipeline is
sufficient.
SPEC.md. Resolved in#4250: public
primitives use a colocated lightweight
CONTRACT.md, public types, and rendererbranches as their coverage source instead of an upstream design-system spec.
assertions run only under
@react-native-windows/automationand only checkHasKeyboardFocusafter a click. Open decision: whether extending them is thistask's job or belongs entirely to
storybook-e2e.md; the boundaryshould be agreed before either task starts, so the coverage is not written twice or
not at all.
Evidence and references
packages/agentic/components/src/componentsand
src/primitives- fileinventory behind the table above.
packages/agentic/components/src/components/button/button.test.tsxpackages/agentic/components/src/index.test.tspackages/agentic/components/jest.config.cjsand
package.json- testexecution and
furn.jestPlatform..github/skills/agentic-component-authoring/references/tests-and-stories.mdpackages/agentic/components/src/components/AGENTS.mdapps/storybook/windows-tests/storybook-smoke.test.cjsand
apps/storybook/scripts/smoke-stories.jsonstory IDs, run by
jest.windows.config.cjs.Sources retrieved 2026-08-20.