Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QAA] Refactoring layout class #8941

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
160 changes: 71 additions & 89 deletions apps/ledger-live-desktop/tests/component/layout.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,46 @@ export class Layout extends Component {
readonly renderError = this.page.getByTestId("render-error");
readonly appVersion = this.page.getByTestId("app-version");

// portfolio && accounts
readonly totalBalance = this.page.getByTestId("total-balance");

// drawer
// side bar
readonly drawerCollapseButton = this.page.getByTestId("drawer-collapse-button");
readonly drawerPortfolioButton = this.page.getByTestId("drawer-dashboard-button");
private drawerMarketButton = this.page.getByTestId("drawer-market-button");
private drawerAccountsButton = this.page.getByTestId("drawer-accounts-button");
private drawerDiscoverButton = this.page.getByTestId("drawer-catalog-button");
private drawerSendButton = this.page.getByTestId("drawer-send-button");
private drawerReceiveButton = this.page.getByTestId("drawer-receive-button");
private drawerManagerButton = this.page.getByTestId("drawer-manager-button");
private drawerBuycryptoButton = this.page.getByTestId("drawer-exchange-button");
private drawerEarnButton = this.page.getByTestId("drawer-earn-button");
private drawerSwapButton = this.page.getByTestId("drawer-swap-button");
readonly drawerMarketButton = this.page.getByTestId("drawer-market-button");
readonly drawerAccountsButton = this.page.getByTestId("drawer-accounts-button");
readonly drawerDiscoverButton = this.page.getByTestId("drawer-catalog-button");
readonly drawerSendButton = this.page.getByTestId("drawer-send-button");
readonly drawerReceiveButton = this.page.getByTestId("drawer-receive-button");
readonly drawerEarnButton = this.page.getByTestId("drawer-earn-button");
readonly drawerBuycryptoButton = this.page.getByTestId("drawer-exchange-button");
readonly drawerSwapButton = this.page.getByTestId("drawer-swap-button");
readonly drawerExperimentalButton = this.page.getByTestId("drawer-experimental-button");
private bookmarkedAccountsList = this.page.getByTestId("drawer-bookmarked-accounts");
readonly bookmarkedAccounts = this.bookmarkedAccountsList.locator(".bookmarked-account-item");
readonly inputWarning = this.page.locator("id=input-warning");
readonly drawerManagerButton = this.page.getByTestId("drawer-manager-button");
readonly bookmarkedAccounts = this.page
.getByTestId("drawer-bookmarked-accounts")
.locator(".bookmarked-account-item");

// topbar
private topbarDiscreetButton = this.page.getByTestId("topbar-discreet-button");
readonly topbarDiscreetButton = this.page.getByTestId("topbar-discreet-button");
readonly topbarSynchronizeButton = this.page.getByTestId("topbar-synchronize-button");
private topbarSettingsButton = this.page.getByTestId("topbar-settings-button");
readonly topbarSettingsButton = this.page.getByTestId("topbar-settings-button");
readonly topbarLockButton = this.page.getByTestId("topbar-password-lock-button");
readonly topbarHelpButton = this.page.getByTestId("topbar-help-button");
private discreetTooltip = this.page.locator("#tippy-12"); // automatically generated tippy id but it's consistent
readonly discreetTooltip = this.page.locator("#tippy-12"); // automatically generated tippy id but it's consistent

// general
readonly inputError = this.page.locator("id=input-error"); // no data-testid because css style is applied
readonly insufficientFundsWarning = this.page.getByTestId("insufficient-funds-warning");
readonly logo = this.page.getByTestId("logo");
readonly marketPerformanceWidget = this.page.getByTestId("market-performance-widget");

// updater
readonly appUpdateBanner = this.page.getByTestId("layout-app-update-banner");
// }

readonly marketPerformanceWidget = this.page.getByTestId("market-performance-widget");
@step("Close side bar")
async closeSideBar() {
await this.drawerCollapseButton.click();
}

@step("Go to Experimental Features")
async goToExperimentalFeatures() {
await this.drawerExperimentalButton.click();
}

@step("Go to Portfolio")
async goToPortfolio() {
Expand All @@ -55,109 +57,89 @@ export class Layout extends Component {
await this.drawerMarketButton.click();
}

@step("Check input error state visibibility: $0")
async checkInputErrorVisibibility(expectedState: "visible" | "hidden") {
await this.inputError.waitFor({ state: expectedState });
}

@step("synchronize accounts")
async syncAccounts() {
await this.topbarSynchronizeButton.click();
}

@step("Wait for accounts sync to be finished")
async waitForAccountsSyncToBeDone() {
await expect(this.topbarSynchronizeButton).not.toHaveText("Synchronizing");
}

@step("Open Accounts")
async goToAccounts() {
await this.drawerAccountsButton.click();
}

@step("Wait for balance to be visible")
async expectBalanceVisibility() {
await this.totalBalance.waitFor({ state: "visible" });
}

@step("Go to discover")
async goToDiscover() {
await this.drawerDiscoverButton.click();
}

@step("Go to manager")
async goToManager() {
await this.drawerManagerButton.click();
@step("Open send modal")
async openSendModalFromSideBar() {
await this.drawerSendButton.click();
}

@step("Go to buy crypto")
async goToBuyCrypto() {
await this.drawerBuycryptoButton.click();
@step("Open receive modal")
async openReceiveModalFromSideBar() {
await this.drawerReceiveButton.click();
}

@step("Go to earn")
async goToEarn() {
await this.drawerEarnButton.click();
}

async toggleDiscreetMode() {
await this.topbarDiscreetButton.click();
await this.discreetTooltip.waitFor({ state: "hidden" }); // makes sure the tooltip has disappeared to prevent flakiness
@step("Go to buy crypto")
async goToBuySellCrypto() {
await this.drawerBuycryptoButton.click();
}

@step("Go to swap")
async goToSwap() {
await this.drawerSwapButton.click();
}

@step("Go to manager")
async goToManager() {
await this.drawerManagerButton.click();
}

@step("Go to Settings")
async goToSettings() {
await this.topbarSettingsButton.click();
}

@step("Check warning message")
async checkAmoutWarningMessage(expectedWarningMessage: RegExp) {
if (expectedWarningMessage !== null) {
await expect(this.insufficientFundsWarning).toBeVisible();
const warningText = await this.insufficientFundsWarning.innerText();
expect(warningText).toMatch(expectedWarningMessage);
}
@step("synchronize accounts")
async syncAccounts() {
await this.topbarSynchronizeButton.click();
}

@step("Wait for accounts sync to be finished")
async waitForAccountsSyncToBeDone() {
await expect(this.topbarSynchronizeButton).not.toHaveText("Synchronizing");
}

@step("Toggle discreet mode")
async toggleDiscreetMode() {
await this.topbarDiscreetButton.click();
await this.discreetTooltip.waitFor({ state: "hidden" }); // makes sure the tooltip has disappeared to prevent flakiness
}

@step("Check warning message")
async checkInputWarningMessage(expectedWarningMessage: string | null) {
if (expectedWarningMessage !== null) {
await expect(this.inputWarning).toBeVisible();
const warningText = await this.inputWarning.innerText();
expect(warningText).toMatch(expectedWarningMessage);
}
@step("Expect top bar lock button to be visible")
async expectTopBarLockButtonToBeVisible() {
await expect(this.topbarLockButton).toBeVisible();
}

@step("Check if the error message is the same as expected")
async checkErrorMessage(errorMessage: string | null) {
if (errorMessage !== null) {
await this.inputError.waitFor({ state: "visible" });
const errorText: any = await this.inputError.textContent();
const normalize = (str: string) => str.replace(/\u00A0/g, " ").trim();
expect(normalize(errorText)).toEqual(normalize(errorMessage));
}
@step("Expect top bar lock button not to be visible")
async expectTopBarLockButtonNotToBeVisible() {
await expect(this.topbarLockButton).not.toBeVisible();
}

@step("Lock app")
async lockApp() {
async lockAppFromTopBar() {
await this.topbarLockButton.click();
}

@step("Open send modal")
async openSendModal() {
await this.drawerSendButton.click();
}

@step("Open receive modal")
async openReceiveModal() {
await this.drawerReceiveButton.click();
@step("open Help")
async openHelp() {
await this.topbarHelpButton.click();
}

@step("wait for loading spinner to have disappeared")
async waitForLoadingSpinnerToHaveDisappeared() {
await this.loadingSpinner.waitFor({ state: "detached" });
}

@step("Go to swap")
async goToSwap() {
await this.drawerSwapButton.click();
}
}
13 changes: 13 additions & 0 deletions apps/ledger-live-desktop/tests/page/lockscreen.page.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { AppPage } from "tests/page/abstractClasses";
import { step } from "tests/misc/reporters/step";

export class LockscreenPage extends AppPage {
readonly container = this.page.getByTestId("lockscreen-container");
private passwordInput = this.page.getByTestId("lockscreen-password-input");
private forgottenButton = this.page.getByTestId("lockscreen-forgotten-button");
private loginButton = this.page.getByTestId("lockscreen-login-button");
readonly inputError = this.page.locator("id=input-error"); // no data-testid because css style is applied
readonly logo = this.page.getByTestId("logo");

async login(password: string) {
await this.container.waitFor({ state: "visible" });
Expand All @@ -15,4 +18,14 @@ export class LockscreenPage extends AppPage {
async lostPassword() {
await this.forgottenButton.click();
}

@step("Check input error state visibibility: $0")
async checkInputErrorVisibility(expectedState: "visible" | "hidden") {
await this.inputError.waitFor({ state: expectedState });
}

@step("Expect Ledger Logo to be visible")
async expectLogoToBeVisible() {
await this.logo.waitFor({ state: "visible" });
}
}
37 changes: 37 additions & 0 deletions apps/ledger-live-desktop/tests/page/modal/send.modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export class SendModal extends Modal {
private noTagButton = this.page.getByRole("button", { name: "Don’t add Tag" });
private ENSAddressLabel = this.page.getByTestId("ens-address-sendModal");

readonly inputError = this.page.locator("id=input-error"); // no data-testid because css style is applied
readonly insufficientFundsWarning = this.page.getByTestId("insufficient-funds-warning");
readonly inputWarning = this.page.locator("id=input-warning");

async selectAccount(name: string) {
await this.drowdownAccount.click();
await this.page.getByText(name).click();
Expand Down Expand Up @@ -144,4 +148,37 @@ export class SendModal extends Modal {
await this.cryptoAmountField.fill(amount);
}
}

@step("Check input error state visibibility: $0")
async checkInputErrorVisibility(expectedState: "visible" | "hidden") {
await this.inputError.waitFor({ state: expectedState });
}

@step("Check if the error message is the same as expected")
async checkErrorMessage(errorMessage: string | null) {
if (errorMessage !== null) {
await this.inputError.waitFor({ state: "visible" });
const errorText: any = await this.inputError.textContent();
const normalize = (str: string) => str.replace(/\u00A0/g, " ").trim();
expect(normalize(errorText)).toEqual(normalize(errorMessage));
}
}

@step("Check warning message")
async checkAmountWarningMessage(expectedWarningMessage: RegExp) {
if (expectedWarningMessage !== null) {
await expect(this.insufficientFundsWarning).toBeVisible();
const warningText = await this.insufficientFundsWarning.innerText();
expect(warningText).toMatch(expectedWarningMessage);
}
}

@step("Check warning message")
async checkInputWarningMessage(expectedWarningMessage: string | null) {
if (expectedWarningMessage !== null) {
await expect(this.inputWarning).toBeVisible();
const warningText = await this.inputWarning.innerText();
expect(warningText).toMatch(expectedWarningMessage);
}
}
}
5 changes: 5 additions & 0 deletions apps/ledger-live-desktop/tests/page/portfolio.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,9 @@ export class PortfolioPage extends AppPage {
const operationRow = this.operationRows.first();
await expect(operationRow).toContainText(counterValue);
}

@step("Wait for balance to be visible")
async expectBalanceVisibility() {
await this.totalBalance.waitFor({ state: "visible" });
VicAlbr marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ test.describe.parallel("Accounts @smoke", () => {

await test.step(`[${currency}] Done`, async () => {
await addAccountModal.done();
await layout.totalBalance.waitFor({ state: "visible" });
await portfolioPage.expectTotalBalanceToBeVisible();
});

await test.step(`Navigate to first account`, async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test("accounts are restored on an encrypted app.json", async ({ page }) => {
const layout = new Layout(page);
const lockscreenPage = new LockscreenPage(page);
await lockscreenPage.login("bad password");
await layout.inputError.waitFor({ state: "visible" });
await lockscreenPage.checkInputErrorVisibility("visible");
await lockscreenPage.login("foobar");
await layout.goToAccounts();
const accountsPage = new AccountsPage(page);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ test("Countervalues: at least one call is made and successful to the API", async
});
});

await layout.topbarSynchronizeButton.click();
await layout.syncAccounts();

expect(await firstSuccessfulQuery).toBeDefined();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ test("Send flow", async ({ page }) => {
const sendModal = new SendModal(page);

await test.step("can open send modal and use a qr code from camera", async () => {
await layout.openSendModal();
await layout.openSendModalFromSideBar();
await sendModal.container.waitFor({ state: "visible" });
const sendButtonLoader = sendModal.container
.locator("id=send-recipient-continue-button")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ test("Send flow", async ({ page }) => {
const sendModal = new SendModal(page);

await test.step("can open send modal and max network fees label is shown", async () => {
await layout.openSendModal();
await layout.openSendModalFromSideBar();
await sendModal.container.waitFor({ state: "visible" });
const sendButtonLoader = sendModal.container
.locator("id=send-recipient-continue-button")
Expand Down
Loading
Loading