refactor(frontend): isolate audio meters and apply settings on save

This commit is contained in:
2026-10-07 09:29:20 -03:00
parent 09bf6ece00
commit 0c57f7c76d
7 changed files with 240 additions and 105 deletions
@@ -87,6 +87,32 @@ async function start() {
return client;
}
describe("voice application lifecycle", () => {
it("notifies only meter subscribers when microphone level changes", async () => {
const client = await start();
const app = vi.fn();
const meter = vi.fn();
controller.subscribe(app);
controller.subscribeLevel(meter);
const snapshot = controller.getSnapshot();
client.emit("level", 0.2);
expect(controller.getLevel()).toBe(0.2);
expect(meter).toHaveBeenCalledOnce();
expect(app).not.toHaveBeenCalled();
expect(controller.getSnapshot()).toBe(snapshot);
});
it("saves only changed preferences and keeps noise calibration out of session updates", async () => {
const client = await start();
const save = vi.spyOn(Storage.prototype, "setItem");
client.updateSession.mockClear();
controller.changeSettings({ noiseGate: -35 });
expect(save).toHaveBeenCalledExactlyOnceWith("s2s.ws.noiseGate", "-35");
expect(client.setGate).toHaveBeenCalledExactlyOnceWith({ enabled: true, thresholdDb: -35 });
expect(client.updateSession).not.toHaveBeenCalled();
controller.changeSettings({ voice: "Serena", instructions: "New instructions" });
expect(client.updateSession).toHaveBeenCalledOnce();
controller.changeSettings({ voice: "Serena", instructions: "New instructions" });
expect(client.updateSession).toHaveBeenCalledOnce();
});
it("renders configuration and starts without waiting for optional reports", async () => {
const original = fetchMock.getMockImplementation();
if (!original) {