Skip to content

Commit 8086262

Browse files
authored
Move AudioPlayer to shared components (#30386)
* feat: add `PlayPauseButton` to storybook * feat: add generic media body * feat: add seekbar component * chore: add ViewWrapper to help writing stories with vm * refactor: move `formatBytes` from `formattingUtils` into shared component * refactor: add `className` props to `Clock` * feat: add new audio player component * test(e2e): add screenshots for new shared components * feat: add AudioPlayerViewModel * feat: use new audio player in `MAudioBody` * refactor: remove old audio player * test(e2e): update existing tests * refactor: remove unused `DurationClock` * refactor: rename `SeekBar` into `LegacySeekBar`
1 parent f9a0a62 commit 8086262

File tree

72 files changed

+1684
-244
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1684
-244
lines changed

playwright/e2e/audio-player/audio-player.spec.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
4040
// wait for the tile to finish loading
4141
await expect(
4242
page
43-
.locator(".mx_AudioPlayer_mediaName")
43+
.getByTestId("audio-player-name")
4444
.last()
4545
.filter({ hasText: file.split("/").at(-1) }),
4646
).toBeVisible();
@@ -55,12 +55,10 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
5555
// Check that the audio player is rendered and its button becomes visible
5656
const checkPlayerVisibility = async (locator: Locator) => {
5757
// Assert that the audio player and media information are visible
58-
const mediaInfo = locator.locator(
59-
".mx_EventTile_mediaLine .mx_MAudioBody .mx_AudioPlayer_container .mx_AudioPlayer_mediaInfo",
60-
);
61-
await expect(mediaInfo.locator(".mx_AudioPlayer_mediaName", { hasText: ".ogg" })).toBeVisible(); // extension
62-
await expect(mediaInfo.locator(".mx_AudioPlayer_byline", { hasText: "00:01" })).toBeVisible();
63-
await expect(mediaInfo.locator(".mx_AudioPlayer_byline", { hasText: "(3.56 KB)" })).toBeVisible(); // actual size
58+
const mediaInfo = locator.getByRole("region", { name: "Audio player" });
59+
await expect(mediaInfo.getByText(".ogg")).toBeVisible(); // extension
60+
await expect(mediaInfo.getByRole("time")).toHaveText("00:01"); // duration
61+
await expect(mediaInfo.getByText("(3.56 KB)")).toBeVisible(); // actual size;
6462

6563
// Assert that the play button can be found and is visible
6664
await expect(locator.getByRole("button", { name: "Play" })).toBeVisible();
@@ -79,7 +77,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
7977
}
8078

8179
// Check the status of the seek bar
82-
expect(await page.locator(".mx_AudioPlayer_seek input[type='range']").count()).toBeGreaterThan(0);
80+
expect(await page.getByRole("region", { name: "Audio player" }).getByRole("slider").count()).toBeGreaterThan(0);
8381

8482
// Enable IRC layout
8583
await app.settings.setValue("layout", null, SettingLevel.DEVICE, Layout.IRC);
@@ -101,7 +99,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
10199
display: none !important;
102100
}
103101
`,
104-
mask: [page.locator(".mx_AudioPlayer_seek")],
102+
mask: [page.getByTestId("audio-player-seek")],
105103
};
106104

107105
// Take a snapshot of mx_EventTile_last on IRC layout
@@ -187,9 +185,9 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
187185
await uploadFile(page, "playwright/sample-files/1sec.ogg");
188186

189187
// Assert that the audio player is rendered
190-
const container = page.locator(".mx_EventTile_last .mx_AudioPlayer_container");
188+
const container = page.locator(".mx_EventTile_last").getByRole("region", { name: "Audio player" });
191189
// Assert that the counter is zero before clicking the play button
192-
await expect(container.locator(".mx_AudioPlayer_seek [role='timer']", { hasText: "00:00" })).toBeVisible();
190+
await expect(container.getByRole("timer")).toHaveText("00:00");
193191

194192
// Find and click "Play" button, the wait is to make the test less flaky
195193
await expect(container.getByRole("button", { name: "Play" })).toBeVisible();
@@ -199,7 +197,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
199197
await expect(container.getByRole("button", { name: "Pause" })).toBeVisible();
200198

201199
// Assert that the timer is reset when the audio file finished playing
202-
await expect(container.locator(".mx_AudioPlayer_seek [role='timer']", { hasText: "00:00" })).toBeVisible();
200+
await expect(container.getByRole("timer")).toHaveText("00:00");
203201

204202
// Assert that "Play" button can be found
205203
await expect(container.getByRole("button", { name: "Play" })).toBeVisible();
@@ -227,7 +225,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
227225
await uploadFile(page, "playwright/sample-files/1sec.ogg");
228226

229227
// Assert the audio player is rendered
230-
await expect(page.locator(".mx_EventTile_last .mx_AudioPlayer_container")).toBeVisible();
228+
await expect(page.getByRole("region", { name: "Audio player" })).toBeVisible();
231229

232230
// Find and click "Reply" button on MessageActionBar
233231
const tile = page.locator(".mx_EventTile_last");
@@ -237,7 +235,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
237235
await uploadFile(page, "playwright/sample-files/1sec.ogg");
238236

239237
// Assert that the audio player is rendered
240-
await expect(tile.locator(".mx_AudioPlayer_container")).toBeVisible();
238+
await expect(tile.getByRole("region", { name: "Audio player" })).toBeVisible();
241239

242240
// Assert that replied audio file is rendered as file button inside ReplyChain
243241
const button = tile.locator(".mx_ReplyChain_wrapper .mx_MFileBody_info[role='button']");
@@ -262,23 +260,27 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
262260
await uploadFile(page, "playwright/sample-files/upload-first.ogg");
263261

264262
// Assert that the audio player is rendered
265-
await expect(page.locator(".mx_EventTile_last .mx_AudioPlayer_container")).toBeVisible();
263+
await expect(
264+
page.locator(".mx_EventTile_last").getByRole("region", { name: "Audio player" }),
265+
).toBeVisible();
266266

267267
await clickButtonReply(tile);
268268

269269
// Reply to the player with another audio file
270270
await uploadFile(page, "playwright/sample-files/upload-second.ogg");
271271

272272
// Assert that the audio player is rendered
273-
await expect(page.locator(".mx_EventTile_last .mx_AudioPlayer_container")).toBeVisible();
273+
await expect(
274+
page.locator(".mx_EventTile_last").getByRole("region", { name: "Audio player" }),
275+
).toBeVisible();
274276

275277
await clickButtonReply(tile);
276278

277279
// Reply to the player with yet another audio file to create a reply chain
278280
await uploadFile(page, "playwright/sample-files/upload-third.ogg");
279281

280282
// Assert that the audio player is rendered
281-
await expect(tile.locator(".mx_AudioPlayer_container")).toBeVisible();
283+
await expect(tile.getByRole("region", { name: "Audio player" })).toBeVisible();
282284

283285
// Assert that there are two "mx_ReplyChain" elements
284286
await expect(tile.locator(".mx_ReplyChain")).toHaveCount(2);
@@ -314,18 +316,20 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
314316
// On the main timeline
315317
const messageList = page.locator(".mx_RoomView_MessageList");
316318
// Assert the audio player is rendered
317-
await expect(messageList.locator(".mx_EventTile_last .mx_AudioPlayer_container")).toBeVisible();
319+
await expect(
320+
messageList.locator(".mx_EventTile_last").getByRole("region", { name: "Audio player" }),
321+
).toBeVisible();
318322
// Find and click "Reply in thread" button
319323
await messageList.locator(".mx_EventTile_last").hover();
320324
await messageList.locator(".mx_EventTile_last").getByRole("button", { name: "Reply in thread" }).click();
321325

322326
// On a thread
323327
const thread = page.locator(".mx_ThreadView");
324328
const threadTile = thread.locator(".mx_EventTile_last");
325-
const audioPlayer = threadTile.locator(".mx_AudioPlayer_container");
329+
const audioPlayer = threadTile.getByRole("region", { name: "Audio player" });
326330

327331
// Assert that the counter is zero before clicking the play button
328-
await expect(audioPlayer.locator(".mx_AudioPlayer_seek [role='timer']", { hasText: "00:00" })).toBeVisible();
332+
await expect(audioPlayer.getByRole("timer")).toHaveText("00:00");
329333

330334
// Find and click "Play" button, the wait is to make the test less flaky
331335
await expect(audioPlayer.getByRole("button", { name: "Play" })).toBeVisible();
@@ -335,7 +339,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => {
335339
await expect(audioPlayer.getByRole("button", { name: "Pause" })).toBeVisible();
336340

337341
// Assert that the timer is reset when the audio file finished playing
338-
await expect(audioPlayer.locator(".mx_AudioPlayer_seek [role='timer']", { hasText: "00:00" })).toBeVisible();
342+
await expect(audioPlayer.getByRole("timer")).toHaveText("00:00");
339343

340344
// Assert that "Play" button can be found
341345
await expect(audioPlayer.getByRole("button", { name: "Play" })).not.toBeDisabled();

playwright/e2e/right-panel/file-panel.spec.ts

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,7 @@ test.describe("FilePanel", () => {
6363
await expect(roomViewBody.locator(".mx_EventTile[data-layout='group'] img[alt='riot.png']")).toBeVisible();
6464

6565
// Assert that the audio player is rendered
66-
await expect(
67-
roomViewBody.locator(".mx_EventTile[data-layout='group'] .mx_AudioPlayer_container"),
68-
).toBeVisible();
66+
await expect(roomViewBody.getByRole("region", { name: "Audio player" })).toBeVisible();
6967

7068
// Assert that the file button exists
7169
await expect(
@@ -97,9 +95,7 @@ test.describe("FilePanel", () => {
9795
await expect(image.locator("img[alt='riot.png']")).toBeVisible();
9896

9997
// Detect the audio file
100-
const audio = filePanelMessageList.locator(
101-
".mx_EventTile_mediaLine .mx_MAudioBody .mx_AudioPlayer_container",
102-
);
98+
const audio = filePanelMessageList.getByRole("region", { name: "Audio player" });
10399
// Assert that the play button is rendered
104100
await expect(audio.getByRole("button", { name: "Play" })).toBeVisible();
105101

@@ -130,29 +126,27 @@ test.describe("FilePanel", () => {
130126
// Take a snapshot of file tiles list on FilePanel
131127
await expect(filePanelMessageList).toMatchScreenshot("file-tiles-list.png", {
132128
// Exclude timestamps & flaky seek bar from snapshot
133-
mask: [page.locator(".mx_MessageTimestamp, .mx_AudioPlayer_seek")],
129+
mask: [page.locator(".mx_MessageTimestamp"), page.getByTestId("audio-player-seek")],
134130
});
135131
});
136132

137133
test("should render the audio player and play the audio file on the panel", async ({ page }) => {
138134
// Upload an image file
139135
await uploadFile(page, "playwright/sample-files/1sec.ogg");
140136

141-
const audioBody = page.locator(
142-
".mx_FilePanel .mx_RoomView_MessageList .mx_EventTile_mediaLine .mx_MAudioBody .mx_AudioPlayer_container",
143-
);
137+
const audioBody = page.getByTestId("right-panel").getByRole("region", { name: "Audio player" });
138+
144139
// Assert that the audio player is rendered
145-
// Assert that the audio file information is rendered
146-
const mediaInfo = audioBody.locator(".mx_AudioPlayer_mediaInfo");
147-
await expect(mediaInfo.locator(".mx_AudioPlayer_mediaName").getByText("1sec.ogg")).toBeVisible();
148-
await expect(mediaInfo.locator(".mx_AudioPlayer_byline", { hasText: "00:01" })).toBeVisible();
149-
await expect(mediaInfo.locator(".mx_AudioPlayer_byline", { hasText: "(3.56 KB)" })).toBeVisible(); // actual size
140+
// Assert that the audio file information is rendered;
141+
await expect(audioBody.getByText("1sec.ogg")).toBeVisible(); // extension
142+
await expect(audioBody.getByRole("time")).toHaveText("00:01"); // duration
143+
await expect(audioBody.getByText("(3.56 KB)")).toBeVisible(); // actual size;
150144

151145
// Assert that the duration counter is 00:01 before clicking the play button
152-
await expect(audioBody.locator(".mx_AudioPlayer_mediaInfo time", { hasText: "00:01" })).toBeVisible();
146+
await expect(audioBody.getByRole("time")).toHaveText("00:01");
153147

154148
// Assert that the counter is zero before clicking the play button
155-
await expect(audioBody.locator(".mx_AudioPlayer_seek [role='timer']", { hasText: "00:00" })).toBeVisible();
149+
await expect(audioBody.getByRole("timer")).toHaveText("00:00");
156150

157151
// Click the play button
158152
await audioBody.getByRole("button", { name: "Play" }).click();
@@ -161,7 +155,7 @@ test.describe("FilePanel", () => {
161155
await expect(audioBody.getByRole("button", { name: "Pause" })).toBeVisible();
162156

163157
// Assert that the timer is reset when the audio file finished playing
164-
await expect(audioBody.locator(".mx_AudioPlayer_seek [role='timer']", { hasText: "00:00" })).toBeVisible();
158+
await expect(audioBody.getByRole("timer")).toHaveText("00:00");
165159

166160
// Assert that the play button is rendered
167161
await expect(audioBody.getByRole("button", { name: "Play" })).toBeVisible();
10 KB
Loading
13.1 KB
Loading
9.88 KB
Loading
9.05 KB
Loading
5.08 KB
Loading
4.86 KB
Loading
4.4 KB
Loading
4.39 KB
Loading

0 commit comments

Comments
 (0)