test(web): stabilize the overflow mutation control

This commit is contained in:
creatixchu
2026-08-05 19:09:26 +08:00
parent 438b769fbc
commit cfc2783b87
@@ -40,13 +40,13 @@ const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/conversation-column-over
*/ */
const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md') const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md')
const MODE = webSnapshotMode() const MODE = webSnapshotMode()
/** Narrow sweep stop where the mutation control retains overflow across scrollbar implementations. */
const CONTROL_VIEWPORT = 600
/** /**
* Viewport widths bracketing the glow. The hero box is `min(776, column - 48)` * Viewport widths bracketing the glow: the narrow stops retain the reported
* and the glow is 1051/776 of it, so every stop under a ~1051px column bleeds * bleed while the widest stop proves the relation can also be false.
* and the widest one does not — the sweep therefore covers both sides of the
* relation rather than sampling one comfortable width.
*/ */
const WIDTHS = [1680, 1200, 1000, 800, 600] const WIDTHS = [1680, 1200, 1000, 800, CONTROL_VIEWPORT]
/** Element id of the mutation control's injected sheet, so the test can take it back out. */ /** Element id of the mutation control's injected sheet, so the test can take it back out. */
const CONTROL_STYLE_ID = 'dsh-column-overflow-control' const CONTROL_STYLE_ID = 'dsh-column-overflow-control'
/** Horizontal wheel delta per gesture; must exceed the widest bleed the sweep can produce. */ /** Horizontal wheel delta per gesture; must exceed the widest bleed the sweep can produce. */
@@ -261,7 +261,9 @@ describe('web e2e: the conversation column scrolls on one axis', () => {
// The vacuity guard, in two halves: the glow has to reach past the column // The vacuity guard, in two halves: the glow has to reach past the column
// at the narrow stops, and that reach has to still register as scrollable // at the narrow stops, and that reach has to still register as scrollable
// overflow. Without both, the claim below holds for free. // overflow. Without both, the claim below holds for free.
expect(stops.filter(stop => stop.glowBleeds).map(stop => stop.width)).toEqual([1200, 1000, 800, 600]) expect(stops.filter(stop => stop.glowBleeds).map(stop => stop.width)).toEqual([
1200, 1000, 800, CONTROL_VIEWPORT,
])
for (const stop of stops.filter(stop => stop.glowBleeds)) { for (const stop of stops.filter(stop => stop.glowBleeds)) {
expect(stop.bleedRange, `viewport ${String(stop.width)}`).toBeGreaterThan(0) expect(stop.bleedRange, `viewport ${String(stop.width)}`).toBeGreaterThan(0)
} }
@@ -283,10 +285,6 @@ describe('web e2e: the conversation column scrolls on one axis', () => {
// that a one-axis scroller computes to `auto` — and shows the same gesture, // that a one-axis scroller computes to `auto` — and shows the same gesture,
// at the same timing, carrying the column to its positive scroll boundary. // at the same timing, carrying the column to its positive scroll boundary.
// Without it a `scrollLeft` of 0 could equally mean the wheel never arrived. // Without it a `scrollLeft` of 0 could equally mean the wheel never arrived.
// Settle the resize first: this test runs at 1680 on its own and after the
// sweep's 600 in a full run, and an unsettled column reports the previous
// viewport's bleed.
await settleAt(1200)
// Injected with an id rather than through `addStyleTag`, so the teardown // Injected with an id rather than through `addStyleTag`, so the teardown
// below can take the sheet out again by selector: it must not outlive this // below can take the sheet out again by selector: it must not outlive this
// test, or the golden ends up reading the control. // test, or the golden ends up reading the control.
@@ -297,7 +295,10 @@ describe('web e2e: the conversation column scrolls on one axis', () => {
document.head.append(sheet) document.head.append(sheet)
}, CONTROL_STYLE_ID) }, CONTROL_STYLE_ID)
try { try {
const before = await measureColumn(page, 1200) // Resolve the mutated layout at the narrowest sweep stop. At wider stops,
// a classic scrollbar can change the available box enough to remove the
// overflow that the control is meant to expose.
const before = await settleAt(CONTROL_VIEWPORT)
expect(before.overflowX).toBe('auto') expect(before.overflowX).toBe('auto')
expect(before.bleedRange).toBeGreaterThan(0) expect(before.bleedRange).toBeGreaterThan(0)
const scrollLimit = await horizontalScrollLimit(page) const scrollLimit = await horizontalScrollLimit(page)
@@ -316,7 +317,7 @@ describe('web e2e: the conversation column scrolls on one axis', () => {
} }
// The override is gone and the shipped state is back: the later goldens // The override is gone and the shipped state is back: the later goldens
// read the product, not the control. // read the product, not the control.
expect((await measureColumn(page, 1200)).overflowX).toBe('hidden') expect((await settleAt(CONTROL_VIEWPORT)).overflowX).toBe('hidden')
expect(tripwire.pageErrors).toEqual([]) expect(tripwire.pageErrors).toEqual([])
}, 120_000) }, 120_000)