Spaces:
Running
Running
File size: 4,701 Bytes
6c3af4e d84bd10 6c3af4e d84bd10 6c3af4e d84bd10 6c3af4e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | import { MantineProvider } from "@mantine/core";
import { fireEvent, render, screen, within } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { VoiceOption } from "@/modules/textToSpeech";
import VoiceSettingsForm from "./VoiceSettingsForm";
const localVoice: VoiceOption = {
value: "piper:en_US-lessac-high",
label: "lessac โข English (high)",
engine: "local",
languageCode: "en_US",
};
const systemVoice: VoiceOption = {
value: "system:os-voice",
label: "OS Voice โข en-US",
engine: "system",
languageCode: "en-US",
};
const { settings, setSettings, listVoices } = vi.hoisted(() => ({
settings: {
current: {
enableDictation: false,
enableLocalDictationModel: true,
selectedVoiceId: "",
textToSpeechEngine: "local" as "local" | "system",
},
},
setSettings: vi.fn(),
listVoices: vi.fn(),
}));
vi.mock("create-pubsub/react", () => ({
usePubSub: () => [settings.current, setSettings],
}));
vi.mock("@/modules/textToSpeech", () => ({
listVoices: (_languageCode: string | undefined, engine: "local" | "system") =>
listVoices(engine),
}));
/**
* jsdom runs no CSS transitions, so Mantine leaves the dropdown `display: none`
* even once it is open; every query in this file passes `hidden: true` to read
* the options that were rendered into it.
*/
function openSelect(input: HTMLElement) {
fireEvent.mouseDown(input);
fireEvent.click(input);
const listbox = document.getElementById(
input.getAttribute("aria-controls") ?? "",
);
if (!listbox) throw new Error("The select did not render a listbox");
return within(listbox);
}
function renderForm() {
return render(
<MantineProvider>
<VoiceSettingsForm />
</MantineProvider>,
);
}
function voiceInput() {
return screen.getByPlaceholderText("Auto-detected") as HTMLElement;
}
beforeEach(() => {
// jsdom has no layout, so Mantine cannot scroll the active option into view.
Element.prototype.scrollIntoView = vi.fn();
vi.clearAllMocks();
settings.current = {
enableDictation: false,
enableLocalDictationModel: true,
selectedVoiceId: "",
textToSpeechEngine: "local",
};
setSettings.mockImplementation((next: Record<string, unknown>) => {
settings.current = { ...settings.current, ...next };
});
listVoices.mockImplementation((engine: "local" | "system") =>
Promise.resolve(engine === "local" ? [localVoice] : [systemVoice]),
);
});
describe("VoiceSettingsForm", () => {
it("lists only the local voices while the local engine is selected", async () => {
renderForm();
await screen.findByText("Voice Selection");
const options = openSelect(voiceInput()).getAllByRole("option", {
hidden: true,
});
expect(options.map((option) => option.textContent)).toEqual([
"๐บ๐ธ lessac โข English (high)",
]);
});
it("lists only the system voices while the system engine is selected", async () => {
settings.current.textToSpeechEngine = "system";
renderForm();
await screen.findByText("Voice Selection");
const options = openSelect(voiceInput()).getAllByRole("option", {
hidden: true,
});
expect(options.map((option) => option.textContent)).toEqual([
"๐บ๐ธ OS Voice โข en-US",
]);
});
it("disables the on-device model switch while dictation itself is off", () => {
renderForm();
expect(
screen.getByRole("switch", {
name: /On-device dictation model/i,
}),
).toBeDisabled();
});
it("persists toggling the on-device dictation model while dictation is on", () => {
settings.current.enableDictation = true;
renderForm();
const switchInput = screen.getByRole("switch", {
name: /On-device dictation model/i,
}) as HTMLInputElement;
expect(switchInput).not.toBeDisabled();
fireEvent.click(switchInput);
expect(setSettings).toHaveBeenCalledWith(
expect.objectContaining({ enableLocalDictationModel: false }),
expect.anything(),
);
});
it("goes back to auto-detection when the engine changes", async () => {
settings.current.selectedVoiceId = localVoice.value;
renderForm();
const engine = screen.getAllByRole("combobox")[0] as HTMLElement;
fireEvent.click(
openSelect(engine).getByRole("option", {
name: "System voices (Multi-lingual)",
hidden: true,
}),
);
expect(setSettings).toHaveBeenLastCalledWith(
expect.objectContaining({
textToSpeechEngine: "system",
selectedVoiceId: "",
}),
expect.anything(),
);
expect((voiceInput() as HTMLInputElement).value).toBe("");
});
});
|