Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Add E2E test of audio player #10441

Merged
merged 75 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
4dcc8e7
Add audio-player.spec.ts
luixxiul Mar 19, 2023
1694921
Download audio file
luixxiul Mar 19, 2023
ddc7898
Reply
luixxiul Mar 19, 2023
b8facfe
ReplyChain
luixxiul Mar 19, 2023
f88ff9c
Audio player on a thread
luixxiul Mar 19, 2023
133cf69
Add 'wrapper' option to takeSnapshots() in mx_ThreadView
luixxiul Mar 23, 2023
2e55e28
Click timestamps to highlight mx_EventTile to hopefully avoid flaky P…
luixxiul Mar 23, 2023
f2a6d0a
Assert that the radio button for light theme was checked
luixxiul Mar 24, 2023
c6cf476
Typo
luixxiul Mar 24, 2023
f23cfc2
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 24, 2023
617f979
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 24, 2023
b282fff
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 24, 2023
c6b908d
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 24, 2023
f0b120e
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 24, 2023
495b612
Add comments to const percyCSS
luixxiul Mar 25, 2023
649d20b
Remove double quotation marks inside backticks
luixxiul Mar 25, 2023
445be1d
Rename a test
luixxiul Mar 25, 2023
3742b4f
Rename a test and edit a comment on mx_ReplyChain
luixxiul Mar 25, 2023
f6ffc1a
Wait until rendering of the player settled and assert that the play b…
luixxiul Mar 25, 2023
b18794d
Extract the test for IRC layout
luixxiul Mar 25, 2023
36b650e
Add and edit comments for takeSnapshots() and the test on IRC layout
luixxiul Mar 25, 2023
399a434
Move comments about snapshot widths
luixxiul Mar 25, 2023
fa97ee6
Check audio player's rendering and its button's visibility
luixxiul Mar 25, 2023
725d020
Add checkPlayerVisibility()
luixxiul Mar 25, 2023
82e4804
Take snapshots of the small player
luixxiul Mar 26, 2023
bcf8634
Edit snapshot name
luixxiul Mar 26, 2023
376ef1b
Use cy.closeDialog()
luixxiul Mar 26, 2023
6d559f0
Check player visibility on ThreadView
luixxiul Mar 26, 2023
1e0560c
Manage widths with variables
luixxiul Mar 26, 2023
39cdbe3
Merge branch 'develop' into test-audioplayer
luixxiul Mar 26, 2023
8ff182a
Remove 'takeSnapshotTimeline'
luixxiul Mar 26, 2023
b148eb8
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 27, 2023
f4a0ee5
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 27, 2023
e8094bd
Update cypress/e2e/audio-player/audio-player.spec.ts
luixxiul Mar 27, 2023
6b496e8
Edit comments
luixxiul Mar 27, 2023
98dd473
Remove an obsolete comment
luixxiul Mar 27, 2023
1a0fde5
Remove a command to set a layout value
luixxiul Mar 27, 2023
1b279fd
Remove a command to enable use_system_theme
luixxiul Mar 27, 2023
698f443
Revert "Remove a command to enable use_system_theme"
luixxiul Mar 29, 2023
437ee52
Edit a comment - disable system theme
luixxiul Mar 29, 2023
a59586f
Merge branch 'develop' of https://github.com/matrix-org/matrix-react-…
luixxiul Mar 31, 2023
555f5de
Edit a comment
luixxiul Apr 1, 2023
cdc77d6
Remove an assertion about the audio player being rendered
luixxiul Apr 1, 2023
946b330
Edit a test on a thread
luixxiul Apr 1, 2023
c581aae
Use Cypress Testing Library
luixxiul Mar 31, 2023
6969e5a
Use existing functions in favor of visitRoom()
luixxiul Apr 1, 2023
af07043
Improve the test flow - checking on the high contrast theme
luixxiul Apr 1, 2023
04ad2f8
Simplify and improve the widths setting of snapshots
luixxiul Apr 1, 2023
a20648f
Improve takeSnapshots
luixxiul Apr 1, 2023
dd1d306
Improve the test - checking a reply and a reply chain
luixxiul Apr 1, 2023
6495655
Remove redundant within()
luixxiul Apr 1, 2023
7774d44
Add audio files to make the test check files more strictly
luixxiul Apr 1, 2023
5dc2463
Simplify the test a little bit by removing within()
luixxiul Apr 1, 2023
3c5bb25
Edit a comment
luixxiul Apr 1, 2023
7488d88
Create uploadAndTakeSnapshots()
luixxiul Apr 1, 2023
a9fc678
Improve the test - download
luixxiul Apr 1, 2023
21d0798
lint
luixxiul Apr 1, 2023
b11f30d
theme -> detail
luixxiul Apr 1, 2023
7019c86
Merge branch 'develop' of https://github.com/matrix-org/matrix-react-…
luixxiul Apr 1, 2023
b176a22
Iterate - remove uploadAndTakeSnapshots
luixxiul Apr 2, 2023
50a0c1a
Iterate - remove within()
luixxiul Apr 2, 2023
0175351
Iterate - remove redundant wrappers
luixxiul Apr 2, 2023
e2e08b3
Output log for IRC layout
luixxiul Apr 2, 2023
f3fc364
Remove redundant comments
luixxiul Apr 2, 2023
b38ee4d
Edit log()
luixxiul Apr 2, 2023
df5f2b9
Chain commands
luixxiul Apr 2, 2023
bf296a4
Edit comments
luixxiul Apr 2, 2023
d95b153
Merge branch 'develop' of https://github.com/matrix-org/matrix-react-…
luixxiul Apr 3, 2023
c1baa6d
Remove unused injectAxe()
luixxiul Apr 3, 2023
c0d9733
Merge branch 'develop' into test-audioplayer
luixxiul Apr 5, 2023
7d0df71
Add a comment about 'monospace'
luixxiul Apr 5, 2023
e1ae92b
Edit a comment
luixxiul Apr 5, 2023
febe45b
Merge branch 'develop' into test-audioplayer
richvdh Apr 5, 2023
4c9c613
Merge branch 'develop' into test-audioplayer
luixxiul Apr 5, 2023
450a48f
Merge branch 'develop' into test-audioplayer
t3chguy Apr 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
386 changes: 386 additions & 0 deletions cypress/e2e/audio-player/audio-player.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,386 @@
/*
Copyright 2023 Suguru Hirahara

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/// <reference types="cypress" />

import { HomeserverInstance } from "../../plugins/utils/homeserver";
import { SettingLevel } from "../../../src/settings/SettingLevel";
import { Layout } from "../../../src/settings/enums/Layout";

describe("Audio player", () => {
let homeserver: HomeserverInstance;
const TEST_USER = "Hanako";

const percyCSS =
// FIXME: hide mx_SeekBar because flaky - see https://github.com/vector-im/element-web/issues/24898
".mx_SeekBar, " +
// Exclude various components from the snapshot, for consistency
".mx_JumpToBottomButton, " +
".mx_MessageTimestamp, .mx_RoomView_myReadMarker { visibility: hidden !important; }";

const uploadFile = (file: string) => {
// Upload a file from the message composer
cy.get(".mx_MessageComposer_actions input[type='file']").selectFile(file, { force: true });

cy.get(".mx_Dialog").within(() => {
// Find and click primary "Upload" button
cy.get("[data-testid='dialog-primary-button']").findButton("Upload").click();
});

// Wait until the file is sent
cy.get(".mx_RoomView_statusArea_expanded").should("not.exist");
cy.get(".mx_EventTile.mx_EventTile_last .mx_EventTile_receiptSent").should("exist");
};

/**
* Take snapshots of mx_EventTile_last on each layout, outputting log for reference/debugging.
* @param detail The Percy snapshot name. Used for outputting logs too.
*/
const takeSnapshots = (detail: string, monospace = false) => {
richvdh marked this conversation as resolved.
Show resolved Hide resolved
// Check that the audio player is rendered and its button becomes visible
const checkPlayerVisibility = () => {
// Assert that the audio player and media information are visible
cy.get(".mx_EventTile_mediaLine .mx_MAudioBody .mx_AudioPlayer_container .mx_AudioPlayer_mediaInfo").within(
() => {
cy.contains(".mx_AudioPlayer_mediaName", ".ogg").should("be.visible"); // extension
cy.contains(".mx_AudioPlayer_byline", "00:01").should("be.visible");
cy.contains(".mx_AudioPlayer_byline", "(3.56 KB)").should("be.visible"); // actual size
},
);

// Assert that the play button can be found and is visible
cy.findButton("Play").should("be.visible");

if (monospace) {
// Assert that the monospace timer is visible
cy.get("[role='timer']").should("have.css", "font-family", '"monospace"').should("be.visible");
}
};

/**
* Define snapshot widths of selected EventTile, on which the audio player is rendered
*
* 50px (magic number): narrow enough EventTile to be compressed to check a11y
* 267px: EventTile on IRC and modern/group layout, on which the player is rendered in its full width
* 285px: EventTile on bubble layout, on which the player is rendered in its full width
*/
const snapshotWidthsIRC = [50, 267];
const snapshotWidthsGroup = snapshotWidthsIRC;
const snapshotWidthsBubble = [50, 285];

if (monospace) {
// Enable system font and monospace setting
cy.setSettingValue("useSystemFont", null, SettingLevel.DEVICE, true);
cy.setSettingValue("systemFont", null, SettingLevel.DEVICE, "monospace");
}

// Check the status of the seek bar
// TODO: check if visible - currently checking its visibility on a compressed EventTile returns an error
cy.get(".mx_AudioPlayer_seek input[type='range']").should("exist");

// Enable IRC layout
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.IRC);

cy.get(".mx_EventTile_last[data-layout='irc']").within(() => {
// Click the event timestamp to highlight EventTile in case it is not visible
cy.get(".mx_MessageTimestamp").click();

// Assert that rendering of the player settled and the play button is visible before taking a snapshot
checkPlayerVisibility();
});

// Take a snapshot of mx_EventTile_last on IRC layout
cy.get(".mx_EventTile_last").percySnapshotElement(detail + " on IRC layout", {
percyCSS,
widths: snapshotWidthsIRC,
});

// Output a log
cy.log("Took a snapshot of " + detail + " on IRC layout");

// Take a snapshot on modern/group layout
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.Group);
cy.get(".mx_EventTile_last[data-layout='group']").within(() => {
cy.get(".mx_MessageTimestamp").click();
checkPlayerVisibility();
});
cy.get(".mx_EventTile_last").percySnapshotElement(detail + " on modern/group layout", {
percyCSS,
widths: snapshotWidthsGroup,
});
cy.log("Took a snapshot of " + detail + " on modern/group layout");

// Take a snapshot on bubble layout
cy.setSettingValue("layout", null, SettingLevel.DEVICE, Layout.Bubble);
cy.get(".mx_EventTile_last[data-layout='bubble']").within(() => {
cy.get(".mx_MessageTimestamp").click();
checkPlayerVisibility();
});
cy.get(".mx_EventTile_last").percySnapshotElement(detail + " on bubble layout", {
percyCSS,
widths: snapshotWidthsBubble,
});
cy.log("Took a snapshot of " + detail + " on bubble layout");
};

beforeEach(() => {
cy.startHomeserver("default").then((data) => {
homeserver = data;
cy.initTestUser(homeserver, TEST_USER);
});

cy.createRoom({ name: "Test Room" }).viewRoomByName("Test Room");

// Wait until configuration is finished
cy.contains(
".mx_RoomView_body .mx_GenericEventListSummary[data-layout='group'] .mx_GenericEventListSummary_summary",
"created and configured the room.",
).should("exist");
});

afterEach(() => {
cy.stopHomeserver(homeserver);
});

it("should be correctly rendered - light theme", () => {
uploadFile("cypress/fixtures/1sec-long-name-audio-file.ogg");

takeSnapshots("Selected EventTile of audio player (light theme)");
});

it("should be correctly rendered - light theme with monospace font", () => {
uploadFile("cypress/fixtures/1sec-long-name-audio-file.ogg");

takeSnapshots("Selected EventTile of audio player (light theme, monospace font)", true); // Enable monospace
});

it("should be correctly rendered - high contrast theme", () => {
// Disable system theme in case ThemeWatcher enables the theme automatically,
// so that the high contrast theme can be enabled
cy.setSettingValue("use_system_theme", null, SettingLevel.DEVICE, false);

// Enable high contrast manually
cy.openUserSettings("Appearance")
.get(".mx_ThemeChoicePanel")
.within(() => {
cy.get("[data-testid='theme-choice-panel-selectors']").within(() => {
// Enable light theme
cy.get(".mx_ThemeSelector_light").click();

// Assert that the radio button for light theme was checked
cy.get(".mx_StyledRadioButton_checked input[value='light']").should("exist");
});

cy.get("[data-testid='theme-choice-panel-highcontrast']").within(() => {
// Click the checkbox
cy.get("label .mx_Checkbox_background").click();
});
});

cy.closeDialog();

uploadFile("cypress/fixtures/1sec-long-name-audio-file.ogg");

takeSnapshots("Selected EventTile of audio player (high contrast)");
});

it("should be correctly rendered - dark theme", () => {
// Enable dark theme
cy.setSettingValue("theme", null, SettingLevel.ACCOUNT, "dark");

uploadFile("cypress/fixtures/1sec-long-name-audio-file.ogg");

takeSnapshots("Selected EventTile of audio player (dark theme)");
});

it("should play an audio file", () => {
uploadFile("cypress/fixtures/1sec.ogg");

// Assert that the audio player is rendered
cy.get(".mx_EventTile_last .mx_EventTile_mediaLine .mx_MAudioBody .mx_AudioPlayer_container").within(() => {
// Assert that the counter is zero before clicking the play button
cy.contains(".mx_AudioPlayer_seek [role='timer']", "00:00").should("exist");

// Find and click "Play" button
cy.findButton("Play").click();

// Assert that "Pause" button can be found
cy.findButton("Pause").should("exist");

// Assert that the timer is reset when the audio file finished playing
cy.contains(".mx_AudioPlayer_seek [role='timer']", "00:00").should("exist");

// Assert that "Play" button can be found
cy.findButton("Play").should("exist");
});
});

it("should support downloading an audio file", () => {
uploadFile("cypress/fixtures/1sec.ogg");

// Find and click "Download" button on MessageActionBar
cy.get(".mx_EventTile_last").realHover().findButton("Download").click();

// Assert that the file was downloaded
cy.readFile("cypress/downloads/1sec.ogg").should("exist");
});

it("should support replying to audio file with another audio file", () => {
uploadFile("cypress/fixtures/1sec.ogg");

// Assert the audio player is rendered
cy.get(".mx_EventTile_last .mx_AudioPlayer_container").should("exist");

// Find and click "Reply" button on MessageActionBar
cy.get(".mx_EventTile_last").realHover().findButton("Reply").click();

// Reply to the player with another audio file
uploadFile("cypress/fixtures/1sec.ogg");

cy.get(".mx_EventTile_last").within(() => {
// Assert that the audio player is rendered
cy.get(".mx_AudioPlayer_container").should("exist");

// Assert that replied audio file is rendered as file button inside ReplyChain
cy.get(".mx_ReplyChain_wrapper .mx_MFileBody_info[role='button']").within(() => {
// Assert that the file button has file name
cy.get(".mx_MFileBody_info_filename").should("exist");
});
});

// Take snapshots
takeSnapshots("Selected EventTile of audio player with a reply");
});

it("should support creating a reply chain with multiple audio files", () => {
// Note: "mx_ReplyChain" element is used not only for replies which
// create a reply chain, but also for a single reply without a replied
// message. This test checks whether a reply chain which consists of
// multiple audio file replies is rendered properly.

// Find and click "Reply" button
const clickButtonReply = () => {
cy.get(".mx_EventTile_last").realHover().findButton("Reply").click();
};

uploadFile("cypress/fixtures/upload-first.ogg");

// Assert that the audio player is rendered
cy.get(".mx_EventTile_last .mx_AudioPlayer_container").should("exist");

clickButtonReply();

// Reply to the player with another audio file
uploadFile("cypress/fixtures/upload-second.ogg");

// Assert that the audio player is rendered
cy.get(".mx_EventTile_last .mx_AudioPlayer_container").should("exist");

clickButtonReply();

// Reply to the player with yet another audio file to create a reply chain
uploadFile("cypress/fixtures/upload-third.ogg");

cy.get(".mx_EventTile_last").within(() => {
// Assert that the audio player is rendered
cy.get(".mx_AudioPlayer_container").should("exist");

// Assert that there are two "mx_ReplyChain" elements
cy.get(".mx_ReplyChain").should("have.length", 2);

// Assert that one line contains the user name
cy.contains(".mx_ReplyChain .mx_ReplyTile_sender", TEST_USER);

// Assert that the other line contains the file button
cy.get(".mx_ReplyChain .mx_MFileBody").should("exist");

// Click "In reply to"
cy.contains(".mx_ReplyChain .mx_ReplyChain_show", "In reply to").click();

cy.get("blockquote.mx_ReplyChain:first-of-type").within(() => {
// Assert that "In reply to" has disappeared
cy.contains("In reply to").should("not.exist");

// Assert that audio file on the first row is rendered as file button
cy.get(".mx_MFileBody_info[role='button']").within(() => {
// Assert that the file button contains the name of the file sent at first
cy.contains(".mx_MFileBody_info_filename", "upload-first.ogg");
});
});
});

// Take snapshots
takeSnapshots("Selected EventTile of audio player with a reply chain");
});

it("should be rendered, play, and support replying on a thread", () => {
uploadFile("cypress/fixtures/1sec-long-name-audio-file.ogg");

// On the main timeline
cy.get(".mx_RoomView_MessageList").within(() => {
// Assert the audio player is rendered
cy.get(".mx_EventTile_last .mx_AudioPlayer_container").should("exist");

// Find and click "Reply in thread" button
cy.get(".mx_EventTile_last").realHover().findButton("Reply in thread").click();
});

// On a thread
cy.get(".mx_ThreadView").within(() => {
cy.get(".mx_EventTile_last")
.within(() => {
// Assert that the player is correctly rendered on a thread
cy.get(".mx_EventTile_mediaLine .mx_MAudioBody .mx_AudioPlayer_container").within(() => {
// Assert that the counter is zero before clicking the play button
cy.contains(".mx_AudioPlayer_seek [role='timer']", "00:00").should("exist");

// Find and click "Play" button
cy.findButton("Play").click();

// Assert that "Pause" button can be found
cy.findButton("Pause").should("exist");

// Assert that the timer is reset when the audio file finished playing
cy.contains(".mx_AudioPlayer_seek [role='timer']", "00:00").should("exist");

// Assert that "Play" button can be found
cy.findButton("Play").should("exist");
});
})
.realHover()
.findButton("Reply")
.click(); // Find and click "Reply" button

cy.get(".mx_MessageComposer--compact").within(() => {
// Assert that the reply preview is rendered on the message composer
cy.get(".mx_ReplyPreview").within(() => {
// Assert that the reply preview contains audio ReplyTile the file info button
cy.get(".mx_ReplyTile_audio .mx_MFileBody_info[role='button']").should("exist");
});

// Select :smile: emoji and send it
cy.get("[data-testid='basicmessagecomposer']").type(":smile:");
cy.get(".mx_Autocomplete_Completion[aria-selected='true']").click();
cy.get("[data-testid='basicmessagecomposer']").type("{enter}");
});

cy.get(".mx_EventTile_last").within(() => {
// Assert that the file name is rendered on the file button
cy.get(".mx_ReplyTile_audio .mx_MFileBody_info[role='button']").should("exist");
});
});
});
});
Binary file added cypress/fixtures/1sec-long-name-audio-file.ogg
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Binary file not shown.
Binary file added cypress/fixtures/upload-first.ogg
Binary file not shown.
Binary file added cypress/fixtures/upload-second.ogg
Binary file not shown.
Binary file added cypress/fixtures/upload-third.ogg
Binary file not shown.
Loading