Skip to content

Commit 3155178

Browse files
committed
test: cover Background Sounds helper contract (#105)
1 parent 49b05a4 commit 3155178

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

tests/background-sounds.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { describe, expect, test, vi } from "vitest";
2+
import { readFile } from "node:fs/promises";
3+
import { runInNewContext } from "node:vm";
24
import { createTmuApp } from "../src/app";
35
import {
46
BackgroundSoundsError,
@@ -7,6 +9,19 @@ import {
79
} from "../src/background-sounds";
810

911
describe("Background Sounds runtime boundary", () => {
12+
test.each([
13+
"comfortSoundsAvailable", "comfortSoundsEnabled", "setComfortSoundsEnabled:",
14+
"selectedComfortSound", "setSelectedComfortSound:", "relativeVolume", "setRelativeVolume:",
15+
])("bundled helper rejects a missing %s selector", async (missingSelector) => {
16+
const response = await runBundledHelper({ missingSelector });
17+
expect(response).toMatchObject({ protocolVersion: 1, ok: false, code: "contract-mismatch" });
18+
});
19+
20+
test("bundled helper rejects macOS when Background Sounds is unavailable", async () => {
21+
const response = await runBundledHelper({ available: false });
22+
expect(response).toMatchObject({ protocolVersion: 1, ok: false, code: "unavailable" });
23+
});
24+
1025
test.each([
1126
["linux", "25.5.0", false],
1227
["darwin", "24.9.0", false],
@@ -104,6 +119,33 @@ describe("Background Sounds runtime boundary", () => {
104119
});
105120
});
106121

122+
async function runBundledHelper(options: { missingSelector?: string; available?: boolean }): Promise<Record<string, unknown>> {
123+
const source = await readFile(new URL("../src/background-sounds.jxa", import.meta.url), "utf8");
124+
const required = new Set([
125+
"comfortSoundsAvailable", "comfortSoundsEnabled", "setComfortSoundsEnabled:",
126+
"selectedComfortSound", "setSelectedComfortSound:", "relativeVolume", "setRelativeVolume:",
127+
]);
128+
const settings = {
129+
comfortSoundsAvailable: options.available ?? true,
130+
respondsToSelector: (selector: string) => required.has(selector) && selector !== options.missingSelector,
131+
};
132+
const dollar = Object.assign((_value: unknown) => ({}), {
133+
NSSelectorFromString: (selector: string) => selector,
134+
NSBundle: { bundleWithPath: () => ({ load: true }) },
135+
NSClassFromString: (name: string) => name === "HUComfortSoundsSettings" ? { sharedInstance: settings } : null,
136+
});
137+
const context: {
138+
ObjC: { import: () => undefined; unwrap: (value: unknown) => unknown };
139+
$: typeof dollar;
140+
__result?: string;
141+
} = {
142+
ObjC: { import: () => undefined, unwrap: (value: unknown) => value },
143+
$: dollar,
144+
};
145+
runInNewContext(`${source}\nglobalThis.__result = run(["probe"]);`, context);
146+
return JSON.parse(context.__result!) as Record<string, unknown>;
147+
}
148+
107149
describe("Background Sounds session lifecycle", () => {
108150
const snapshot = {
109151
enabled: false,

tests/vue-tui.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ describe("TMU top-level surface smoke", () => {
430430
playlist.add(track);
431431
playlist.startAt(0);
432432
const coordinator = new AppCoordinator({
433-
appState: createInitialAppState({}), uiState: createInitialUiState(),
433+
appState: createInitialAppState({}, { backgroundSoundsCandidate: true }), uiState: createInitialUiState(),
434434
initialPlaylistContent: playlist, player: new NoopPlayer(),
435435
});
436436
const hidden = await render(createTmuRoot({ coordinator, noColor: true }), { columns: 80, rows: 24 });
@@ -444,7 +444,7 @@ describe("TMU top-level surface smoke", () => {
444444
coordinator.appState.activePlaylistContent.repeatAll = true;
445445

446446
const terminal = await render(createTmuRoot({ coordinator, noColor: true }), { columns: 80, rows: 24 });
447-
for (const tab of ["playback", "library", "downloader"] as const) {
447+
for (const tab of ["playback", "library", "downloader", "background"] as const) {
448448
coordinator.dispatchUi({ type: "switchTab", tab });
449449
const frame = terminal.lastFrame()!;
450450
expect(frame).toContain("── ▶ PLAYING · A Very Long Current T");

0 commit comments

Comments
 (0)