Add camera frontend tests
This commit is contained in:
1 parent
23a66c6fdf
commit
3a93d6ea5d
1 file changed
+147
@@ -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)', () => {
|
suite('ui — CanvasStage centre crosshair (Konva)', () => {
|
||||||
// Verify the lines actually render at the correct coordinates in
|
// Verify the lines actually render at the correct coordinates in
|
||||||
// Konva when the toggle is on. Requires a proper VueKonva mount.
|
// Konva when the toggle is on. Requires a proper VueKonva mount.
|
||||||
|
|||||||
Reference in new issue
Block a user