Files
frontend-miniapp/tests/unit/GuideAutoSwitchStateMachine.spec.ts
lyf 9ea1bfab71
Some checks failed
CI / verify (push) Has been cancelled
同步 sgs-frontend-mobile 源码
2026-07-27 11:26:01 +08:00

236 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
GuideAutoSwitchStateMachine,
type GuideAutoSwitchDirection,
type GuideAutoSwitchInputSource
} from '@/components/map/guideAutoSwitchStateMachine'
const createMachine = () => {
const requests: GuideAutoSwitchDirection[] = []
const machine = new GuideAutoSwitchStateMachine({
onSwitchRequested: ({ direction }) => requests.push(direction)
})
return { machine, requests }
}
beforeEach(() => {
vi.useFakeTimers()
vi.setSystemTime(0)
})
afterEach(() => {
vi.useRealTimers()
})
describe('建筑外观与馆内楼层自动切换状态机', () => {
it('连续放大 14.9% 不进入,达到 15% 后进入', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'gesture')
machine.updateDistance(85.1, { source: 'gesture' })
vi.advanceTimersByTime(400)
expect(requests).toEqual([])
machine.updateDistance(85, { source: 'gesture' })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
})
it('可将进入阈值提高到 32%,为近外观阶段预留一次缩放', () => {
const requests: GuideAutoSwitchDirection[] = []
const machine = new GuideAutoSwitchStateMachine({
enterRatio: 0.32,
onSwitchRequested: ({ direction }) => requests.push(direction)
})
machine.beginInput(100, 'button')
machine.updateDistance(68.1, { source: 'button' })
vi.advanceTimersByTime(400)
expect(requests).toEqual([])
machine.updateDistance(68, { source: 'button' })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
})
it('配置固定外观阈值后,慢速连续缩放也按默认外观尺度进入室内', () => {
const requests: GuideAutoSwitchDirection[] = []
const machine = new GuideAutoSwitchStateMachine({
overviewEntryDistance: 68,
onSwitchRequested: ({ direction }) => requests.push(direction)
})
machine.beginInput(100, 'button')
machine.updateDistance(72, { source: 'button' })
vi.advanceTimersByTime(2001)
machine.beginInput(72, 'button')
machine.updateDistance(67.9, { source: 'button' })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
})
it('进入条件必须连续保持 120ms', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'wheel')
machine.updateDistance(85, { source: 'wheel' })
vi.advanceTimersByTime(119)
expect(requests).toEqual([])
vi.advanceTimersByTime(1)
expect(requests).toEqual(['enter-floor'])
})
it('两次滚轮事件累计不足 15% 时不进入', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'wheel')
machine.updateDistance(95, { source: 'wheel' })
machine.beginInput(95, 'wheel')
machine.updateDistance(90, { source: 'wheel' })
vi.advanceTimersByTime(400)
expect(requests).toEqual([])
})
it('相对楼层初始距离拉远 19.9% 不退出,达到 20% 后退出', () => {
const { machine, requests } = createMachine()
machine.setView('floor')
machine.setFloorInitialDistance(100)
machine.updateDistance(119.9)
vi.advanceTimersByTime(500)
expect(requests).toEqual([])
machine.updateDistance(120)
vi.advanceTimersByTime(400)
expect(requests).toEqual(['exit-overview'])
})
it('退出条件必须连续保持 400ms', () => {
const { machine, requests } = createMachine()
machine.setView('floor')
machine.setFloorInitialDistance(100)
machine.updateDistance(120)
vi.advanceTimersByTime(399)
expect(requests).toEqual([])
vi.advanceTimersByTime(1)
expect(requests).toEqual(['exit-overview'])
})
it('回到楼层默认距离或轻微拉远时仍停留室内,持续越过退出带才切回室外', () => {
const requests: GuideAutoSwitchDirection[] = []
const machine = new GuideAutoSwitchStateMachine({
exitRatio: 0.15,
exitHoldMs: 400,
onSwitchRequested: ({ direction }) => requests.push(direction)
})
machine.setView('floor')
machine.setFloorInitialDistance(100)
machine.updateDistance(100)
vi.advanceTimersByTime(500)
expect(requests).toEqual([])
machine.updateDistance(114.9)
vi.advanceTimersByTime(500)
expect(requests).toEqual([])
machine.updateDistance(115)
vi.advanceTimersByTime(400)
expect(requests).toEqual(['exit-overview'])
})
it('0.8% 内的触控反向抖动不重置进入基准,也不取消候选状态', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'touch', { resetBaseline: true })
machine.updateDistance(85, { source: 'touch' })
vi.advanceTimersByTime(60)
machine.updateDistance(85.6, { source: 'touch' })
vi.advanceTimersByTime(60)
expect(requests).toEqual(['enter-floor'])
})
it('明确反向缩放超过 0.8% 后取消候选并重置进入基准', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'touch', { resetBaseline: true })
machine.updateDistance(85, { source: 'touch' })
vi.advanceTimersByTime(60)
machine.updateDistance(86, { source: 'touch' })
vi.advanceTimersByTime(120)
expect(requests).toEqual([])
machine.updateDistance(73, { source: 'touch' })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
})
it('退出候选明确反向超过 0.8% 后会取消防抖任务', () => {
const { machine, requests } = createMachine()
machine.setView('floor')
machine.setFloorInitialDistance(100)
machine.updateDistance(120)
vi.advanceTimersByTime(200)
machine.updateDistance(118.9)
vi.advanceTimersByTime(400)
expect(requests).toEqual([])
})
it('进入意图超时后使用新的连续缩放距离重新计算基准', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'wheel')
machine.updateDistance(90, { source: 'wheel' })
vi.advanceTimersByTime(2001)
machine.updateDistance(80, { previousDistance: 90, source: 'wheel' })
vi.advanceTimersByTime(120)
expect(requests).toEqual([])
machine.updateDistance(76.5, { source: 'wheel' })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
})
it('切换成功后 1499ms 内不能反向切换1500ms 后可以', () => {
const { machine, requests } = createMachine()
machine.beginInput(100, 'wheel')
machine.updateDistance(85, { source: 'wheel' })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
machine.markTransitionSucceeded()
machine.setView('floor')
machine.setFloorInitialDistance(100)
machine.updateDistance(120)
vi.advanceTimersByTime(1499)
expect(requests).toEqual(['enter-floor'])
vi.advanceTimersByTime(1)
expect(requests).toEqual(['enter-floor', 'exit-overview'])
})
it.each<GuideAutoSwitchInputSource>(['wheel', 'button', 'touch'])(
'%s 路径使用同一套 15% 进入判断',
(source) => {
const { machine, requests } = createMachine()
machine.beginInput(100, source, { resetBaseline: source === 'touch' })
machine.updateDistance(85.1, { source })
vi.advanceTimersByTime(400)
expect(requests).toEqual([])
machine.updateDistance(85, { source })
vi.advanceTimersByTime(120)
expect(requests).toEqual(['enter-floor'])
}
)
})