utils/ts_core/src/clock.test.ts
Krzysztof kuhy Rudnicki c5b3fceeae ts_core 0.1.1, web_ui 0.4.0: consume @kuhyx/ts-config
The two shared packages are the first repos on the preset (link:../ts_config
inside the monorepo; consumers outside use the git tag). Each eslint.config.js
is now the defineConfig() call plus one override with its reason: a public
API name (`nextChance`, `fuzzyMatch`) the boolean-prefix rule would rename,
which is a breaking change for the three repos importing it.

Everything else the preset flagged is fixed in code, not disabled:
key order (perfectionist), hex casing, sort compare functions in tests,
Iterator#map().toArray(), explicit returns on multiline arrows.

web_ui: react-refresh/only-export-components was a real finding --
range-slider.tsx exported `steppedValue` next to the component, which breaks
Vite HMR for the module. The keyboard contract moves to stepped-value.ts as
`steppedValue` + a new pure `keyTarget(key, values, current)`, which also
resolves unicorn/no-late-event-control: the handler now decides the target
first and calls preventDefault() only when it owns the key. Its tests move
with it (the 250-line gate caught the combined file). Minor bump for the new
export. dist/ rebuilt in both packages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DnAYyNH1Sm4iJNidfYbrZJ
2026-09-16 21:46:41 +02:00

81 lines
2.0 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import {
type Clock,
createManualClock,
createRealClock,
realClock,
} from './clock.ts'
describe('createRealClock', () => {
it('reads from performance.now()', () => {
const spy = vi.spyOn(performance, 'now').mockReturnValue(1234)
expect(createRealClock().now()).toBe(1234)
spy.mockRestore()
})
it('advances as real time passes', () => {
const clock = createRealClock()
const first = clock.now()
expect(clock.now()).toBeGreaterThanOrEqual(first)
})
})
describe('realClock', () => {
it('is a stable shared instance', () => {
// The whole reason this export exists: a fresh object per render would
// re-fire every effect that takes the clock as a dependency.
expect(realClock).toBe(realClock)
expect(realClock).not.toBe(createRealClock())
})
it('satisfies the Clock interface', () => {
const asClock: Clock = realClock
expect(typeof asClock.now()).toBe('number')
})
})
describe('createManualClock', () => {
it('starts at 0 by default', () => {
expect(createManualClock().now()).toBe(0)
})
it('starts at the given time', () => {
expect(createManualClock(500).now()).toBe(500)
})
it('only moves when told to', () => {
const clock = createManualClock(100)
expect(clock.now()).toBe(100)
expect(clock.now()).toBe(100)
clock.advance(50)
expect(clock.now()).toBe(150)
})
it('accumulates repeated advances', () => {
const clock = createManualClock()
clock.advance(10)
clock.advance(15)
expect(clock.now()).toBe(25)
})
it('moves backwards on a negative advance', () => {
const clock = createManualClock(100)
clock.advance(-40)
expect(clock.now()).toBe(60)
})
it('jumps to an absolute time with set()', () => {
const clock = createManualClock(100)
clock.set(7)
expect(clock.now()).toBe(7)
})
it('keeps two instances independent', () => {
const a = createManualClock()
const b = createManualClock()
a.advance(99)
expect(b.now()).toBe(0)
})
})