import { describe, expect, it } from 'vitest'; import { createReplyDelay, createTypingDelay, DND_AVAILABILITY, OFFLINE_AVAILABILITY, ONLINE_AVAILABILITY, } from '../src/timing'; describe('createTypingDelay', () => { it('uses 0.05 to 0.08 seconds per character by default', () => { expect(createTypingDelay('12345', { rng: () => 0 })).toBe(0.25); expect(createTypingDelay('12345', { rng: () => 1 })).toBe(0.4); expect(createTypingDelay('12345', { rng: () => 0.5 })).toBeCloseTo(0.325); }); it('returns zero for empty messages', () => { expect(createTypingDelay('', { rng: () => 1 })).toBe(0); }); }); describe('createReplyDelay', () => { it('does not add availability delay after the first reply in an active exchange', () => { expect(createReplyDelay(ONLINE_AVAILABILITY, { isFirstReplyInExchange: false, rng: () => 1 })).toBe(0); expect(createReplyDelay(DND_AVAILABILITY, { isFirstReplyInExchange: false, rng: () => 1 })).toBe(0); }); it('adds an online first-reply delay from the configured range', () => { expect(createReplyDelay(ONLINE_AVAILABILITY, { isFirstReplyInExchange: true, rng: () => 0 })).toBe(1); expect(createReplyDelay(ONLINE_AVAILABILITY, { isFirstReplyInExchange: true, rng: () => 1 })).toBe(12); }); it('can skip do-not-disturb first replies when probability fails', () => { expect(createReplyDelay(DND_AVAILABILITY, { isFirstReplyInExchange: true, rng: () => 0.99 })).toBeNull(); }); it('returns a do-not-disturb delay when probability succeeds', () => { const values = [0.1, 0.5]; const rng = () => values.shift() ?? 0; expect(createReplyDelay(DND_AVAILABILITY, { isFirstReplyInExchange: true, rng })).toBe(330); }); it('blocks offline replies', () => { expect(createReplyDelay(OFFLINE_AVAILABILITY, { isFirstReplyInExchange: true, rng: () => 0 })).toBeNull(); }); });