Files
SnowLuma/packages/onebot/tests/ptt-trans-waiter.test.ts
T
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

111 lines
4.4 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest';
import {
deliverPttTransText,
pttTransKey,
requestPttTransText,
} from '../src/modules/ptt-trans-waiter';
afterEach(() => vi.useRealTimers());
describe('PTT transcription requests', () => {
it.each([Number(18446744073335783674n), 1.5, NaN, Infinity])(
'rejects an inexact numeric message id: %s',
(msgId) => {
expect(() => pttTransKey(10001, msgId)).toThrow(RangeError);
},
);
it('keeps accounts isolated for the same message id', async () => {
const first = requestPttTransText(pttTransKey(10001, 1), 20_000, async () => '');
const second = requestPttTransText(pttTransKey(10002, 1), 20_000, async () => '');
deliverPttTransText(pttTransKey(10001, 1), 'first');
deliverPttTransText(pttTransKey(10002, 1), 'second');
await expect(first).resolves.toBe('first');
await expect(second).resolves.toBe('second');
});
it.each(['text', ''])('accepts a pushed transcription: %j', async (text) => {
const result = requestPttTransText('account:push', 20_000, async () => '');
expect(deliverPttTransText('account:push', text)).toBe(true);
await expect(result).resolves.toBe(text);
expect(deliverPttTransText('account:push', text)).toBe(false);
});
it('registers before triggering so an immediate push is not lost', async () => {
const result = requestPttTransText('account:fast', 20_000, async () => {
deliverPttTransText('account:fast', 'pushed');
return 'inline';
});
await expect(result).resolves.toBe('pushed');
});
it('accepts an inline transcription', async () => {
await expect(
requestPttTransText('account:inline', 20_000, async () => 'inline'),
).resolves.toBe('inline');
});
it.each([new Error('failed'), 'failed'])(
'propagates a trigger failure: %s',
async (failure) => {
await expect(
requestPttTransText('account:failure', 20_000, async () => {
throw failure;
}),
).rejects.toThrow('failed');
},
);
it('handles a synchronous trigger failure', async () => {
await expect(
requestPttTransText('account:sync-failure', 20_000, () => {
throw new Error('sync');
}),
).rejects.toThrow('sync');
});
it.each(['resolve', 'reject'] as const)(
'ignores a superseded trigger that later calls %s',
async (settle) => {
const oldTrigger = Promise.withResolvers<string>();
const old = requestPttTransText('account:replace', 20_000, () => oldTrigger.promise);
const rejected = expect(old).rejects.toThrow('被新的请求取代');
const current = requestPttTransText('account:replace', 20_000, async () => '');
await rejected;
if (settle === 'resolve') {
oldTrigger.resolve('stale');
} else {
oldTrigger.reject(new Error('stale'));
}
await new Promise((resolve) => setTimeout(resolve, 0));
deliverPttTransText('account:replace', 'current');
await expect(current).resolves.toBe('current');
},
);
it('times out while the trigger is pending and ignores its eventual failure', async () => {
vi.useFakeTimers();
const trigger = Promise.withResolvers<string>();
const result = requestPttTransText('account:timeout', 1_000, () => trigger.promise);
const rejected = expect(result).rejects.toThrow('超时');
await vi.advanceTimersByTimeAsync(1_000);
await rejected;
const next = requestPttTransText('account:timeout', 1_000, async () => '');
trigger.reject(new Error('late failure'));
await vi.advanceTimersByTimeAsync(0);
deliverPttTransText('account:timeout', 'next');
await expect(next).resolves.toBe('next');
expect(vi.getTimerCount()).toBe(0);
});
it('clears the timeout after a successful result', async () => {
vi.useFakeTimers();
const result = requestPttTransText('account:done', 1_000, async () => 'done');
await expect(result).resolves.toBe('done');
expect(vi.getTimerCount()).toBe(0);
expect(() => deliverPttTransText('account:done', 'late')).not.toThrow();
});
});