Skip to content

Commit 557d81c

Browse files
ryan-williamsclaude
andcommitted
test(e2e): rewrite v-drag cypress specs to match the implementation
The fork-authored `v-drag.spec.ts` had never passed in CI — it asserted UI that doesn't exist and used pointer events the handlers ignore. Rewritten to exercise the real behavior; 16/16 pass on clean fixture state. - z-order: dropped the 3 tests for non-existent `button[title*="forward/backward"]` (z-order is keyboard-only) and replaced them with `Cmd+Arrow` / `Cmd+Shift+Arrow` shortcut tests dispatched to `window` (where `onZOrderKeyDown` listens). - drag-to-move + snap: the body-drag handler ignores `pointermove`s whose `pointerId` differs from the `pointerdown`; the moves omitted it, so the drag never ran. Added `pointerId: 1` to every move/up. - reset-AR: the button is `v-if`d on `hasAspectRatioChanged`, so it's absent on a fresh selection. Rewritten to assert absence, then free-resize a corner (re-query the handle per event to dodge re-render staleness) → button appears → click → AR restored. Note: the tests mutate the fork's persistent deck state (`.slidev/state.db`), so local re-runs need the fixture's `.slidev/` cleared between runs; CI runs on a fresh checkout so it's unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 030732e commit 557d81c

1 file changed

Lines changed: 83 additions & 47 deletions

File tree

cypress/e2e/examples/v-drag.spec.ts

Lines changed: 83 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ context('v-drag', () => {
7474
cy.get('[data-testid="box1"]')
7575
.trigger('pointerdown', { button: 0, pointerId: 1, buttons: 1, force: true })
7676

77-
// Move pointer (events go to document after pointerdown)
78-
cy.document().trigger('pointermove', { clientX: 400, clientY: 400, buttons: 1 })
79-
cy.document().trigger('pointerup')
77+
// Move pointer (events go to document after pointerdown). `pointerId` MUST match
78+
// the pointerdown's — the body-drag handler ignores moves with a different id.
79+
cy.document().trigger('pointermove', { clientX: 400, clientY: 400, buttons: 1, pointerId: 1 })
80+
cy.document().trigger('pointerup', { pointerId: 1 })
8081

8182
cy.wait(200)
8283

@@ -91,59 +92,65 @@ context('v-drag', () => {
9192
})
9293
})
9394

94-
describe('z-order', () => {
95+
describe('z-order (keyboard)', () => {
9596
beforeEach(() => {
9697
goPage(15) // v-drag Z-Order Tests page
9798
})
9899

99-
it('z-order buttons are visible when element is selected', () => {
100-
// Click to select stack-a
101-
cy.get('[data-testid="stack-a"]').click()
102-
cy.wait(200)
103-
104-
// Z-order buttons should be visible
105-
cy.get('#drag-control-container button[title*="forward"]').should('exist')
106-
cy.get('#drag-control-container button[title*="backward"]').should('exist')
107-
})
100+
// Z-order has no on-canvas buttons — it's driven by Cmd/Ctrl+Arrow shortcuts,
101+
// handled by DragControl's window-level capture-phase `onZOrderKeyDown` listener
102+
// (Cmd+Up = forward, Cmd+Down = backward, add Shift for to-front/to-back). Dispatch
103+
// straight to `window` so the capture listener fires.
104+
function pressZOrder(key: 'ArrowUp' | 'ArrowDown', shift = false) {
105+
cy.window().then((win) => {
106+
win.dispatchEvent(new win.KeyboardEvent('keydown', {
107+
key,
108+
metaKey: true,
109+
shiftKey: shift,
110+
bubbles: true,
111+
cancelable: true,
112+
}))
113+
})
114+
}
108115

109-
it('bring forward increases z-index', () => {
110-
// Click to select stack-a (initial z-index: 100)
111-
cy.get('[data-testid="stack-a"]').click()
116+
it('cmd+ArrowUp brings the selected element forward (raises z-index)', () => {
117+
cy.get('[data-testid="stack-a"]').click() // z:100, below b(101) and c(102)
112118
cy.wait(200)
113-
114-
// Get initial z-index
115119
cy.get('[data-testid="stack-a"]').then(($el) => {
116120
const initialZIndex = Number.parseInt($el.css('z-index'))
117-
118-
// Click bring forward button
119-
cy.get('#drag-control-container button[title*="forward"]').first().click()
121+
pressZOrder('ArrowUp')
120122
cy.wait(200)
121-
122-
// z-index should have increased
123123
cy.get('[data-testid="stack-a"]').should(($el2) => {
124-
const newZIndex = Number.parseInt($el2.css('z-index'))
125-
expect(newZIndex).to.be.greaterThan(initialZIndex)
124+
expect(Number.parseInt($el2.css('z-index'))).to.be.greaterThan(initialZIndex)
126125
})
127126
})
128127
})
129128

130-
it('send backward decreases z-index', () => {
131-
// Click to select stack-c (initial z-index: 102)
132-
cy.get('[data-testid="stack-c"]').click()
129+
it('cmd+ArrowDown sends the selected element backward (lowers z-index)', () => {
130+
cy.get('[data-testid="stack-c"]').click() // z:102, above a(100) and b(101)
133131
cy.wait(200)
134-
135-
// Get initial z-index
136132
cy.get('[data-testid="stack-c"]').then(($el) => {
137133
const initialZIndex = Number.parseInt($el.css('z-index'))
138-
139-
// Click send backward button
140-
cy.get('#drag-control-container button[title*="backward"]').first().click()
134+
pressZOrder('ArrowDown')
141135
cy.wait(200)
142-
143-
// z-index should have decreased
144136
cy.get('[data-testid="stack-c"]').should(($el2) => {
145-
const newZIndex = Number.parseInt($el2.css('z-index'))
146-
expect(newZIndex).to.be.lessThan(initialZIndex)
137+
expect(Number.parseInt($el2.css('z-index'))).to.be.lessThan(initialZIndex)
138+
})
139+
})
140+
})
141+
142+
it('cmd+Shift+ArrowUp brings the element above all its siblings', () => {
143+
cy.get('[data-testid="stack-a"]').click() // starts lowest at z:100
144+
cy.wait(200)
145+
pressZOrder('ArrowUp', true)
146+
cy.wait(200)
147+
cy.get('[data-testid="stack-a"]').then(($a) => {
148+
const za = Number.parseInt($a.css('z-index'))
149+
cy.get('[data-testid="stack-b"]').should(($b) => {
150+
expect(za).to.be.greaterThan(Number.parseInt($b.css('z-index')))
151+
})
152+
cy.get('[data-testid="stack-c"]').should(($c) => {
153+
expect(za).to.be.greaterThan(Number.parseInt($c.css('z-index')))
147154
})
148155
})
149156
})
@@ -193,13 +200,38 @@ context('v-drag', () => {
193200
cy.get('#drag-control-container div[style*="cursor"]').should('have.length.at.least', 4)
194201
})
195202

196-
it('reset aspect ratio button is visible', () => {
197-
// Click on box1 to select it
203+
it('reset aspect ratio button appears only after a free corner resize', () => {
198204
cy.get('[data-testid="box1"]').click()
199205
cy.wait(200)
200206

201-
// Reset aspect ratio button should be visible
207+
// Fresh selection: AR unchanged, so the reset-AR button is absent (it's `v-if`d on
208+
// `hasAspectRatioChanged`).
209+
cy.get('#drag-control-container button[title="Reset aspect ratio"]').should('not.exist')
210+
211+
// Free-drag a corner handle to skew the aspect ratio. The corner handlers live on the
212+
// handle element (which re-renders as the box resizes), need `buttons: 1` on the
213+
// pointerdown to arm `currentDrag`, and a matching `pointerId`. Re-query the handle for
214+
// each event so a re-render between events can't leave us dispatching to a stale node,
215+
// and send two moves with different x/y ratios to guarantee the AR actually changes.
216+
const handle = '#drag-control-container div[style*="nwse-resize"]'
217+
cy.get(handle).first().then(($h) => {
218+
const r = $h[0].getBoundingClientRect()
219+
const cx = r.left + r.width / 2
220+
const cy2 = r.top + r.height / 2
221+
cy.get(handle).first().trigger('pointerdown', { button: 0, buttons: 1, pointerId: 1, clientX: cx, clientY: cy2, force: true })
222+
cy.get(handle).first().trigger('pointermove', { button: 0, buttons: 1, pointerId: 1, clientX: cx + 120, clientY: cy2 + 120, force: true })
223+
cy.get(handle).first().trigger('pointermove', { button: 0, buttons: 1, pointerId: 1, clientX: cx + 160, clientY: cy2 + 30, force: true })
224+
cy.get(handle).first().trigger('pointerup', { pointerId: 1, force: true })
225+
})
226+
cy.wait(200)
227+
228+
// AR now differs from the original → the reset button is shown.
202229
cy.get('#drag-control-container button[title="Reset aspect ratio"]').should('exist')
230+
231+
// Clicking it restores the original AR, so the button hides again.
232+
cy.get('#drag-control-container button[title="Reset aspect ratio"]').click()
233+
cy.wait(200)
234+
cy.get('#drag-control-container button[title="Reset aspect ratio"]').should('not.exist')
203235
})
204236
})
205237

@@ -251,17 +283,18 @@ context('v-drag', () => {
251283
cy.get('[data-testid="snap-mover"]')
252284
.trigger('pointerdown', { button: 0, pointerId: 1, buttons: 1, force: true })
253285

254-
// Move near the target - should trigger snap guides
286+
// Move near the target - should trigger snap guides. `pointerId` must match the
287+
// pointerdown or the body-drag handler drops the move.
255288
cy.document()
256-
.trigger('pointermove', { clientX: nearTargetX, clientY: nearTargetY, buttons: 1 })
289+
.trigger('pointermove', { clientX: nearTargetX, clientY: nearTargetY, buttons: 1, pointerId: 1 })
257290

258291
cy.wait(100)
259292

260293
// Snap guide lines should appear
261294
cy.get('.snap-guide').should('have.length.at.least', 1)
262295
cy.screenshot('snap-guides-visible')
263296

264-
cy.document().trigger('pointerup')
297+
cy.document().trigger('pointerup', { pointerId: 1 })
265298
cy.wait(100)
266299

267300
// Snap guides should disappear after drag ends
@@ -278,12 +311,15 @@ context('v-drag', () => {
278311
cy.get('[data-testid="snap-mover"]')
279312
.trigger('pointerdown', { button: 0, pointerId: 1, buttons: 1, force: true })
280313

281-
// Move near target with Meta key held - should NOT snap
314+
// Move near target with Meta key held - should NOT snap (Meta disables snapping).
315+
// `pointerId` must match the pointerdown so the move actually drives the drag —
316+
// otherwise this would pass vacuously (no drag at all → no guides).
282317
cy.document()
283318
.trigger('pointermove', {
284319
clientX: nearTargetX,
285320
clientY: nearTargetY,
286321
buttons: 1,
322+
pointerId: 1,
287323
metaKey: true,
288324
})
289325

@@ -293,7 +329,7 @@ context('v-drag', () => {
293329
cy.get('.snap-guide').should('not.exist')
294330
cy.screenshot('snap-meta-no-guides')
295331

296-
cy.document().trigger('pointerup')
332+
cy.document().trigger('pointerup', { pointerId: 1 })
297333
})
298334
})
299335

@@ -309,13 +345,13 @@ context('v-drag', () => {
309345
.trigger('pointerdown', { button: 0, pointerId: 1, buttons: 1, force: true })
310346

311347
cy.document()
312-
.trigger('pointermove', { clientX: centerX, clientY: centerY, buttons: 1 })
348+
.trigger('pointermove', { clientX: centerX, clientY: centerY, buttons: 1, pointerId: 1 })
313349

314350
cy.wait(100)
315351
cy.get('.snap-guide').should('have.length.at.least', 1)
316352
cy.screenshot('snap-to-slide-center')
317353

318-
cy.document().trigger('pointerup')
354+
cy.document().trigger('pointerup', { pointerId: 1 })
319355
})
320356
})
321357
})

0 commit comments

Comments
 (0)