element-call-Github/src/useCallViewKeyboardShortcuts.test.tsx
Will Hunt b3ceb5300c
Add keyboard shortcuts for raised hand / reactions (#2784)
* Add support for reactions / raised-hands via keyboard shortcuts.

* Add tests

* Fixup shortcuts

* update snapshotr

* fix type

* keyshortcuts

* remove mistakenly commited file

* fix label logic

* Add renderer for call joined / left

* Use caption

* lint

* remove unexpected file

* remove other unexpected change

* Remove other other unexpected change.
2024-11-19 16:57:57 +00:00

126 lines
3.5 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/
import { render } from "@testing-library/react";
import { FC, useRef } from "react";
import { expect, test, vi } from "vitest";
import { Button } from "@vector-im/compound-web";
import userEvent from "@testing-library/user-event";
import { useCallViewKeyboardShortcuts } from "../src/useCallViewKeyboardShortcuts";
import { ReactionOption, ReactionSet, ReactionsRowSize } from "./reactions";
// Test Explanation:
// - The main objective is to test `useCallViewKeyboardShortcuts`.
// The TestComponent just wraps a button around that hook.
interface TestComponentProps {
setMicrophoneMuted?: (muted: boolean) => void;
onButtonClick?: () => void;
sendReaction?: () => void;
toggleHandRaised?: () => void;
}
const TestComponent: FC<TestComponentProps> = ({
setMicrophoneMuted = (): void => {},
onButtonClick = (): void => {},
sendReaction = (reaction: ReactionOption): void => {},
toggleHandRaised = (): void => {},
}) => {
const ref = useRef<HTMLDivElement | null>(null);
useCallViewKeyboardShortcuts(
ref,
() => {},
() => {},
setMicrophoneMuted,
sendReaction,
toggleHandRaised,
);
return (
<div ref={ref}>
<Button onClick={onButtonClick}>TEST</Button>
</div>
);
};
test("spacebar unmutes", async () => {
const user = userEvent.setup();
let muted = true;
render(
<TestComponent
onButtonClick={() => (muted = false)}
setMicrophoneMuted={(m) => {
muted = m;
}}
/>,
);
await user.keyboard("[Space>]");
expect(muted).toBe(false);
await user.keyboard("[/Space]");
expect(muted).toBe(true);
});
test("spacebar prioritizes pressing a button", async () => {
const user = userEvent.setup();
const setMuted = vi.fn();
const onClick = vi.fn();
render(
<TestComponent setMicrophoneMuted={setMuted} onButtonClick={onClick} />,
);
await user.tab(); // Focus the button
await user.keyboard("[Space]");
expect(setMuted).not.toBeCalled();
expect(onClick).toBeCalled();
});
test("reactions can be sent via keyboard presses", async () => {
const user = userEvent.setup();
const sendReaction = vi.fn();
render(<TestComponent sendReaction={sendReaction} />);
for (let index = 1; index <= ReactionsRowSize; index++) {
await user.keyboard(index.toString());
expect(sendReaction).toHaveBeenNthCalledWith(index, ReactionSet[index - 1]);
}
});
test("raised hand can be sent via keyboard presses", async () => {
const user = userEvent.setup();
const toggleHandRaised = vi.fn();
render(<TestComponent toggleHandRaised={toggleHandRaised} />);
await user.keyboard("h");
expect(toggleHandRaised).toHaveBeenCalledOnce();
});
test("unmuting happens in place of the default action", async () => {
const user = userEvent.setup();
const defaultPrevented = vi.fn();
// In the real application, we mostly just want the spacebar shortcut to avoid
// scrolling the page. But to test that here in JSDOM, we need some kind of
// container element that can be interactive and receive focus / keydown
// events. <video> is kind of a weird choice, but it'll do the job.
render(
<video
tabIndex={0}
onKeyDown={(e) => defaultPrevented(e.isDefaultPrevented())}
>
<TestComponent setMicrophoneMuted={() => {}} />
</video>,
);
await user.tab(); // Focus the <video>
await user.keyboard("[Space]");
expect(defaultPrevented).toBeCalledWith(true);
});