Prevent voice message from displaying spurious errors (#30736)

* fix: avoid to render `AudioPlayerViewModel` when `MAudioBody` is inherited

* fix: avoid `Playback.prepare` to fail when called twice

* fix: add `decoding` to playback type

* refactor: fix circular deps

* refactor: extract `MockedPlayback` from `AudioPlayerViewModel`

* test: add `MAudioBody` basic test

* test: add tests for `MVoiceMessageBody`

* fix: lint
This commit is contained in:
Florian Duros
2025-09-12 10:24:51 +02:00
committed by GitHub
parent 7fc0cb242c
commit b6710d19c0
9 changed files with 219 additions and 54 deletions

View File

@@ -5,18 +5,17 @@
* Please see LICENSE files in the repository root for full details.
*/
import EventEmitter from "events";
import { SimpleObservable } from "matrix-widget-api";
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: MockedPlayback & Playback;
let playback: Playback;
beforeEach(() => {
playback = new MockedPlayback(PlaybackState.Decoding, 50, 10) as unknown as MockedPlayback & Playback;
playback = new MockedPlayback(PlaybackState.Decoding, 50, 10) as unknown as Playback;
});
it("should return the snapshot", () => {
@@ -66,38 +65,3 @@ describe("AudioPlayerViewModel", () => {
expect(playback.skipTo).toHaveBeenCalledWith(10 + 5); // 5 seconds forward
});
});
/**
* A mocked playback implementation for testing purposes.
* It simulates a playback with a fixed size and allows state changes.
*/
class MockedPlayback extends EventEmitter {
public sizeBytes = 8000;
public constructor(
public currentState: PlaybackState,
public durationSeconds: number,
public timeSeconds: number,
) {
super();
}
public setState(state: PlaybackState): void {
this.currentState = state;
this.emit("update", state);
}
public get isPlaying(): boolean {
return this.currentState === PlaybackState.Playing;
}
public get clockInfo() {
return {
liveData: new SimpleObservable(),
};
}
public prepare = jest.fn().mockResolvedValue(undefined);
public skipTo = jest.fn();
public toggle = jest.fn();
}