claude-code-best/packages/remote-control-server/src/__tests__/automationState.test.ts
2026-05-01 21:39:30 +08:00

226 lines
6.7 KiB
TypeScript

import { describe, test, expect } from 'bun:test'
import {
getAutomationStateSnapshot,
getAutomationStateEventPayload,
automationStatesEqual,
} from '../services/automationState'
import type { AutomationStateResponse } from '../types/api'
// =============================================================================
// normalizeAutomationState (via getAutomationStateSnapshot)
// =============================================================================
describe('normalizeAutomationState', () => {
test('returns undefined when metadata has no automation_state key', () => {
expect(getAutomationStateSnapshot({})).toBeUndefined()
expect(getAutomationStateSnapshot({ other: true })).toBeUndefined()
expect(getAutomationStateSnapshot(null)).toBeUndefined()
expect(getAutomationStateSnapshot(undefined)).toBeUndefined()
})
test('returns disabled state for null automation_state', () => {
const result = getAutomationStateSnapshot({ automation_state: null })
expect(result).toEqual({
enabled: false,
phase: null,
next_tick_at: null,
sleep_until: null,
})
})
test('returns disabled state for non-object automation_state', () => {
for (const val of ['string', 123, true, []]) {
const result = getAutomationStateSnapshot({ automation_state: val })
expect(result?.enabled).toBe(false)
}
})
test('normalizes enabled: true correctly', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true },
})
expect(result?.enabled).toBe(true)
})
test('normalizes enabled to false for non-true values', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: 'yes' },
})
expect(result?.enabled).toBe(false)
})
test('accepts phase: standby', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, phase: 'standby' },
})
expect(result?.phase).toBe('standby')
})
test('accepts phase: sleeping', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, phase: 'sleeping' },
})
expect(result?.phase).toBe('sleeping')
})
test('rejects invalid phase values', () => {
for (const phase of ['running', 'idle', 'active', '', null]) {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, phase },
})
expect(result?.phase).toBeNull()
}
})
test('normalizes next_tick_at as number', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, next_tick_at: 12345 },
})
expect(result?.next_tick_at).toBe(12345)
})
test('normalizes next_tick_at as null for non-number', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, next_tick_at: 'soon' },
})
expect(result?.next_tick_at).toBeNull()
})
test('normalizes sleep_until as number', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, sleep_until: 99999 },
})
expect(result?.sleep_until).toBe(99999)
})
test('normalizes sleep_until as null for non-number', () => {
const result = getAutomationStateSnapshot({
automation_state: { enabled: true, sleep_until: false },
})
expect(result?.sleep_until).toBeNull()
})
test('fully normalizes a complete valid state', () => {
const result = getAutomationStateSnapshot({
automation_state: {
enabled: true,
phase: 'sleeping',
next_tick_at: 100,
sleep_until: 200,
},
})
expect(result).toEqual({
enabled: true,
phase: 'sleeping',
next_tick_at: 100,
sleep_until: 200,
})
})
})
// =============================================================================
// getAutomationStateEventPayload
// =============================================================================
describe('getAutomationStateEventPayload', () => {
test('returns disabled default when no automation_state in metadata', () => {
const result = getAutomationStateEventPayload({})
expect(result).toEqual({
enabled: false,
phase: null,
next_tick_at: null,
sleep_until: null,
})
})
test('returns disabled default for null metadata', () => {
const result = getAutomationStateEventPayload(null)
expect(result).toEqual({
enabled: false,
phase: null,
next_tick_at: null,
sleep_until: null,
})
})
test('returns normalized state when automation_state present', () => {
const result = getAutomationStateEventPayload({
automation_state: {
enabled: true,
phase: 'standby',
next_tick_at: 50,
sleep_until: 60,
},
})
expect(result).toEqual({
enabled: true,
phase: 'standby',
next_tick_at: 50,
sleep_until: 60,
})
})
test('returns a new object each call (not frozen reference)', () => {
const a = getAutomationStateEventPayload({})
const b = getAutomationStateEventPayload({})
expect(a).toEqual(b)
expect(a).not.toBe(b)
})
})
// =============================================================================
// automationStatesEqual
// =============================================================================
describe('automationStatesEqual', () => {
const base: AutomationStateResponse = {
enabled: true,
phase: 'standby',
next_tick_at: 100,
sleep_until: 200,
}
test('returns true for identical states', () => {
expect(automationStatesEqual(base, { ...base })).toBe(true)
})
test('returns false when enabled differs', () => {
expect(automationStatesEqual(base, { ...base, enabled: false })).toBe(false)
})
test('returns false when phase differs', () => {
expect(automationStatesEqual(base, { ...base, phase: 'sleeping' })).toBe(
false,
)
expect(automationStatesEqual(base, { ...base, phase: null })).toBe(false)
})
test('returns false when next_tick_at differs', () => {
expect(automationStatesEqual(base, { ...base, next_tick_at: 999 })).toBe(
false,
)
expect(automationStatesEqual(base, { ...base, next_tick_at: null })).toBe(
false,
)
})
test('returns false when sleep_until differs', () => {
expect(automationStatesEqual(base, { ...base, sleep_until: 999 })).toBe(
false,
)
expect(automationStatesEqual(base, { ...base, sleep_until: null })).toBe(
false,
)
})
test('returns true when both are disabled defaults', () => {
const disabled: AutomationStateResponse = {
enabled: false,
phase: null,
next_tick_at: null,
sleep_until: null,
}
expect(automationStatesEqual(disabled, { ...disabled })).toBe(true)
})
})