mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 08:03:28 +00:00
test(e2e): start the board marquee off the board's padding cliff
`selects the full lane across a single large marquee scroll jump` failed the changed-e2e-specs job with `Received: 0` — no card ever previewed. The CI trace shows the drag started at (284, 195) and the failure screenshot shows a native text selection with no marquee overlay, so the board never accepted the pointerdown. An element scan across that row shows why: the marquee may only start on empty board space, and the usable strip is only x 280-298 — the board's own left edge on one side, the first lane's cards on the other. `selectionBox.x + 4` aims 4px inside that strip, so a layout that rounds a few pixels differently lands outside the board entirely, where the pointerdown never reaches the handler and the browser text-selects instead. Aim at the middle of the measured strip, assert the start point really is empty board space before pressing, and assert the selection rect appears so a rejected gesture fails immediately instead of surfacing 15s later as "0 cards previewed". Also carried over from the first attempt at this deflake: the lane scroll now jumps until the virtualizer stops moving the bottom, because a measured card is much taller than the row estimate and a fixed pass budget commits the marquee short of the last cards; and the final assertion checks the badge's text so a short selection reports its count.
This commit is contained in:
@@ -373,28 +373,85 @@ test.describe('Workspace board lane virtualization', () => {
|
||||
throw new Error('Expected the marquee lane and selection surface to have bounding boxes')
|
||||
}
|
||||
|
||||
await orcaPage.mouse.move(selectionBox.x + 4, box.y + 12)
|
||||
// Why: the marquee may only start on empty board space — the board ignores a
|
||||
// pointerdown on a card, and one that misses the board entirely never reaches
|
||||
// its handler at all, so the browser text-selects instead and no marquee runs.
|
||||
// The usable strip is the board's padding between its own left edge and the
|
||||
// first lane's cards; starting a fixed 4px inside it hugs that outer edge and
|
||||
// falls off it whenever layout rounds differently. Aim at the middle instead.
|
||||
const firstCardBox = await laneCards.first().boundingBox()
|
||||
if (!firstCardBox) {
|
||||
throw new Error('Expected the first marquee card to have a bounding box')
|
||||
}
|
||||
const startX = Math.round((selectionBox.x + firstCardBox.x) / 2)
|
||||
const startY = Math.round(box.y + 12)
|
||||
const startTarget = await orcaPage.evaluate(
|
||||
({ x, y }) => {
|
||||
const element = document.elementFromPoint(x, y)
|
||||
return {
|
||||
onSurface: Boolean(element?.closest('[data-workspace-board-selection-surface]')),
|
||||
onIgnoredTarget: Boolean(
|
||||
element?.closest('[data-workspace-board-card-id], a, button, input, [role="button"]')
|
||||
)
|
||||
}
|
||||
},
|
||||
{ x: startX, y: startY }
|
||||
)
|
||||
expect(
|
||||
startTarget,
|
||||
`marquee start point (${startX}, ${startY}) must be empty board space; ` +
|
||||
`selectionBox.x=${selectionBox.x} firstCard.x=${firstCardBox.x}`
|
||||
).toEqual({ onSurface: true, onIgnoredTarget: false })
|
||||
|
||||
await orcaPage.mouse.move(startX, startY)
|
||||
await orcaPage.mouse.down()
|
||||
await orcaPage.mouse.move(box.x + box.width - 18, box.y + 80, { steps: 4 })
|
||||
|
||||
// Why: proves the board accepted the gesture. Without it a rejected
|
||||
// pointerdown only shows up 15s later as "0 cards previewed", which reads as
|
||||
// a virtualization bug rather than a marquee that never started.
|
||||
await expect(orcaPage.locator('[data-workspace-board-selection-rect]')).toBeVisible()
|
||||
await expect
|
||||
.poll(() => lane.locator('[data-workspace-board-card-area-selected="true"]').count(), {
|
||||
timeout: 15_000
|
||||
})
|
||||
.toBeGreaterThan(0)
|
||||
await laneScroll.evaluate(async (element) => {
|
||||
for (let pass = 0; pass < 4; pass++) {
|
||||
// Why: a measured card is much taller than the lane's row estimate, so each
|
||||
// jump to the bottom re-measures the window and grows the spacer past the
|
||||
// scrollTop the jump just landed on. A fixed pass budget commits the marquee
|
||||
// mid-growth on a loaded machine — short of the last cards — so jump until
|
||||
// the virtualizer stops moving the bottom instead.
|
||||
const laneScrollSettle = await laneScroll.evaluate(async (element) => {
|
||||
let settledPasses = 0
|
||||
let passes = 0
|
||||
while (settledPasses < 2 && passes < 40) {
|
||||
passes += 1
|
||||
element.scrollTop = element.scrollHeight
|
||||
element.dispatchEvent(new Event('scroll', { bubbles: true }))
|
||||
await new Promise<void>((resolve) => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => resolve()))
|
||||
})
|
||||
const maxScrollTop = element.scrollHeight - element.clientHeight
|
||||
settledPasses = element.scrollTop >= maxScrollTop - 1 ? settledPasses + 1 : 0
|
||||
}
|
||||
return {
|
||||
passes,
|
||||
scrollTop: element.scrollTop,
|
||||
maxScrollTop: element.scrollHeight - element.clientHeight
|
||||
}
|
||||
})
|
||||
expect(
|
||||
laneScrollSettle.scrollTop,
|
||||
`lane scroll never settled at its bottom: ${JSON.stringify(laneScrollSettle)}`
|
||||
).toBeGreaterThanOrEqual(laneScrollSettle.maxScrollTop - 1)
|
||||
|
||||
await orcaPage.mouse.move(box.x + box.width - 18, box.y + box.height - 12)
|
||||
await orcaPage.mouse.up()
|
||||
|
||||
await expect(
|
||||
orcaPage.getByText(`${MARQUEE_WORKSPACE_COUNT} selected`, { exact: true })
|
||||
).toBeVisible()
|
||||
// Why: assert the badge's text, not its presence — a marquee that stopped
|
||||
// short reports the count it did commit instead of a bare locator timeout.
|
||||
await expect(orcaPage.getByText(/^\d+ selected$/)).toHaveText(
|
||||
`${MARQUEE_WORKSPACE_COUNT} selected`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user