mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Summary Simplify default scripts. Filtering is still available to users, we can revisit tagging or grouping later. This fixes the issue where we had tests that were in the codebase but never run because they weren't under `/src/components` Also deletes the duplicate litegraph tests and their associated vitest config file. ## Changes - **What**: Test cleanup ## Review Focus ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5888-Tests-Vitest-configuration-cleanup-2806d73d36508197b800f68f0b028279) by [Unito](https://www.unito.io)
1221 lines
38 KiB
TypeScript
1221 lines
38 KiB
TypeScript
/**
|
|
* Test-Driven Design (TDD) tests for device detection functionality.
|
|
*
|
|
* These tests describe the expected behavior for device detection between
|
|
* mouse and trackpad inputs using an efficient timestamp-based approach.
|
|
*
|
|
* Design Philosophy:
|
|
* - Uses timestamps (performance.now()) instead of creating timers for every event
|
|
* - Creates at most ONE timer (for Linux buffer timeout), not one per wheel event
|
|
* - Handles potentially thousands of wheel events per second efficiently
|
|
*
|
|
* Expected new properties on CanvasPointer:
|
|
* - detectedDevice: 'mouse' | 'trackpad'
|
|
* - lastWheelEventTime: number // timestamp, not the event itself
|
|
* - bufferedLinuxEvent: WheelEvent | undefined
|
|
* - bufferedLinuxEventTime: number
|
|
* - linuxBufferTimeoutId: number | undefined // single timer handle
|
|
*
|
|
* Expected new methods on CanvasPointer:
|
|
* - detectDevice(event: WheelEvent): void
|
|
* - clearLinuxBuffer(): void
|
|
*
|
|
* Performance: This design can handle 10,000+ events without creating any timers
|
|
* (except one for Linux detection), ensuring smooth scrolling performance.
|
|
*
|
|
* @vitest-environment jsdom
|
|
*/
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { CanvasPointer } from '@/lib/litegraph/src/CanvasPointer'
|
|
|
|
describe('CanvasPointer Device Detection - Efficient Timestamp-Based TDD Tests', () => {
|
|
let element: HTMLDivElement
|
|
let pointer: CanvasPointer
|
|
|
|
beforeEach(() => {
|
|
element = document.createElement('div')
|
|
pointer = new CanvasPointer(element)
|
|
// Mock performance.now() for timestamp-based testing
|
|
vi.spyOn(performance, 'now').mockReturnValue(0)
|
|
vi.spyOn(global, 'setTimeout')
|
|
vi.spyOn(global, 'clearTimeout')
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
vi.clearAllTimers()
|
|
})
|
|
|
|
describe('Initial State', () => {
|
|
it('should start in mouse detected mode immediately after loading', () => {
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should have no last wheel event time immediately after loading', () => {
|
|
expect(pointer.lastWheelEventTime).toBe(0)
|
|
expect(pointer.hasReceivedWheelEvent).toBe(false)
|
|
})
|
|
|
|
it('should have no buffered Linux event immediately after loading', () => {
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
expect(pointer.bufferedLinuxEventTime).toBe(0)
|
|
expect(pointer.linuxBufferTimeoutId).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('First Event Detection', () => {
|
|
describe('switching to trackpad on first event', () => {
|
|
it('should switch to trackpad if first event is pinch-to-zoom with deltaY < 10', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 9.5,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
expect(pointer.lastWheelEventTime).toBe(0) // Records current time
|
|
})
|
|
|
|
it('should switch to trackpad if first event is pinch-to-zoom with deltaY = 9.999', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 9.999,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT switch to trackpad if first event is pinch-to-zoom with deltaY = 10', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should switch to trackpad if first event is two-finger panning with integer values', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 5,
|
|
deltaX: -3
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should switch to trackpad if first event is two-finger panning with ctrlKey true', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 7,
|
|
deltaX: 4
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should switch to trackpad if first event is negative pinch-to-zoom with deltaY > -10', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: -9.5,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
})
|
|
|
|
describe('remaining in mouse mode on first event', () => {
|
|
it('should remain in mouse mode if first event is pinch-to-zoom with deltaY >= 10', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 10.1,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should remain in mouse mode if first event is mouse wheel with deltaY = 120', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 120,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should remain in mouse mode if first event has only deltaY (no deltaX)', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 30,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Mode Switching from Mouse to Trackpad', () => {
|
|
beforeEach(() => {
|
|
// Ensure we start in mouse mode
|
|
pointer.detectedDevice = 'mouse'
|
|
// Simulate a previous event to establish timing
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
})
|
|
|
|
it('should switch to trackpad on two-finger panning with non-zero deltaX and deltaY', () => {
|
|
// Simulate 500ms has passed since last event
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 15,
|
|
deltaX: 8
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT switch to trackpad on two-finger panning with zero deltaX', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 15,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should NOT switch to trackpad on two-finger panning with zero deltaY', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 0,
|
|
deltaX: 15
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should switch to trackpad on pinch-to-zoom with deltaY < 10', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 9.99,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should switch to trackpad on pinch-to-zoom with deltaY = -5.5', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: -5.5,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT switch to trackpad on pinch-to-zoom with deltaY = 10', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should NOT switch to trackpad on pinch-to-zoom with deltaY = -10', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: -10,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
})
|
|
|
|
describe('Mode Switching from Trackpad to Mouse', () => {
|
|
beforeEach(() => {
|
|
// Set to trackpad mode
|
|
pointer.detectedDevice = 'trackpad'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
})
|
|
|
|
it('should switch to mouse on clear mouse wheel event with deltaY > 80', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 80.1,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should switch to mouse on clear mouse wheel event with deltaY = 120', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 120,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should switch to mouse on clear mouse wheel event with negative deltaY < -80', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: -90,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should NOT switch to mouse with deltaY = 80', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 80,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT switch to mouse with deltaY = -80', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: -80,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT switch to mouse with deltaY = 79.999', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 79.999,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
})
|
|
|
|
describe('500ms Cooldown Period', () => {
|
|
it('should NOT allow switching from mouse to trackpad within 500ms', () => {
|
|
pointer.detectedDevice = 'mouse'
|
|
|
|
// First event at time 0
|
|
vi.spyOn(performance, 'now').mockReturnValue(0)
|
|
const event1 = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 60,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
expect(pointer.lastWheelEventTime).toBe(0)
|
|
|
|
// Try to switch after 499ms - should fail
|
|
vi.spyOn(performance, 'now').mockReturnValue(499)
|
|
const event2 = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 5,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should allow switching from mouse to trackpad after 500ms', () => {
|
|
pointer.detectedDevice = 'mouse'
|
|
|
|
// First event at time 0
|
|
vi.spyOn(performance, 'now').mockReturnValue(0)
|
|
const event1 = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 60,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Try to switch after 500ms - should succeed
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
const event2 = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 5,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT allow switching from trackpad to mouse within 500ms', () => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
|
|
// First event at time 0
|
|
vi.spyOn(performance, 'now').mockReturnValue(0)
|
|
const event1 = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 5,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Try to switch after 400ms - should fail
|
|
vi.spyOn(performance, 'now').mockReturnValue(400)
|
|
const event2 = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 120,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should maintain cooldown even with multiple events', () => {
|
|
pointer.detectedDevice = 'mouse'
|
|
|
|
// Series of events that would normally trigger trackpad
|
|
const trackpadEvents = [
|
|
{ deltaY: 5, deltaX: 3 },
|
|
{ deltaY: -7, deltaX: 2 },
|
|
{ deltaY: 8, deltaX: -4 }
|
|
]
|
|
|
|
// Send first mouse event at time 0
|
|
vi.spyOn(performance, 'now').mockReturnValue(0)
|
|
pointer.isTrackpadGesture(
|
|
new WheelEvent('wheel', { deltaY: 60, deltaX: 0 })
|
|
)
|
|
|
|
// Send trackpad events within 500ms window
|
|
trackpadEvents.forEach((eventData, index) => {
|
|
vi.spyOn(performance, 'now').mockReturnValue((index + 1) * 100) // 100ms, 200ms, 300ms
|
|
const event = new WheelEvent('wheel', eventData)
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse') // Should remain mouse
|
|
})
|
|
|
|
// After 500ms from last event (300ms + 500ms = 800ms), should be able to switch
|
|
vi.spyOn(performance, 'now').mockReturnValue(800)
|
|
const switchEvent = new WheelEvent('wheel', { deltaY: 5, deltaX: 3 })
|
|
pointer.isTrackpadGesture(switchEvent)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
})
|
|
|
|
describe('Linux Wheel Event Buffering', () => {
|
|
beforeEach(() => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
it('should buffer possible Linux wheel event and create single timeout', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
vi.spyOn(performance, 'now').mockReturnValue(500) // Allow mode switching
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.bufferedLinuxEvent).toBe(event)
|
|
expect(pointer.bufferedLinuxEventTime).toBe(500)
|
|
expect(pointer.detectedDevice).toBe('trackpad') // No immediate switch
|
|
|
|
// Should create exactly ONE timeout for buffer clearing
|
|
expect(setTimeoutSpy).toHaveBeenCalledTimes(1)
|
|
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 10)
|
|
})
|
|
|
|
it('should reuse timer when buffering new Linux event', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout')
|
|
|
|
// First Linux event
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
const event1 = new WheelEvent('wheel', { deltaY: 15, deltaX: 0 })
|
|
pointer.isTrackpadGesture(event1)
|
|
const firstTimeoutId = pointer.linuxBufferTimeoutId
|
|
|
|
// Second Linux event before timeout
|
|
vi.spyOn(performance, 'now').mockReturnValue(505)
|
|
const event2 = new WheelEvent('wheel', { deltaY: 10, deltaX: 0 })
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
// Should clear the first timeout and create a new one
|
|
expect(clearTimeoutSpy).toHaveBeenCalledWith(firstTimeoutId)
|
|
expect(setTimeoutSpy).toHaveBeenCalledTimes(2)
|
|
expect(pointer.bufferedLinuxEvent).toBe(event2)
|
|
})
|
|
|
|
it('should buffer negative Linux wheel values', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: -10,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.bufferedLinuxEvent).toBe(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
expect(setTimeoutSpy).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('should NOT buffer event with deltaY < 10', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 9,
|
|
deltaX: 0
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
expect(setTimeoutSpy).not.toHaveBeenCalled() // No timer created
|
|
})
|
|
|
|
it('should NOT buffer event with non-zero deltaX', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 1
|
|
})
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
expect(setTimeoutSpy).not.toHaveBeenCalled() // No timer created
|
|
})
|
|
|
|
it('should switch to mouse if follow-up event has same deltaY within 10ms', () => {
|
|
const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout')
|
|
|
|
// First event - buffered at time 500
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
expect(pointer.bufferedLinuxEvent).toBe(event1)
|
|
const timeoutId = pointer.linuxBufferTimeoutId
|
|
|
|
// Follow-up within 10ms with same deltaY
|
|
vi.spyOn(performance, 'now').mockReturnValue(509)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
expect(clearTimeoutSpy).toHaveBeenCalledWith(timeoutId) // Timer cleared
|
|
})
|
|
|
|
it('should switch to mouse if follow-up event is divisible by original deltaY within 10ms', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First event - buffered
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up within 10ms with deltaY divisible by 10
|
|
vi.spyOn(performance, 'now').mockReturnValue(505)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 30,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
})
|
|
|
|
it('should switch to mouse if follow-up deltaY is divisible by original (base 15)', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First event with base 15
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 15,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up with multiple of 15
|
|
vi.spyOn(performance, 'now').mockReturnValue(508)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 45,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should switch to mouse if original deltaY is divisible by follow-up', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First event with larger value
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 30,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up with divisor
|
|
vi.spyOn(performance, 'now').mockReturnValue(507)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should NOT switch to mouse if follow-up is not divisible', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First event
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up with non-divisible value
|
|
vi.spyOn(performance, 'now').mockReturnValue(505)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 13,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should NOT switch to mouse if follow-up comes after 10ms', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First event
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up after 10ms
|
|
vi.spyOn(performance, 'now').mockReturnValue(511)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should call clearLinuxBuffer method after 10ms timeout', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
vi.useFakeTimers() // Use fake timers just for this test
|
|
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.bufferedLinuxEvent).toBe(event)
|
|
|
|
// Simulate timeout firing
|
|
vi.runOnlyPendingTimers()
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
expect(pointer.linuxBufferTimeoutId).toBeUndefined()
|
|
|
|
vi.useRealTimers() // Restore for other tests
|
|
})
|
|
|
|
it('should handle negative Linux wheel values', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First negative event
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: -15,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up with same negative value
|
|
vi.spyOn(performance, 'now').mockReturnValue(505)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: -15,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should handle mixed sign Linux wheel values if divisible', () => {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// First positive event
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Follow-up with negative multiple
|
|
vi.spyOn(performance, 'now').mockReturnValue(505)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: -30,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should allow buffering during 500ms cooldown as exception', () => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
|
|
// Send initial event at time 0
|
|
vi.spyOn(performance, 'now').mockReturnValue(0)
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 5,
|
|
deltaX: 2
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Within cooldown at 100ms, but Linux buffering should still work
|
|
vi.spyOn(performance, 'now').mockReturnValue(100)
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.bufferedLinuxEvent).toBe(event2)
|
|
|
|
// Follow-up for Linux detection at 105ms
|
|
vi.spyOn(performance, 'now').mockReturnValue(105)
|
|
const event3 = new WheelEvent('wheel', {
|
|
deltaY: 20,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event3)
|
|
|
|
// Should switch despite being within original 500ms window
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
})
|
|
|
|
describe('Performance and Efficiency', () => {
|
|
it('should not create timers for regular wheel events', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
pointer.detectedDevice = 'mouse'
|
|
|
|
// Simulate rapid scrolling without Linux-like patterns
|
|
for (let i = 0; i < 100; i++) {
|
|
vi.spyOn(performance, 'now').mockReturnValue(i * 16) // 60fps scrolling
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 120, // Clear mouse wheel value
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event)
|
|
}
|
|
|
|
// Should create NO timers for regular mouse wheel events
|
|
expect(setTimeoutSpy).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('should create at most one timer for Linux detection', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
pointer.detectedDevice = 'trackpad'
|
|
|
|
// Send a Linux-like event that requires buffering
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
const event1 = new WheelEvent('wheel', { deltaY: 10, deltaX: 0 })
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Should create exactly one timer
|
|
expect(setTimeoutSpy).toHaveBeenCalledTimes(1)
|
|
|
|
// Send more regular events
|
|
for (let i = 1; i <= 10; i++) {
|
|
vi.spyOn(performance, 'now').mockReturnValue(500 + i * 100)
|
|
const event = new WheelEvent('wheel', { deltaY: 5, deltaX: 3 })
|
|
pointer.isTrackpadGesture(event)
|
|
}
|
|
|
|
// Still only one timer (the Linux buffer timeout)
|
|
expect(setTimeoutSpy).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('should handle thousands of events efficiently', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
let maxTimersCreated = 0
|
|
|
|
// Simulate extended scrolling session with mixed inputs
|
|
for (let i = 0; i < 10000; i++) {
|
|
vi.spyOn(performance, 'now').mockReturnValue(i)
|
|
|
|
// Mix of different event types
|
|
const eventType = i % 3
|
|
let event: WheelEvent
|
|
|
|
if (eventType === 0) {
|
|
// Mouse wheel
|
|
event = new WheelEvent('wheel', {
|
|
deltaY: 120,
|
|
deltaX: 0
|
|
})
|
|
} else if (eventType === 1) {
|
|
// Trackpad two-finger
|
|
event = new WheelEvent('wheel', {
|
|
deltaY: Math.floor(Math.random() * 20),
|
|
deltaX: Math.floor(Math.random() * 20)
|
|
})
|
|
} else {
|
|
// Pinch to zoom
|
|
event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: Math.random() * 10,
|
|
deltaX: 0
|
|
})
|
|
}
|
|
|
|
pointer.isTrackpadGesture(event)
|
|
|
|
// Track maximum timers created
|
|
maxTimersCreated = Math.max(
|
|
maxTimersCreated,
|
|
setTimeoutSpy.mock.calls.length
|
|
)
|
|
}
|
|
|
|
// Should create at most a few timers for Linux detection, not thousands
|
|
expect(maxTimersCreated).toBeLessThan(10)
|
|
})
|
|
|
|
it('should use minimal memory with timestamp approach', () => {
|
|
// This test verifies the implementation uses timestamps, not stored events
|
|
const initialProps = Object.keys(pointer).length
|
|
|
|
// Process many events
|
|
for (let i = 0; i < 1000; i++) {
|
|
vi.spyOn(performance, 'now').mockReturnValue(i * 10)
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 60 + Math.random() * 100,
|
|
deltaX: Math.random() * 50
|
|
})
|
|
pointer.isTrackpadGesture(event)
|
|
}
|
|
|
|
// Should only have a few properties for tracking state
|
|
const finalProps = Object.keys(pointer).length
|
|
expect(finalProps - initialProps).toBeLessThanOrEqual(5) // Only added minimal tracking properties
|
|
|
|
// Verify we store timestamps, not events (except Linux buffer)
|
|
expect(typeof pointer.lastWheelEventTime).toBe('number')
|
|
expect(typeof pointer.bufferedLinuxEventTime).toBe('number')
|
|
})
|
|
|
|
it('should handle rapid mode switching efficiently', () => {
|
|
const setTimeoutSpy = vi.spyOn(global, 'setTimeout')
|
|
|
|
// Rapidly switch between mouse and trackpad modes
|
|
for (let i = 0; i < 100; i++) {
|
|
const baseTime = i * 600 // Every 600ms to allow switching
|
|
|
|
// Mouse event
|
|
vi.spyOn(performance, 'now').mockReturnValue(baseTime)
|
|
pointer.isTrackpadGesture(
|
|
new WheelEvent('wheel', { deltaY: 120, deltaX: 0 })
|
|
)
|
|
|
|
// Trackpad event
|
|
vi.spyOn(performance, 'now').mockReturnValue(baseTime + 500)
|
|
pointer.isTrackpadGesture(
|
|
new WheelEvent('wheel', { deltaY: 5, deltaX: 3 })
|
|
)
|
|
}
|
|
|
|
// Should create minimal or no timers despite 200 events
|
|
expect(setTimeoutSpy.mock.calls.length).toBeLessThan(5)
|
|
})
|
|
})
|
|
|
|
describe('Edge Cases and Complex Scenarios', () => {
|
|
it('should handle float values correctly for mouse detection', () => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// Float value <= 80 should NOT switch from trackpad
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 60.5,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
|
|
// Float value > 80 should switch to mouse
|
|
vi.spyOn(performance, 'now').mockReturnValue(1000) // 500ms later
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 80.1,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should handle integer values correctly for trackpad detection', () => {
|
|
pointer.detectedDevice = 'mouse'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// Integer values in two-finger panning
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 5,
|
|
deltaX: 3
|
|
})
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should correctly identify pinch-to-zoom with ctrlKey', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 250.5,
|
|
deltaX: 0
|
|
})
|
|
|
|
// This is pinch-to-zoom but deltaY > 10, so stays as mouse on first event
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should handle rapid event sequences', () => {
|
|
pointer.detectedDevice = 'mouse'
|
|
pointer.lastWheelEventTime = 0
|
|
|
|
// Simulate rapid scrolling
|
|
for (let i = 0; i < 10; i++) {
|
|
vi.spyOn(performance, 'now').mockReturnValue(i * 30) // 30ms between events
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 60,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
}
|
|
})
|
|
|
|
it('should handle boundary values for pinch-to-zoom detection', () => {
|
|
// Test deltaY = 10 (boundary)
|
|
const event1 = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
|
|
// Reset and test deltaY = 9.999999
|
|
pointer = new CanvasPointer(element)
|
|
const event2 = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 9.999999,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
|
|
it('should handle boundary values for mouse wheel detection', () => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// Test deltaY = 80 (boundary)
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 80,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
|
|
// Test deltaY = 80.000001
|
|
vi.spyOn(performance, 'now').mockReturnValue(1000) // 500ms later
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 80.000001,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should handle Linux wheel detection with various multiples', () => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// Test with base 10 and multiple 50
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
vi.spyOn(performance, 'now').mockReturnValue(505) // 5ms later
|
|
const event2 = new WheelEvent('wheel', {
|
|
deltaY: 50,
|
|
deltaX: 0
|
|
})
|
|
pointer.isTrackpadGesture(event2)
|
|
expect(pointer.detectedDevice).toBe('mouse')
|
|
})
|
|
|
|
it('should not confuse trackpad integers with Linux wheel', () => {
|
|
pointer.detectedDevice = 'trackpad'
|
|
pointer.lastWheelEventTime = 0
|
|
pointer.hasReceivedWheelEvent = true
|
|
vi.spyOn(performance, 'now').mockReturnValue(500)
|
|
|
|
// Trackpad two-finger panning with integers
|
|
const event1 = new WheelEvent('wheel', {
|
|
deltaY: 10,
|
|
deltaX: 5 // Non-zero deltaX
|
|
})
|
|
pointer.isTrackpadGesture(event1)
|
|
|
|
// Should not buffer this as Linux event
|
|
expect(pointer.bufferedLinuxEvent).toBeUndefined()
|
|
expect(pointer.detectedDevice).toBe('trackpad')
|
|
})
|
|
})
|
|
|
|
describe('Input Type Validation', () => {
|
|
describe('Two-finger panning validation', () => {
|
|
it('should accept integer deltaY values', () => {
|
|
const values = [0, 1, -1, 100, -100, 999, -999]
|
|
values.forEach((deltaY) => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY,
|
|
deltaX: 5
|
|
})
|
|
expect(Number.isInteger(event.deltaY)).toBe(true)
|
|
})
|
|
})
|
|
|
|
it('should accept integer deltaX values', () => {
|
|
const values = [0, 1, -1, 100, -100, 999, -999]
|
|
values.forEach((deltaX) => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: false,
|
|
deltaY: 5,
|
|
deltaX
|
|
})
|
|
expect(Number.isInteger(event.deltaX)).toBe(true)
|
|
})
|
|
})
|
|
|
|
it('should handle ctrlKey true or false', () => {
|
|
;[true, false].forEach((ctrlKey) => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey,
|
|
deltaY: 5,
|
|
deltaX: 3
|
|
})
|
|
expect(typeof event.ctrlKey).toBe('boolean')
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Pinch-to-zoom validation', () => {
|
|
it('should always have ctrlKey true', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 5.5,
|
|
deltaX: 0
|
|
})
|
|
expect(event.ctrlKey).toBe(true)
|
|
})
|
|
|
|
it('should accept float deltaY values in range -1000 to 1000', () => {
|
|
const values = [-1000, -999.99, -0.1, 0, 0.1, 999.99, 1000]
|
|
values.forEach((deltaY) => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY,
|
|
deltaX: 0
|
|
})
|
|
expect(event.deltaY).toBeGreaterThanOrEqual(-1000)
|
|
expect(event.deltaY).toBeLessThanOrEqual(1000)
|
|
})
|
|
})
|
|
|
|
it('should always have deltaX = 0', () => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: 5.5,
|
|
deltaX: 0
|
|
})
|
|
expect(event.deltaX).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('Mouse input validation', () => {
|
|
it('should accept float deltaX values in range -1000 to 1000', () => {
|
|
const values = [-1000, -500.5, 0, 500.5, 1000]
|
|
values.forEach((deltaX) => {
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY: 120,
|
|
deltaX
|
|
})
|
|
expect(event.deltaX).toBeGreaterThanOrEqual(-1000)
|
|
expect(event.deltaX).toBeLessThanOrEqual(1000)
|
|
})
|
|
})
|
|
|
|
it('should have deltaY >= 60 for Windows/Mac mouse', () => {
|
|
const values = [60, 60.1, 80, 120, 240]
|
|
values.forEach((deltaY) => {
|
|
const event = new WheelEvent('wheel', {
|
|
deltaY,
|
|
deltaX: 0
|
|
})
|
|
expect(event.deltaY).toBeGreaterThanOrEqual(60)
|
|
})
|
|
})
|
|
|
|
it('should have integer deltaY as multiples of 10 or 15 for Linux', () => {
|
|
// Base 10 multiples
|
|
const base10Values = [10, 20, 30, 40, 50, -10, -20, -30]
|
|
base10Values.forEach((deltaY) => {
|
|
expect(Number.isInteger(deltaY)).toBe(true)
|
|
// Use Math.abs to avoid JavaScript's -0 vs 0 issue with modulo on negative numbers
|
|
expect(Math.abs(deltaY) % 10).toBe(0)
|
|
})
|
|
|
|
// Base 15 multiples
|
|
const base15Values = [15, 30, 45, 60, -15, -30, -45]
|
|
base15Values.forEach((deltaY) => {
|
|
expect(Number.isInteger(deltaY)).toBe(true)
|
|
// Use Math.abs to avoid JavaScript's -0 vs 0 issue with modulo on negative numbers
|
|
expect(Math.abs(deltaY) % 15).toBe(0)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Float vs Integer understanding', () => {
|
|
it('should recognize that integers are valid float values', () => {
|
|
const integerValues = [0, 1, -1, 10, -10, 100]
|
|
integerValues.forEach((value) => {
|
|
expect(Number.isInteger(value)).toBe(true)
|
|
expect(typeof value === 'number').toBe(true) // Valid as float
|
|
})
|
|
})
|
|
|
|
it('should recognize that decimals are NOT valid integer values', () => {
|
|
const decimalValues = [0.1, -0.1, 10.5, -10.5, 99.99]
|
|
decimalValues.forEach((value) => {
|
|
expect(Number.isInteger(value)).toBe(false)
|
|
expect(typeof value === 'number').toBe(true) // Still valid as float
|
|
})
|
|
})
|
|
|
|
it('should correctly validate pinch-to-zoom deltaY as float', () => {
|
|
// These are all valid float values for pinch-to-zoom
|
|
const validValues = [0, 1, -1, 0.5, -0.5, 999, -999, 500.123]
|
|
validValues.forEach((value) => {
|
|
const event = new WheelEvent('wheel', {
|
|
ctrlKey: true,
|
|
deltaY: value,
|
|
deltaX: 0
|
|
})
|
|
expect(typeof event.deltaY === 'number').toBe(true)
|
|
expect(event.deltaY >= -1000 && event.deltaY <= 1000).toBe(true)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|