mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-27 13:38:33 +00:00
7fe8cdafe0
* Improve coverage * Add view model unit tests to improve coverage * Extract initial pure EventTile derived state helpers * Extract EventTile derived state helpers * Extract EventTile class state derivation * Extract EventTile line class derivation * Extract EventTile sender profile state * Extract EventTile avatar member selection * Extract EventTile avatar clickability state * Extract EventTile sender profile mode * Extract EventTile action bar visibility * Extract EventTile timestamp visibility * Extract EventTile timestamp selection * Extract EventTile timestamp display state * Extract ReplyChain timestamp visibility * Extract EventTile footer display state * Fix sonar issue
88 lines
3.7 KiB
TypeScript
88 lines
3.7 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/room/timeline/event-tile/body/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("does not stop propagation for unhandled key down events", () => {
|
|
const vm = new AudioPlayerViewModel({ playback, mediaName: "mediaName" });
|
|
const event = new KeyboardEvent("keydown", { key: "a" });
|
|
const stopPropagationSpy = jest.spyOn(event, "stopPropagation");
|
|
|
|
vm.onKeyDown(event as unknown as ReactKeyboardEvent<HTMLDivElement>);
|
|
|
|
expect(stopPropagationSpy).not.toHaveBeenCalled();
|
|
expect(playback.toggle).not.toHaveBeenCalled();
|
|
expect(playback.skipTo).not.toHaveBeenCalled();
|
|
});
|
|
|
|
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");
|
|
});
|
|
});
|