Repository navigation
test(BottomSheet): timestamp the reduced-motion mouse close - #10756
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This test passed on main since, but it failed intermittently ( |
|
AI review status for this pull request.
|
PR Analysis Report🔎 Preview ·
|
| Component | Size | LoC | Visual · A11y · RTL |
|---|---|---|---|
| BottomSheet | 68.2 kB (0) · 7.7 kB CSS (0) | — | ✗ · ✓ · — |
| BottomSheetSwitcher | 17.9 kB (0) · 3.4 kB CSS (0) | — | ✗ · ✓ · — |
Visual changes: 2 snapshots in 1 component
A change is a question for the reviewer, not a failure.
| Component · story | Before | After | Diff |
|---|---|---|---|
| BottomSheet · Text Only (neutral, dark) | ![]() |
![]() |
![]() |
| BottomSheet · Text Only (neutral, light) | ![]() |
![]() |
![]() |
Package size: measured; main has no measurement of the merge base to compare yet.
API changes: cli +22 · ~7 · −0 (against the merge base's committed report); theme-butter +1 · ~0 · −0 (against the merge base's committed report); theme-y2k +1 · ~0 · −0 (against the merge base's committed report)
Committed API report behind this build: cli 29 rows, core 34 rows, theme-butter 1 row, theme-y2k 1 row; run pnpm api:report.
31 API changes (advisory)
| Package | Where | Signature | Usage | |
|---|---|---|---|---|
| + | cli |
./api · Functions · function exportSearchIndex |
function exportSearchIndex @experimental: (options?: { cwd?: string | undefined; package?: string | undefined }) => Promise<SearchIndex> |
import {exportSearchIndex} from '@astryxdesign/cli/api'; exportSearchIndex(…) |
| + | cli |
./api · Functions · function rankSearchIndex |
function rankSearchIndex @experimental: (query: string, indexes: SearchIndex | SearchIndex[], options?: { type?: SearchDomain | undefined; limit?: number | undefined }) => Promise<SearchResponse> |
import {rankSearchIndex} from '@astryxdesign/cli/api'; rankSearchIndex(…) |
| + | cli |
./api · Types · type DocsListChild |
type DocsListChild = DocsNodeChild & { topic: string; description: string; children?: DocsListChild[]; childCount?: number } |
import type {DocsListChild} from '@astryxdesign/cli/api' |
| + | cli |
./api · Types · type DocsListNamespace |
childCount?: number | undefined |
import type {DocsListNamespace} from '@astryxdesign/cli/api'; const x: DocsListNamespace = {childCount: …} |
| + | cli |
./api · Types · type DocsListNamespace |
children?: DocsListChild[] | undefined |
import type {DocsListNamespace} from '@astryxdesign/cli/api'; const x: DocsListNamespace = {children: …} |
| + | cli |
./api · Types · type SearchIndex |
type SearchIndex |
import type {SearchIndex} from '@astryxdesign/cli/api' |
| + | cli |
./api · Types · type SearchResultEntry |
deprecated?: ComponentDeprecation | undefined |
import type {SearchResultEntry} from '@astryxdesign/cli/api'; const x: SearchResultEntry = {deprecated: …} |
| + | cli |
./authoring · Types · interface ComponentDeprecation |
interface ComponentDeprecation |
import type {ComponentDeprecation} from '@astryxdesign/cli/authoring' |
| + | cli |
./authoring · Types · interface ComponentIconSlotDoc |
interface ComponentIconSlotDoc |
import type {ComponentIconSlotDoc} from '@astryxdesign/cli/authoring' |
| + | cli |
./authoring · Types · interface ComponentIconSlotStateDoc |
interface ComponentIconSlotStateDoc |
import type {ComponentIconSlotStateDoc} from '@astryxdesign/cli/authoring' |
| + | cli |
./authoring · Types · interface MultiComponentDoc |
deprecated?: ComponentDeprecation |
import type {MultiComponentDoc} from '@astryxdesign/cli/authoring'; const x: MultiComponentDoc = {deprecated: …} |
| + | cli |
./authoring · Types · interface SingleComponentDoc |
deprecated?: ComponentDeprecation |
import type {SingleComponentDoc} from '@astryxdesign/cli/authoring'; const x: SingleComponentDoc = {deprecated: …} |
| + | cli |
./doc · Types · interface ComponentBaseDoc |
deprecated?: ComponentDeprecation |
import type {ComponentBaseDoc} from '@astryxdesign/cli/doc'; const x: ComponentBaseDoc = {deprecated: …} |
| + | cli |
./doc · Types · interface SubComponentDoc |
deprecated?: ComponentDeprecation |
import type {SubComponentDoc} from '@astryxdesign/cli/doc'; const x: SubComponentDoc = {deprecated: …} |
| + | cli |
./doc · Also exported from an earlier entry point · ComponentDeprecation |
ComponentDeprecation (./authoring) |
import {ComponentDeprecation} from '@astryxdesign/cli/doc' |
| + | cli |
./doc · Also exported from an earlier entry point · ComponentIconSlotDoc |
ComponentIconSlotDoc (./authoring) |
import {ComponentIconSlotDoc} from '@astryxdesign/cli/doc' |
| + | cli |
./doc · Also exported from an earlier entry point · ComponentIconSlotStateDoc |
ComponentIconSlotStateDoc (./authoring) |
import {ComponentIconSlotStateDoc} from '@astryxdesign/cli/doc' |
| + | cli |
./json · Also exported from an earlier entry point · DocsListChild |
DocsListChild (./api) |
import {DocsListChild} from '@astryxdesign/cli/json' |
| + | cli |
./json · Also exported from an earlier entry point · SearchIndex |
SearchIndex (./api) |
import {SearchIndex} from '@astryxdesign/cli/json' |
| + | cli |
./template · Also exported from an earlier entry point · ComponentDeprecation |
ComponentDeprecation (./authoring) |
import {ComponentDeprecation} from '@astryxdesign/cli/template' |
| + | cli |
./template · Also exported from an earlier entry point · ComponentIconSlotDoc |
ComponentIconSlotDoc (./authoring) |
import {ComponentIconSlotDoc} from '@astryxdesign/cli/template' |
| + | cli |
./template · Also exported from an earlier entry point · ComponentIconSlotStateDoc |
ComponentIconSlotStateDoc (./authoring) |
import {ComponentIconSlotStateDoc} from '@astryxdesign/cli/template' |
| ~ | cli |
./api · Functions · function search |
function search: (query: string, options?: { cwd?: string | undefined; type?: "template" | "component" | "hook" | "theme" | "doc" | undefined; limit?: number | undefined }) => Promise<SearchResponse> → function search: (query: string, options?: { cwd?: string | undefined; type?: "template" | "component" | "doc" | "theme" | "hook" | undefined; limit?: number | undefined }) => Promise<SearchResponse> |
import {search} from '@astryxdesign/cli/api'; search(…) |
| ~ | cli |
./api · Types · type SwizzleCopyResponse |
data: { component: string; package: string; outputDir: string; filesCopied: number; files: string[]; usesStyleX: boolean; feedback?: SwizzleFeedback | undefined } → data: { component: string; package: string; outputDir: string; filesCopied: number; files: string[]; usesStyleX: boolean; dependencies: Record<string, string>; marker … #84d9505b |
import type {SwizzleCopyResponse} from '@astryxdesign/cli/api'; const x: SwizzleCopyResponse = {data: …} |
| ~ | cli |
./authoring · Types · interface MultiComponentDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {MultiComponentDoc} from '@astryxdesign/cli/authoring'; const x: MultiComponentDoc = {theming: …} |
| ~ | cli |
./authoring · Types · interface SingleComponentDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {SingleComponentDoc} from '@astryxdesign/cli/authoring'; const x: SingleComponentDoc = {theming: …} |
| ~ | cli |
./authoring · Types · type TemplateCategory |
type TemplateCategory = | 'Dashboard - Analytics' | 'Dashboard - Comparison' | 'Dashboard - KPI Summary' | 'Dashboard - Monitoring' | 'Dashboard - Executive Summary' | 'Dashboard - Sco … #e7c18378 → type TemplateCategory = | 'Dashboard - Analytics' | 'Dashboard - Comparison' | 'Dashboard - KPI Summary' | 'Dashboard - Monitoring' | 'Dashboard - Executive Summary' | 'Dashboard - Sco … #a8be998f |
import type {TemplateCategory} from '@astryxdesign/cli/authoring' |
| ~ | cli |
./doc · Types · interface ComponentBaseDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {ComponentBaseDoc} from '@astryxdesign/cli/doc'; const x: ComponentBaseDoc = {theming: …} |
| ~ | cli |
./doc · Types · interface SubComponentDoc |
theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[] } → theming?: { container?: boolean; targets: ComponentThemingTarget[]; vars?: ComponentThemingVar[]; derived?: ComponentThemingDerivedVar[]; componentIcons?: ComponentIconSlotDoc[] } |
import type {SubComponentDoc} from '@astryxdesign/cli/doc'; const x: SubComponentDoc = {theming: …} |
| + | theme-butter |
Public attributes · attr data-astryx-pressable |
attr data-astryx-pressable (public data attribute) |
[data-astryx-pressable] { … } |
| + | theme-y2k |
Public attributes · attr data-astryx-pressable |
attr data-astryx-pressable (public data attribute) |
[data-astryx-pressable] { … } |
Touched components checked; add ci:run-visual, ci:run-a11y or ci:run-rtl to run the full suites.
Generated by PR Enrichment workflow | View full report
|
Merged after @imdreamrunner approved 638afbc. |
Co-authored-by: astracat-bot[bot] <323722387+astracat-bot[bot]@users.noreply.github.com>
Co-authored-by: astracat-bot[bot] <323722387+astracat-bot[bot]@users.noreply.github.com>






validation: ran
pnpm exec playwright test --config playwright.config.ts --project=chromium packages/core/src/BottomSheet/__tests__/BottomSheetRelease.a11y.chromium.spec.ts --grep 'a mouse close under reduced motion' --repeat-each=20 --retries=0: 20/20 passed normally and 20/20 passed with 200 ms mouse-event delivery delays;pnpm exec playwright test --config playwright.config.ts --project=chromium packages/core/src/BottomSheet/__tests__/BottomSheetRelease.a11y.chromium.spec.ts --retries=0: 13/13 passed; targeted Prettier and ESLint checks passed.Maintainer impact
The reduced-motion mouse-close contract intermittently fails because the test's untimestamped five-step mouse drag depends on event delivery speed. CI run 42518970572, job “Accessibility spec-test contracts (5/6)”, at ac0046c failed
expect(dialog).toBeHidden({timeout: 2_000}): Expected hidden, Received visible.A delayed synthetic stream lowers the mouse release velocity, or zeroes it after the tracker's stillness interval. The 150 px drag then snaps back instead of projecting past the dismiss line, so the test never exercises its intended closing behavior.
Intended invariant and change
No behavior change. Reuse this file's existing timestamped CDP
mouseDraghelper. Keep the downward mouse gesture and 150 px travel, pin it to 50 ms (3,000 px/s), and release 1 ms after the final move. The mouse projection remains on the intended dismissal branch: travel exceeds the 48 px projection floor, and150 + 3 × 499 = 1,647 pxpasses the dismiss line. The original input had no specified duration; this chooses a representative fast mouse release, not a longer drag or a different product path.This follows AST-100 FR4's event-time velocity contract and keeps BottomSheet FR15 / reduced-motion DR1's no-travel assertions. Every assertion and timeout remains unchanged. No component, story, runner or workflow changes.
Evidence
deflake_evidence: b. It went red in 2 streaks in 7 days (2026-11-08T05:23Z, 2026-11-08T20:32Z), passing between them.Successful CI run 42503506547 at c08de54 occurred between those streaks. Later successful run 42533992004 at c590f9b contains the failing commit, verified by
git merge-base --is-ancestor.Local tests use base 15098bc, with a freshly built Storybook and the pinned Node/pnpm versions. The BottomSheet sources, this test and VelocityTracker have no changes between the failing commit and that base.
Before the fix, replacing the original
mouse.move(..., {steps: 5})with five 30 px moves and a 200 ms delay after each move reproduced the same hidden-dialog failure in 2/2 runs (--repeat-each=2 --retries=0). Only the synthetic input cadence changed.After the fix, normal delivery passed 20/20 (
--repeat-each=20 --retries=0). Adding a 200 ms delay before every CDP mouse event, including release, while retaining the pinned timestamps also passed 20/20 with the same command. All failure-injection delays were removed from the final change.Scope
Fixes test
99432e86d30378823a6b196cd0f534fb47a0f28955f8de3addb50ad141604b63:packages/core/src/BottomSheet/__tests__/BottomSheetRelease.a11y.chromium.spec.ts › a mouse close under reduced motion moves the sheet no further.