Skip to content

Commit

Permalink
add(test): start adding tests for audio calls (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
luisecm authored Oct 15, 2024
1 parent 13d31dd commit 0b731ec
Show file tree
Hide file tree
Showing 8 changed files with 510 additions and 80 deletions.
14 changes: 14 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ export default defineConfig({
use: {
browserName: "chromium",
viewport: { width: 1280, height: 720 }, // Desktop viewport
launchOptions: {
args: [
"--disable-web-security",
"--use-fake-ui-for-media-stream",
"--use-fake-device-for-media-stream",
],
},
},
},

Expand All @@ -59,6 +66,13 @@ export default defineConfig({
use: {
browserName: "chromium",
...devices["Pixel 5"], // Use predefined mobile device
launchOptions: {
args: [
"--disable-web-security",
"--use-fake-ui-for-media-stream",
"--use-fake-device-for-media-stream",
],
},
},
testIgnore: "./playwright/specs/13-settings-keybinds.spec.ts",
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import MainPage from "./MainPage";
import MainPage from "../MainPage";
import { type Locator, type Page } from "@playwright/test";

export class CallControls extends MainPage {
Expand Down
263 changes: 263 additions & 0 deletions playwright/PageObjects/CallElements/CallScreen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
import MainPage from "../MainPage";
import { type Locator, type Page, expect } from "@playwright/test";

export class CallScreen extends MainPage {
readonly callCollapseExpandButton: Locator;
readonly callDeafenButton: Locator;
readonly callEndButton: Locator;
readonly callFullscreenButton: Locator;
readonly callMuteButton: Locator;
readonly callParticipant: Locator;
readonly callParticipantConnecting: Locator;
readonly callParticipantShaking: Locator;
readonly callScreen: Locator;
readonly callScreenTopbar: Locator;
readonly callSettingsButton: Locator;
readonly callStreamButton: Locator;
readonly callVideoButton: Locator;
readonly callVolumeMixerButton: Locator;
readonly localUserVideo: Locator;
readonly participantDeafenButton: Locator;
readonly participantMuteButton: Locator;
readonly participantProfilePicture: Locator;
readonly participantProfilePictureIdenticon: Locator;
readonly participantProfilePictureImage: Locator;
readonly participantUser: Locator;
readonly participantVideo: Locator;
readonly participantWithoutVideo: Locator;
readonly participants: Locator;
readonly remoteUserVideo: Locator;
readonly usersInCallText: Locator;

constructor(
public readonly page: Page,
public readonly viewport: string,
) {
super(page, viewport);
this.callScreen = this.page.getByTestId("call-screen");
this.callCollapseExpandButton = this.callScreen.getByTestId(
"button-call-collapse-expand",
);
this.callDeafenButton = this.callScreen.getByTestId("button-call-deafen");
this.callEndButton = this.callScreen.getByTestId("button-call-end");
this.callFullscreenButton = this.callScreen.getByTestId(
"button-call-fullscreen",
);
this.callMuteButton = this.callScreen.getByTestId("button-call-mute");
this.callParticipant = this.callScreen.getByTestId("call-participant");
this.callParticipantConnecting = this.page.getByText("Connecting...");
this.callParticipantShaking = this.page.locator(".shaking-participant");
this.callScreenTopbar = this.callScreen.getByTestId("topbar");
this.callSettingsButton = this.callScreen.getByTestId(
"button-call-settings",
);
this.callStreamButton = this.callScreen.getByTestId("button-call-stream");
this.callVideoButton = this.callScreen.getByTestId("button-call-video");
this.callVolumeMixerButton = this.callScreen.getByTestId(
"button-call-volume-mixer",
);
this.localUserVideo = this.callScreen.getByTestId("local-user-video");
this.participantDeafenButton = this.callScreen.getByTestId(
"button-participant-deafen",
);
this.participantMuteButton = this.callScreen.getByTestId(
"button-participant-mute",
);
this.participantProfilePicture = this.page.getByTestId(
"participant-profile-picture",
);
this.participantProfilePictureIdenticon =
this.participantProfilePicture.locator(".identicon");
this.participantProfilePictureImage =
this.participantProfilePicture.locator("img");
this.participantUser = this.page.getByTestId("participant-user");
this.participantVideo = this.page.getByTestId("participant-video");
this.participantWithoutVideo = this.page.getByTestId(
"participant-without-video",
);
this.participants = this.callScreen.locator("#participants");
this.remoteUserVideo = this.callScreen.getByTestId("remote-user-video");
this.usersInCallText = this.callScreen.getByTestId("text-users-in-call");
}

async clickOnStreamButton() {
await this.callStreamButton.click();
await expect(this.callStreamButton).toHaveCSS(
"border-bottom-color",
"rgb(77, 77, 255)",
);
await expect(this.callStreamButton).toHaveAttribute(
"data-tooltip",
"Stream",
);
}

async collapseCall() {
await expect(this.callCollapseExpandButton).toHaveAttribute(
"data-tooltip",
"Less Space",
);
await this.callCollapseExpandButton.click();
await expect(this.callScreen).not.toHaveClass(/.*\bexpanded\b.*/);
await expect(this.callCollapseExpandButton).toHaveAttribute(
"data-tooltip",
"More Space",
);
}

async deafenCall() {
await this.callDeafenButton.click();
await expect(this.callDeafenButton).toHaveCSS(
"background-color",
"color(srgb 0.978824 0.297647 0.396471)",
);
await expect(this.callDeafenButton).toHaveAttribute(
"data-tooltip",
"Deafen",
);
}

async disableVideo() {
await expect(this.callVideoButton).toHaveAttribute(
"data-tooltip",
"Disable Video",
);
await this.callVideoButton.click();
await expect(this.callVideoButton).toHaveCSS(
"background-color",
/rgb\(249, 56, 84\)|color\(srgb 0.978824 0.297647 0.396471\)/,
);

await expect(this.callVideoButton).toHaveAttribute(
"data-tooltip",
"Enable Video",
);
}

async enableVideo() {
await expect(this.callVideoButton).toHaveAttribute(
"data-tooltip",
"Enable Video",
);
await this.callVideoButton.click();
await expect(this.callVideoButton).toHaveCSS(
"background-color",
"rgb(33, 38, 58)",
);
await expect(this.callVideoButton).toHaveAttribute(
"data-tooltip",
"Disable Video",
);
}

async endCall() {
await expect(this.callEndButton).toHaveAttribute("data-tooltip", "End");
await expect(this.callEndButton).toHaveCSS(
"background-color",
"rgb(249, 56, 84)",
);
await this.callEndButton.click();
await this.callScreen.waitFor({ state: "detached" });
}

async expandCall() {
await expect(this.callCollapseExpandButton).toHaveAttribute(
"data-tooltip",
"More Space",
);
await this.callCollapseExpandButton.click();
await expect(this.callScreen).toHaveClass(/.*\bexpanded\b.*/);
await expect(this.callCollapseExpandButton).toHaveAttribute(
"data-tooltip",
"Less Space",
);
}

async enterFullScreenMode() {
await expect(this.callFullscreenButton).toHaveAttribute(
"data-tooltip",
"Fullscreen",
);
await this.callFullscreenButton.click();
const isFullscreen = await this.page.evaluate(() => {
return document.fullscreenElement !== null;
});
expect(isFullscreen).toBeTruthy();
}
async exitFullScreenMode() {
await expect(this.callFullscreenButton).toHaveAttribute(
"data-tooltip",
"Fullscreen",
);
await this.callFullscreenButton.click();
const isFullscreen = await this.page.evaluate(() => {
return document.fullscreenElement !== null;
});
expect(isFullscreen).toBeFalsy();
}

async muteCall() {
await expect(this.callMuteButton).toHaveAttribute("data-tooltip", "Mute");
await this.callMuteButton.click();
await expect(this.callMuteButton).toHaveCSS(
"background-color",
"color(srgb 0.978824 0.297647 0.396471)",
);
await expect(this.callMuteButton).toHaveAttribute("data-tooltip", "Unmute");
}

async openCallSettings() {
await this.callSettingsButton.click();
}

async openCallVolumeMixer() {
await this.callVolumeMixerButton.click();
}

async undeafenCall() {
await this.callDeafenButton.click();
await expect(this.callDeafenButton).toHaveCSS(
"background-color",
"rgb(35, 41, 62)",
);
await expect(this.callDeafenButton).toHaveAttribute(
"data-tooltip",
"Deafen",
);
}

async unmuteCall() {
await expect(this.callMuteButton).toHaveAttribute("data-tooltip", "Unmute");
await this.callMuteButton.click();
await expect(this.callMuteButton).toHaveCSS(
"background-color",
"rgb(35, 41, 62)",
);
await expect(this.callMuteButton).toHaveAttribute("data-tooltip", "Mute");
}

async validateCallScreenContents(
localUserImgSrc: string,
remoteUserImgSrc: string,
) {
// Validate local user contents
await expect(this.participantProfilePictureImage.first()).toHaveAttribute(
"src",
localUserImgSrc,
);

// Validate remote user profile picture
await expect(this.participantProfilePictureImage.last()).toHaveAttribute(
"src",
remoteUserImgSrc,
);

// Validate number of users in call displayed in label
await expect(this.usersInCallText).toHaveText("(2) users in the call");
}

async validateUserIsConnecting() {
await expect(this.callParticipantConnecting).toBeVisible();
await expect(this.callParticipantShaking).toBeVisible();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import MainPage from "./MainPage";
import MainPage from "../MainPage";
import { type Locator, type Page } from "@playwright/test";

export class CallSettings extends MainPage {
Expand Down
86 changes: 86 additions & 0 deletions playwright/PageObjects/CallElements/IncomingCall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import MainPage from "../MainPage";
import { type Locator, type Page, expect } from "@playwright/test";

export class IncomingCall extends MainPage {
readonly buttonAcceptVideoIncomingCall: Locator;
readonly buttonAcceptVoiceIncomingCall: Locator;
readonly buttonDeclineIncomingCall: Locator;
readonly incomingCallModal: Locator;
readonly incomingCallProfilePicture: Locator;
readonly incomingCallProfilePictureIdenticon: Locator;
readonly incomingCallProfilePictureImage: Locator;
readonly incomingCallStatus: Locator;
readonly incomingCallStatusIndicator: Locator;
readonly incomingCallUsername: Locator;

constructor(
public readonly page: Page,
public readonly viewport: string,
) {
super(page, viewport);
this.incomingCallModal = this.page.locator("#incoming-call");
this.buttonAcceptVideoIncomingCall = this.incomingCallModal.getByRole(
"button",
{
name: "Video",
},
);
this.buttonAcceptVoiceIncomingCall = this.incomingCallModal.getByRole(
"button",
{
name: "Voice",
},
);
this.buttonDeclineIncomingCall = this.incomingCallModal.getByRole(
"button",
{
name: "Decline",
exact: true,
},
);
this.incomingCallProfilePicture = this.incomingCallModal.getByTestId(
"friend-profile-picture",
);
this.incomingCallProfilePictureIdenticon =
this.incomingCallProfilePicture.locator(".identicon img");
this.incomingCallProfilePictureImage =
this.incomingCallProfilePicture.locator("img");
this.incomingCallStatus = this.incomingCallModal.getByText(
"status from second user",
); // Temporarily hardcoded
this.incomingCallStatusIndicator =
this.incomingCallModal.getByTestId("status-indicator");
this.incomingCallUsername = this.incomingCallModal.getByText("ChatUserB"); // Temporarily hardcoded
}

async acceptAudioIncomingCall() {
await this.buttonAcceptVoiceIncomingCall.click();
}

async acceptVideoIncomingCall() {
await this.buttonAcceptVideoIncomingCall.click();
}

async denyIncomingCall() {
await this.buttonDeclineIncomingCall.click();
}

async validateIncomingCallModal(
username: string,
status: string,
imageSrc: string,
) {
await expect(this.incomingCallUsername).toHaveText(username);
await expect(this.incomingCallStatus).toHaveText(status);
await expect(this.incomingCallStatusIndicator).toHaveClass(
/.*\bonline\b.*/,
);
await expect(this.incomingCallProfilePictureImage).toHaveAttribute(
"src",
imageSrc,
);
await expect(this.buttonAcceptVideoIncomingCall).toBeVisible();
await expect(this.buttonAcceptVoiceIncomingCall).toBeVisible();
await expect(this.buttonDeclineIncomingCall).toBeVisible();
}
}
Loading

0 comments on commit 0b731ec

Please sign in to comment.