Files
element-web/test/viewmodels/audio/AudioPlayerViewModel-test.tsx
Florian Duros 23fbe9cef6 UseCreateAutoDisposedViewModel for audio player (#31503)
* refactor: useCreateAutoDisposedViewModel for audio player

* Update src/viewmodels/audio/AudioPlayerViewModel.ts

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-11 15:41:27 +00:00

76 lines
3.2 KiB
TypeScript

/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { type ChangeEvent, type KeyboardEvent as ReactKeyboardEvent } from "react";
import { waitFor } from "@testing-library/dom";
import { type Playback, PlaybackState } from "../../../src/audio/Playback";
import { AudioPlayerViewModel } from "../../../src/viewmodels/audio/AudioPlayerViewModel";
import { MockedPlayback } from "../../unit-tests/audio/MockedPlayback";
describe("AudioPlayerViewModel", () => {
let playback: Playback;
beforeEach(() => {
playback = new MockedPlayback(PlaybackState.Decoding, 50, 10) as unknown as Playback;
});
it("should return the snapshot", () => {
const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" });
expect(vm.getSnapshot()).toMatchObject({
mediaName: "mediaName",
sizeBytes: 8000,
playbackState: "decoding",
durationSeconds: 50,
playedSeconds: 10,
percentComplete: 20,
error: false,
});
});
it("should toggle the playback state", async () => {
const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" });
await vm.togglePlay();
expect(playback.toggle).toHaveBeenCalled();
});
it("should move the playback on seekbar change", async () => {
const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" });
await vm.onSeekbarChange({ target: { value: "20" } } as ChangeEvent<HTMLInputElement>);
expect(playback.skipTo).toHaveBeenCalledWith(10); // 20% of 50 seconds
});
it("should has error=true when playback.prepare fails", async () => {
jest.spyOn(playback, "prepare").mockRejectedValue(new Error("Failed to prepare playback"));
const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" });
await waitFor(() => expect(vm.getSnapshot().error).toBe(true));
});
it("should handle key down events", () => {
const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" });
let event = new KeyboardEvent("keydown", { key: " " }) as unknown as ReactKeyboardEvent<HTMLDivElement>;
vm.onKeyDown(event);
expect(playback.toggle).toHaveBeenCalled();
event = new KeyboardEvent("keydown", { key: "ArrowLeft" }) as unknown as ReactKeyboardEvent<HTMLDivElement>;
vm.onKeyDown(event);
expect(playback.skipTo).toHaveBeenCalledWith(10 - 5); // 5 seconds back
event = new KeyboardEvent("keydown", { key: "ArrowRight" }) as unknown as ReactKeyboardEvent<HTMLDivElement>;
vm.onKeyDown(event);
expect(playback.skipTo).toHaveBeenCalledWith(10 + 5); // 5 seconds forward
});
it("should update snapshot when setProps is called with new mediaName", () => {
const vm = new AudioPlayerViewModel({ playback, mediaName: "oldName" });
expect(vm.getSnapshot().mediaName).toBe("oldName");
vm.setProps({ mediaName: "newName" });
expect(vm.getSnapshot().mediaName).toBe("newName");
});
});