test(10-10): promote OsDragOverlay stubs to 8 RED failing tests
- Replace 7 it.todo stubs with 8 real tests covering UX-09 contract - Tests dispatch DragEvent/Event with synthetic dataTransfer on window - Covers: hidden by default, Files type guard, depth counter, nested enter/leave, drop emit, drop reset, z-[9998] class on overlay element - All 8 tests RED (OsDragOverlay.vue does not yet exist)
This commit is contained in:
@@ -1,11 +1,158 @@
|
|||||||
import { describe, it } from 'vitest'
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import OsDragOverlay from '../OsDragOverlay.vue'
|
||||||
|
|
||||||
|
function makeDragEvent(type, types = ['Files'], files = []) {
|
||||||
|
const event = new Event(type, { bubbles: true, cancelable: true })
|
||||||
|
Object.defineProperty(event, 'dataTransfer', {
|
||||||
|
value: { types, files, preventDefault: vi.fn() },
|
||||||
|
writable: false,
|
||||||
|
})
|
||||||
|
event.preventDefault = vi.fn()
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
describe('UX-09: OsDragOverlay shows when OS files are dragged over the window', () => {
|
describe('UX-09: OsDragOverlay shows when OS files are dragged over the window', () => {
|
||||||
it.todo('overlay hidden by default (dragDepth=0)')
|
it('overlay hidden by default (dragDepth=0)', () => {
|
||||||
it.todo('dragenter with dataTransfer.types including "Files" shows overlay')
|
const w = mount(OsDragOverlay, {
|
||||||
it.todo('dragenter without "Files" type is ignored (in-app element drag)')
|
attachTo: document.body,
|
||||||
it.todo('dragleave decrements depth; overlay hides when depth reaches 0')
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
it.todo('drop event emits files-dropped with the file list')
|
})
|
||||||
it.todo('drop resets dragDepth to 0 and hides overlay')
|
expect(w.vm.showOverlay).toBe(false)
|
||||||
it.todo('overlay is teleported to body with z-[9998] (below toast z-[9999])')
|
expect(w.vm.dragDepth).toBe(0)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('dragenter with dataTransfer.types including "Files" shows overlay (dragDepth=1)', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
|
})
|
||||||
|
const event = makeDragEvent('dragenter', ['Files'])
|
||||||
|
window.dispatchEvent(event)
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.showOverlay).toBe(true)
|
||||||
|
expect(w.vm.dragDepth).toBe(1)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('dragenter without "Files" type is ignored (in-app element drag)', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
|
})
|
||||||
|
const event = makeDragEvent('dragenter', ['text/plain'])
|
||||||
|
window.dispatchEvent(event)
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.showOverlay).toBe(false)
|
||||||
|
expect(w.vm.dragDepth).toBe(0)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('dragleave decrements depth; overlay hides when depth reaches 0', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
|
})
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(1)
|
||||||
|
expect(w.vm.showOverlay).toBe(true)
|
||||||
|
|
||||||
|
window.dispatchEvent(new Event('dragleave'))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(0)
|
||||||
|
expect(w.vm.showOverlay).toBe(false)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('nested dragenter+dragleave maintains overlay until depth=0', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
|
})
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(2)
|
||||||
|
expect(w.vm.showOverlay).toBe(true)
|
||||||
|
|
||||||
|
window.dispatchEvent(new Event('dragleave'))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(1)
|
||||||
|
expect(w.vm.showOverlay).toBe(true)
|
||||||
|
|
||||||
|
window.dispatchEvent(new Event('dragleave'))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(0)
|
||||||
|
expect(w.vm.showOverlay).toBe(false)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('drop event emits files-dropped with the file list', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
|
})
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
|
||||||
|
const file = new File(['x'], 'a.txt', { type: 'text/plain' })
|
||||||
|
const dropEvent = new Event('drop', { bubbles: true, cancelable: true })
|
||||||
|
Object.defineProperty(dropEvent, 'dataTransfer', {
|
||||||
|
value: { files: [file] },
|
||||||
|
writable: false,
|
||||||
|
})
|
||||||
|
dropEvent.preventDefault = vi.fn()
|
||||||
|
window.dispatchEvent(dropEvent)
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
|
||||||
|
const emitted = w.emitted('files-dropped')
|
||||||
|
expect(emitted).toBeTruthy()
|
||||||
|
expect(emitted[0][0]).toHaveLength(1)
|
||||||
|
expect(emitted[0][0][0]).toBeInstanceOf(File)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('drop resets dragDepth to 0 and hides overlay', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { stubs: { Teleport: true, AppIcon: true } },
|
||||||
|
})
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(3)
|
||||||
|
|
||||||
|
const dropEvent = new Event('drop', { bubbles: true, cancelable: true })
|
||||||
|
Object.defineProperty(dropEvent, 'dataTransfer', {
|
||||||
|
value: { files: [] },
|
||||||
|
writable: false,
|
||||||
|
})
|
||||||
|
dropEvent.preventDefault = vi.fn()
|
||||||
|
window.dispatchEvent(dropEvent)
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
|
||||||
|
expect(w.vm.dragDepth).toBe(0)
|
||||||
|
expect(w.vm.showOverlay).toBe(false)
|
||||||
|
|
||||||
|
window.dispatchEvent(new Event('dragleave'))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
expect(w.vm.dragDepth).toBe(0)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('overlay is teleported to body with z-[9998] (below toast z-[9999])', async () => {
|
||||||
|
const w = mount(OsDragOverlay, {
|
||||||
|
attachTo: document.body,
|
||||||
|
})
|
||||||
|
window.dispatchEvent(makeDragEvent('dragenter', ['Files']))
|
||||||
|
await w.vm.$nextTick()
|
||||||
|
|
||||||
|
const overlay = document.querySelector('[data-test="os-drag-overlay"]')
|
||||||
|
expect(overlay).toBeTruthy()
|
||||||
|
expect(overlay.classList.contains('z-[9998]')).toBe(true)
|
||||||
|
w.unmount()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user