Repository navigation
test(core): layout starts read back from the browser allow round-off - #10188
Conversation
Two animated-layout cases compared a start time read back from the browser with a number the page holds. The browser keeps a start time in its own units: Chromium converts it to seconds and back, and WebKit rounds it to the microsecond. So the read back can differ by round-off. CI read 63.79999999998835 for 63.79999999998836 in "a swap whose parts ride the glide starts them with the glide, ...". That case now compares to six digits. "a change made after a block that follows an earlier layout motion ..." now lets its start sit 5e-7 ms below the clock reading. A start 0.1 ms off still fails the swap case, and a start on the pre-block frame time fails the block case.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis Report🔎 Preview ·
|
| Package | Where | Signature | Usage | |
|---|---|---|---|---|
| + | 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 |
./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 |
./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 |
./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: …} |
Not run on this PR: add ci:run-visual, ci:run-a11y or ci:run-rtl to run them.
Generated by PR Enrichment workflow | View full report
There was a problem hiding this comment.
Approved pending CI: CI has not run on this head yet. It runs once the pull request is marked ready for review and a maintainer adds the ci:run label.
The tolerances stay at round-off scale. Chromium reads 63.79999999998836 back as 63.79999999998835, as CI reported, and both cases pass at this head. A start moved by 1 µs still fails the swap case, and a start kept on the frame before the block still fails the block case.
[Automated review]
Maintainer impact
One animated-layout case fails on CI by round-off: "a swap whose parts ride the glide starts them with the glide, on the start read for the change, however late in its frame the change is made". In #9699's
pr-interaction (2/2),animatedLayout.interaction.browser.spec.ts:1013reported "Expected: 63.79999999998836, Received: 63.79999999998835". The code writes the change's start intoanimation.startTime, andlayoutStartForreturns the same number. But the case reads the start back from the browser, which keeps it in its own units:(63.79999999998836 / 1000) * 1000is 63.79999999998835, CI's value.The block case at line 949 ("a change made after a block that follows an earlier layout motion…") has the same exposure: it compares a start read back with a
performance.now()reading it can equal.Intended invariant
What each case checks is unchanged: the glide and the copy start on the change's start, and a change after a block starts after the block. No product code changes, and no timeout or retry changes.
Change
toBeCloseTo(run.startedAt, 6)allows a difference under 5e-7 ms.Both tolerances stay at round-off scale. A bound of a few units in the last place would fail WebKit's microsecond rounding.
Evidence
Every commit below is evidence, not for landing.
ca6d85c271(mainplus the probe, exact compare) fails 3 of 3 in each engine, with the values above.7eac81c8fa(the probe with this change's compare) passes 3 of 3 in each engine.5fdc599df4starts every layout animation 0.1 ms late. The swap case fails 3 of 3 in each engine.dac0908315starts a change after a block on the timeline's held frame time, the regression the block case guards. It fails 3 of 3 in each engine, starting about 1000 ms early.76cb9be7c6starts it 0.1 ms early. The swap case fails 3 of 3 in Chromium. The one-sided block case still passes 3 of 3 per engine: its change starts over 0.1 ms after the block.Scope
Testing
CI=true pnpm lint: 0 errors. Strict ESLint on the spec: 0 errors (4 older warnings, none on these lines). Core typecheck;check:changesets; Changeset coverage: nothing here ships to consumers;review:pre.