test(e2e): start marquee from an explicit empty lane

This commit is contained in:
Brennan Benson
2026-08-03 20:16:15 -07:00
parent 2e489d897e
commit 7cdfb7149a
@@ -1,13 +1,6 @@
import { test, expect } from './helpers/orca-app'
import { waitForActiveWorktree, waitForSessionReady } from './helpers/store'
type MarqueeStartPoint = { x: number; y: number } | null
type MarqueeStartProbe = {
point: MarqueeStartPoint
geometry: { surfaceLeft: number; laneScrollTop: number; cardLeft: number } | null
blockers: string[]
}
const SEEDED_WORKSPACE_COUNT = 300
const MARQUEE_WORKSPACE_COUNT = 102
const MANY_LANE_COUNT = 21
@@ -315,8 +308,9 @@ test.describe('Workspace board lane virtualization', () => {
test('selects the full lane across a single large marquee scroll jump', async ({ orcaPage }) => {
const statusId = 'virtual-marquee'
const emptyStatusId = 'virtual-marquee-start'
await orcaPage.evaluate(
({ count, status }) => {
({ count, emptyStatus, status }) => {
const store = window.__store
if (!store) {
throw new Error('window.__store is not available')
@@ -360,10 +354,13 @@ test.describe('Workspace board lane virtualization', () => {
})
state.setWorkspaceStatuses([
{ id: status, label: 'Virtual marquee' },
...state.workspaceStatuses.filter((entry) => entry.id !== status)
{ id: emptyStatus, label: 'Marquee start' },
...state.workspaceStatuses.filter(
(entry) => entry.id !== status && entry.id !== emptyStatus
)
])
},
{ count: MARQUEE_WORKSPACE_COUNT, status: statusId }
{ count: MARQUEE_WORKSPACE_COUNT, emptyStatus: emptyStatusId, status: statusId }
)
await orcaPage.getByRole('button', { name: 'Workspace board' }).click()
@@ -373,123 +370,37 @@ test.describe('Workspace board lane virtualization', () => {
const laneCards = lane.locator('[data-workspace-board-card-id]')
await expect.poll(() => laneCards.count(), { timeout: 15_000 }).toBeGreaterThan(3)
const laneScroll = lane.locator('[data-workspace-board-lane-scroll]')
// Why: the marquee only starts on empty board space — the board ignores a
// pointerdown on a card, and one that lands on anything stacked over the
// board never reaches its handler at all, so the browser text-selects and no
// marquee runs. A precomputed point cannot be trusted: the strip is a few px
// of board padding, and the sheet, sidebar and lane fill all keep resizing it
// after the card-count wait. Ask the live DOM which point is actually empty,
// scanning the strip between the board's left edge and the first card. The
// scan stays in the lane's top rows because the marquee anchors its range in
// content space — starting below the first card would exclude it from the 102.
const probeMarqueeStart = (): Promise<MarqueeStartProbe> =>
orcaPage.evaluate((status) => {
const IGNORED = [
'[data-workspace-board-card-id]',
'a',
'button',
'input',
'select',
'textarea',
'[role="button"]',
'[role="menu"]',
'[role="menuitem"]'
].join(',')
const surface = document.querySelector<HTMLElement>(
'[data-workspace-board-selection-surface]'
)
const laneElement = document.querySelector<HTMLElement>(
`[data-workspace-status="${status}"]`
)
const scroll = laneElement?.querySelector<HTMLElement>('[data-workspace-board-lane-scroll]')
const card = laneElement?.querySelector<HTMLElement>('[data-workspace-board-card-id]')
if (!surface || !scroll || !card) {
return { point: null, geometry: null, blockers: ['board not mounted'] }
}
const surfaceRect = surface.getBoundingClientRect()
const scrollRect = scroll.getBoundingClientRect()
const cardRect = card.getBoundingClientRect()
const geometry = {
surfaceLeft: Math.round(surfaceRect.left),
laneScrollTop: Math.round(scrollRect.top),
cardLeft: Math.round(cardRect.left)
}
const describe = (element: Element | null): string => {
if (!element) {
return 'null'
}
const classes =
typeof element.className === 'string' && element.className.trim().length > 0
? `.${element.className.trim().split(/\s+/).slice(0, 3).join('.')}`
: ''
return `${element.tagName.toLowerCase()}${classes}`
}
const blockers: string[] = []
const top = Math.round(scrollRect.top)
for (let y = top + 6; y <= top + 40; y += 6) {
for (
let x = Math.ceil(surfaceRect.left) + 2;
x <= Math.floor(cardRect.left) - 2;
x += 2
) {
const element = document.elementFromPoint(x, y)
const onSurface = Boolean(element?.closest('[data-workspace-board-selection-surface]'))
const onIgnoredTarget = Boolean(element?.closest(IGNORED))
if (onSurface && !onIgnoredTarget) {
return { point: { x, y }, geometry, blockers }
}
if (blockers.length < 6) {
blockers.push(
`(${x},${y})=${describe(element)}${onSurface ? ' onSurface' : ''}${
onIgnoredTarget ? ' ignored' : ''
}`
)
}
}
}
return { point: null, geometry, blockers }
}, statusId)
// Why: one empty reading can be a frame mid-relayout. Two consecutive probes
// agreeing on the same point is what proves the strip has stopped moving.
let marqueeStart: MarqueeStartPoint = null
let probe = await probeMarqueeStart()
let previousKey = JSON.stringify(probe.point)
const probeDeadline = Date.now() + 15_000
while (Date.now() < probeDeadline) {
await orcaPage.waitForTimeout(100)
probe = await probeMarqueeStart()
const key = JSON.stringify(probe.point)
if (probe.point && key === previousKey) {
marqueeStart = probe.point
break
}
previousKey = key
}
// Why: a viewport that leaves the board no empty space is a layout this test
// cannot drive at all — report that instead of failing on it.
test.skip(
marqueeStart === null,
`no empty board space for the marquee start; geometry=${JSON.stringify(
probe.geometry
)} blockers=${probe.blockers.join(' | ')}`
const emptyLaneScroll = orcaPage.locator(
`[data-workspace-status="${emptyStatusId}"] [data-workspace-board-lane-scroll]`
)
const start = marqueeStart as { x: number; y: number }
const box = await laneScroll.boundingBox()
if (!box) {
throw new Error('Expected the marquee lane to have a bounding box')
const emptyBox = await emptyLaneScroll.boundingBox()
if (!box || !emptyBox) {
throw new Error('Expected the marquee and empty start lanes to have bounding boxes')
}
const preflight = await probeMarqueeStart()
expect(
preflight.point,
`marquee start point (${start.x}, ${start.y}) must still be empty board space; ` +
`geometry=${JSON.stringify(preflight.geometry)} blockers=${preflight.blockers.join(' | ')}`
).not.toBeNull()
await orcaPage.mouse.move(start.x, start.y)
// Why: the sidebar seam overlaps the board edge on CI, so start in a dedicated empty lane.
const startX = Math.round(emptyBox.x + Math.min(24, emptyBox.width / 4))
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; ` +
`emptyLane=${JSON.stringify(emptyBox)}`
).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 })