Add camera frontend tests

This commit is contained in:
th committed 2026-06-07 23:58:05 +02:00
1 parent 23a66c6fdf
commit 3a93d6ea5d
1 file changed
+147
+147
View File
@@ -10199,6 +10199,153 @@ export function registerAllTests(): void {
})
})
suite('ui — camera framing', () => {
function resetPropertySectionPrefs() {
try {
localStorage.removeItem('animatr:propSections')
} catch {
/* noop */
}
}
function stubLaneRect(lane: HTMLElement, width = 1000): void {
const fakeRect = {
left: 0,
top: 0,
width,
height: 20,
right: width,
bottom: 20,
x: 0,
y: 0,
toJSON: () => ({}),
} as DOMRect
;(lane as unknown as { getBoundingClientRect: () => DOMRect }).getBoundingClientRect = () =>
fakeRect
}
test('stage camera button enables camera without resizing the editor stage', async () => {
const s = makeFreshStore()
s.scene.canvas.width = 640
s.scene.canvas.height = 360
const handle = mountComponent(CanvasStage, {})
try {
await nextTick()
const dims = handle.host.querySelector('.dims') as HTMLElement
const btn = handle.host.querySelector('.zoom-controls .camera-btn') as HTMLButtonElement
expect(dims).toBeTruthy()
expect(btn).toBeTruthy()
expect(dims.textContent?.trim()).toBe('640 × 360')
expect(s.scene.camera).toBe(undefined)
btn.click()
await nextTick()
expect(s.scene.camera?.enabled).toBe(true)
expect(s.selectedCamera).toBe(true)
expect(btn.classList.contains('active')).toBe(true)
expect(dims.textContent?.trim()).toBe('640 × 360')
expect(s.scene.canvas.width).toBe(640)
expect(s.scene.canvas.height).toBe(360)
btn.click()
await nextTick()
expect(s.scene.camera?.enabled).toBe(false)
expect(dims.textContent?.trim()).toBe('640 × 360')
} finally {
handle.unmount()
}
})
test('properties panel edits the selected camera frame, not scene canvas size', async () => {
resetPropertySectionPrefs()
const s = makeFreshStore()
s.scene.canvas.width = 800
s.scene.canvas.height = 450
s.enableCamera()
s.selectCamera(true)
const handle = mountComponent(PropertiesPanel, {})
try {
await nextTick()
const banner = handle.host.querySelector('.multi-banner') as HTMLElement
expect(banner.textContent).toContain(i18nT('properties.camera.banner'))
const inputs = handle.host.querySelectorAll<HTMLInputElement>(
'.prop-group input[type="number"]',
)
expect(inputs.length).toBe(4)
const [xInput, yInput, widthInput, heightInput] = Array.from(inputs)
expect(Number(widthInput.value)).toBe(800)
expect(Number(heightInput.value)).toBe(450)
xInput.value = '24'
xInput.dispatchEvent(new Event('input', { bubbles: true }))
widthInput.value = '320'
widthInput.dispatchEvent(new Event('input', { bubbles: true }))
await nextTick()
expect(s.scene.camera?.keyframes.length).toBe(1)
expect(s.scene.camera?.keyframes[0].props.x).toBe(24)
expect(s.scene.camera?.keyframes[0].props.width).toBe(320)
expect(s.scene.canvas.width).toBe(800)
expect(s.scene.canvas.height).toBe(450)
void yInput
} finally {
handle.unmount()
}
})
test('timeline camera row selects, hides, locks, and adds camera keyframes', async () => {
const s = makeFreshStore()
s.setDuration(10)
s.enableCamera()
s.selectCamera(false)
const handle = mountComponent(Timeline, {})
try {
await nextTick()
const trackName = handle.host.querySelector('.camera-track .track-name') as HTMLElement
const eye = handle.host.querySelector('.camera-track .eye-btn') as HTMLButtonElement
const lock = handle.host.querySelector('.camera-track .lock-btn') as HTMLButtonElement
const lane = handle.host.querySelector('.camera-track .camera-lane') as HTMLElement
expect(trackName).toBeTruthy()
expect(eye).toBeTruthy()
expect(lock).toBeTruthy()
expect(lane).toBeTruthy()
trackName.click()
await nextTick()
expect(s.selectedCamera).toBe(true)
eye.click()
await nextTick()
expect(s.scene.camera?.overlayVisible).toBe(false)
expect(eye.classList.contains('hidden')).toBe(true)
lock.click()
await nextTick()
expect(s.scene.camera?.locked).toBe(true)
expect(lock.classList.contains('locked')).toBe(true)
stubLaneRect(lane)
lane.dispatchEvent(
new MouseEvent('dblclick', { bubbles: true, cancelable: true, clientX: 500 }),
)
await nextTick()
expect(s.scene.camera?.keyframes.length).toBe(0)
lock.click()
await nextTick()
lane.dispatchEvent(
new MouseEvent('dblclick', { bubbles: true, cancelable: true, clientX: 500 }),
)
await nextTick()
expect(s.scene.camera?.keyframes.length).toBe(1)
expect(Math.abs((s.scene.camera?.keyframes[0].time ?? 0) - 5) < 0.1).toBe(true)
expect(Math.abs(s.playhead - 5) < 0.1).toBe(true)
} finally {
handle.unmount()
}
})
})
suite('ui — CanvasStage centre crosshair (Konva)', () => {
// Verify the lines actually render at the correct coordinates in
// Konva when the toggle is on. Requires a proper VueKonva mount.