Open History to see the last commit
1import { VOICE_RECORDING_LIMIT_SECONDS } from "@t3tools/client-runtime/voice-input";
2import { expect, it, vi } from "vite-plus/test";
3import { createEnvironmentTranscriber } from "./environmentTranscriber";
4
5it("never uploads a recording whose grant changed while the phone decoded it", async () => {
6 let grant = 1;
7 const decoded = Promise.withResolvers<Uint8Array>();
8 const upload = vi.fn(async () => "hello");
9 const transcriber = createEnvironmentTranscriber({
10 canSend: () => grant === 1,
11 prepare: async () => "en",
12 decode: () => decoded.promise,
13 upload,
14 });
15 const options = { signal: new AbortController().signal };
16 const recording = await transcriber.prepare(options);
17 const transcription = recording.transcribe("file:///draft.m4a", options);
18 grant++;
19 decoded.resolve(new Uint8Array([0, 128, 0, 64]));
20 await expect(transcription).rejects.toMatchObject({ code: "cancelled" });
21 expect(upload).not.toHaveBeenCalled();
22});
23
24it("uploads normalized mono samples only after the recording is finished", async () => {
25 const upload = vi.fn(async (bytes: Uint8Array) => {
26 expect(Array.from(new Float32Array(Uint8Array.from(bytes).buffer))).toEqual([-1, 0.5]);
27 return "hello";
28 });
29 const transcriber = createEnvironmentTranscriber({
30 canSend: () => true,
31 prepare: async () => "en",
32 decode: async () => new Uint8Array([255, 0, 128, 0, 64, 255]).subarray(1, 5),
33 upload,
34 });
35 const options = { signal: new AbortController().signal };
36 const recording = await transcriber.prepare(options);
37 expect(upload).not.toHaveBeenCalled();
38 await expect(recording.transcribe("file:///draft.m4a", options)).resolves.toBe("hello");
39});
40
41it("trims at most one second of recorder padding and rejects longer recordings", async () => {
42 const limit = 16_000 * VOICE_RECORDING_LIMIT_SECONDS;
43 const padded = new Uint8Array((limit + 16_000 + 1) * 2);
44 padded[(limit - 1) * 2 + 1] = 64;
45 let bytes = padded.subarray(0, -2);
46 const upload = vi.fn(async (body: Uint8Array) => {
47 expect(body.byteLength).toBe(limit * 4);
48 expect(
49 new DataView(body.buffer, body.byteOffset, body.byteLength).getFloat32(
50 body.byteLength - 4,
51 true,
52 ),
53 ).toBe(0.5);
54 return "hello";
55 });
56 const options = { signal: new AbortController().signal };
57 const recording = await createEnvironmentTranscriber({
58 canSend: () => true,
59 prepare: async () => "en",
60 decode: async () => bytes,
61 upload,
62 }).prepare(options);
63 await expect(recording.transcribe("file:///padded.m4a", options)).resolves.toBe("hello");
64 bytes = padded;
65 await expect(recording.transcribe("file:///too-long.m4a", options)).rejects.toThrow(
66 "This recording couldn’t be read. Try recording again.",
67 );
68 expect(upload).toHaveBeenCalledOnce();
69});