mirror of
https://github.com/element-hq/element-call.git
synced 2026-10-15 13:21:02 +00:00
- Draws the level as lit bars, and each failure state as its own message with a next action rather than as a meter that has stopped. - A bar and the space beside it keep one size wherever the meter is drawn; what the width decides is how many bars there are. Bars spread to fill would be a different shape in every place, and would close into one block where the space ran short. - Announces the level on a fixed scale, so it does not rest on hue or on how many bars happened to fit. - The hook is a bridge and nothing more: the capture belongs to the state layer. - The capture is held by a component of its own, so a level that does change redraws the meter rather than whatever is rendered beside it. A level arrives many times a second; held by the menu it would reconcile every device row on the way to the bars. A test counts those renders, because nothing else would notice the hook moving back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
41 lines
1.5 KiB
TypeScript
41 lines
1.5 KiB
TypeScript
/*
|
|
Copyright 2026 Element Creations Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import { describe, expect, test } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
|
|
import { MicrophoneLevelMeter } from "./MicrophoneLevelMeter";
|
|
import { LEVEL_SCALE } from "../state/MicrophoneLevel";
|
|
|
|
describe("MicrophoneLevelMeter", () => {
|
|
test("announces the level rather than relying on hue", () => {
|
|
render(<MicrophoneLevelMeter state={{ type: "level", level: 6 }} />);
|
|
|
|
const meter = screen.getByRole("meter", { name: "Microphone level" });
|
|
expect(meter).toHaveAttribute("aria-valuenow", "6");
|
|
expect(meter).toHaveAttribute("aria-valuemax", String(LEVEL_SCALE));
|
|
expect(meter).toHaveAttribute("aria-valuetext", `6 of ${LEVEL_SCALE}`);
|
|
});
|
|
|
|
test("shows distinct messages for denied permission and no input device", () => {
|
|
const denied = render(
|
|
<MicrophoneLevelMeter state={{ type: "permission-denied" }} />,
|
|
);
|
|
// A next action, not a flat meter that reads as silence.
|
|
expect(
|
|
denied.getByText(/Allow access in your browser settings/),
|
|
).toBeInTheDocument();
|
|
expect(denied.queryByRole("meter")).toBeNull();
|
|
|
|
const missing = render(
|
|
<MicrophoneLevelMeter state={{ type: "no-device" }} />,
|
|
);
|
|
expect(missing.getByText(/No microphone found/)).toBeInTheDocument();
|
|
expect(missing.queryByRole("meter")).toBeNull();
|
|
});
|
|
});
|