1import * as NodeVM from "node:vm";
2import { describe, expect, it, vi } from "vite-plus/test";
3
4import { deviceStreamDocument, deviceStreamMessage } from "./device-stream-document";
5
6describe("native device stream document", () => {
7 it("keeps ticket and device values from terminating the embedded script", () => {
8 const deviceId = '</script><script>alert("device")</script>';
9 const configuration = JSON.stringify({ deviceId, ticket: "<ticket>" });
10 const html = deviceStreamDocument(
11 configuration,
12 "var T3DeviceStream={start(input){return input}};",
13 );
14 const script = html.match(/<script>([\s\S]*)<\/script>/)?.[1];
15 expect(html.match(/<script>/g)).toHaveLength(1);
16 const input: unknown = NodeVM.runInNewContext(script!, { window: { addEventListener() {} } });
17 expect(input).toEqual({ deviceId, ticket: "<ticket>" });
18 });
19
20 it("reports a bootstrap exception to the native recovery UI", () => {
21 const postMessage = vi.fn();
22 const html = deviceStreamDocument(
23 "{}",
24 'var T3DeviceStream={start(){throw new Error("startup")}};',
25 );
26 NodeVM.runInNewContext(html.match(/<script>([\s\S]*)<\/script>/)![1]!, {
27 window: { addEventListener() {}, ReactNativeWebView: { postMessage } },
28 });
29 expect(JSON.parse(postMessage.mock.calls[0]![0] as string)).toEqual({
30 type: "status",
31 status: "error",
32 detail: "Device viewer stopped unexpectedly.",
33 });
34 });
35});
36
37describe("native device stream messages", () => {
38 it.each([
39 "invalid JSON",
40 "null",
41 '"input"',
42 "{}",
43 '{"type":"input","connected":"yes"}',
44 '{"type":"unknown"}',
45 '{"type":"status","status":"unknown"}',
46 '{"type":"status","status":"error","detail":42}',
47 '{"type":"status"}',
48 ])("ignores invalid bridge messages: %s", (data) => expect(deviceStreamMessage(data)).toBeNull());
49});