Skip to content

Commit

Permalink
test: [POM] fix change language flaky tests and migrate tests to Page…
Browse files Browse the repository at this point in the history
… Object Model (#28777)

## **Description**

- Fix change language flaky tests. There are multiple reasons for the
flakiness, including taking actions during the loading spinner and
excessive misuse of refresh page
- Migrate change language e2e tests to Page Object Model
- Created base pages for advanced settings page and general settings
page
- For some special language-related locators, as they are only used in
this specific test, I didn't migrate them to POM methods.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27155?quickstart=1)

## **Related issues**

Fixes:#27904
#28698
#27390

## **Manual testing steps**
Check code readability, make sure tests pass.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
chloeYue authored Nov 29, 2024
1 parent db4386f commit 5e52a7d
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 76 deletions.
5 changes: 4 additions & 1 deletion test/e2e/page-objects/common.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export type RawLocator = string | { css: string; text: string };
export type RawLocator =
| string
| { css?: string; text?: string }
| { tag: string; text: string };
32 changes: 32 additions & 0 deletions test/e2e/page-objects/pages/settings/advanced-settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Driver } from '../../../webdriver/driver';

class AdvancedSettings {
private readonly driver: Driver;

private readonly downloadDataButton = '[data-testid="export-data-button"]';

private readonly downloadStateLogsButton =
'[data-testid="advanced-setting-state-logs"]';

constructor(driver: Driver) {
this.driver = driver;
}

async check_pageIsLoaded(): Promise<void> {
try {
await this.driver.waitForMultipleSelectors([
this.downloadStateLogsButton,
this.downloadDataButton,
]);
} catch (e) {
console.log(
'Timeout while waiting for Advanced Settings page to be loaded',
e,
);
throw e;
}
console.log('Advanced Settings page is loaded');
}
}

export default AdvancedSettings;
61 changes: 61 additions & 0 deletions test/e2e/page-objects/pages/settings/general-settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Driver } from '../../../webdriver/driver';

class GeneralSettings {
private readonly driver: Driver;

private readonly generalSettingsPageTitle = {
text: 'General',
tag: 'h4',
};

private readonly loadingOverlaySpinner = '.loading-overlay__spinner';

private readonly selectLanguageField = '[data-testid="locale-select"]';

constructor(driver: Driver) {
this.driver = driver;
}

async check_pageIsLoaded(): Promise<void> {
try {
await this.check_noLoadingOverlaySpinner();
await this.driver.waitForMultipleSelectors([
this.generalSettingsPageTitle,
this.selectLanguageField,
]);
} catch (e) {
console.log(
'Timeout while waiting for General Settings page to be loaded',
e,
);
throw e;
}
console.log('General Settings page is loaded');
}

/**
* Change the language of MM on General Settings page
*
* @param languageToSelect - The language to select
*/
async changeLanguage(languageToSelect: string): Promise<void> {
console.log(
'Changing language to ',
languageToSelect,
'on general settings page',
);
await this.check_noLoadingOverlaySpinner();
await this.driver.clickElement(this.selectLanguageField);
await this.driver.clickElement({
text: languageToSelect,
tag: 'option',
});
await this.check_noLoadingOverlaySpinner();
}

async check_noLoadingOverlaySpinner(): Promise<void> {
await this.driver.assertElementNotPresent(this.loadingOverlaySpinner);
}
}

export default GeneralSettings;
153 changes: 78 additions & 75 deletions test/e2e/tests/settings/change-language.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { strict as assert } from 'assert';
import { Suite } from 'mocha';

import { Driver } from '../../webdriver/driver';
import {
defaultGanacheOptions,
withFixtures,
unlockWallet,
} from '../../helpers';
import { withFixtures } from '../../helpers';
import FixtureBuilder from '../../fixture-builder';
import AdvancedSettings from '../../page-objects/pages/settings/advanced-settings';
import GeneralSettings from '../../page-objects/pages/settings/general-settings';
import HeaderNavbar from '../../page-objects/pages/header-navbar';
import Homepage from '../../page-objects/pages/homepage';
import SendTokenPage from '../../page-objects/pages/send/send-token-page';
import SettingsPage from '../../page-objects/pages/settings/settings-page';
import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow';

const selectors = {
accountOptionsMenuButton: '[data-testid="account-options-menu-button"]',
settingsOption: { text: 'Settings', tag: 'div' },
localeSelect: '[data-testid="locale-select"]',
ethOverviewSend: '[data-testid="eth-overview-send"]',
ensInput: '[data-testid="ens-input"]',
nftsTab: '[data-testid="account-overview__nfts-tab"]',
labelSpanish: { tag: 'p', text: 'Idioma actual' },
currentLanguageLabel: { tag: 'p', text: 'Current language' },
advanceText: { text: 'Avanceret', tag: 'div' },
Expand All @@ -29,50 +25,37 @@ const selectors = {
headerText: { text: 'الإعدادات', tag: 'h3' },
};

async function changeLanguage(driver: Driver, languageIndex: number) {
await driver.clickElement(selectors.accountOptionsMenuButton);
await driver.clickElement(selectors.settingsOption);

const dropdownElement = await driver.findElement(selectors.localeSelect);
await dropdownElement.click();

const options = await dropdownElement.findElements({ css: 'option' });
await options[languageIndex].click();
}

describe('Settings - general tab @no-mmi', function (this: Suite) {
it('validate the change language functionality', async function () {
let languageIndex = 10;

await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test?.fullTitle(),
},

async ({ driver }: { driver: Driver }) => {
await unlockWallet(driver);
await changeLanguage(driver, languageIndex);
await loginWithBalanceValidation(driver);
await new HeaderNavbar(driver).openSettingsPage();
const generalSettings = new GeneralSettings(driver);
await generalSettings.check_pageIsLoaded();

// Validate the label changes to Spanish
// Change language to Spanish and validate that the word has changed correctly
await generalSettings.changeLanguage('Español');
const isLanguageLabelChanged = await driver.isElementPresent(
selectors.labelSpanish,
);
assert.equal(isLanguageLabelChanged, true, 'Language did not change');

// Refresh the page and validate that the language is still Spanish
await driver.refresh();

// Change back to English and verify that the word is correctly changed back to English
languageIndex = 9;

const dropdownElement = await driver.findElement(
selectors.localeSelect,
await generalSettings.check_pageIsLoaded();
assert.equal(
await driver.isElementPresent(selectors.labelSpanish),
true,
'Language did not change after refresh',
);
await dropdownElement.click();
const options = await dropdownElement.findElements({ css: 'option' });
await options[languageIndex].click();

// Change language back to English and validate that the word has changed correctly
await generalSettings.changeLanguage('English');
const isLabelTextChanged = await driver.isElementPresent(
selectors.currentLanguageLabel,
);
Expand All @@ -82,21 +65,22 @@ describe('Settings - general tab @no-mmi', function (this: Suite) {
});

it('validate "Dansk" language on page navigation', async function () {
const languageIndex = 6;
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test?.fullTitle(),
},

async ({ driver }: { driver: Driver }) => {
await unlockWallet(driver);
await changeLanguage(driver, languageIndex);

await driver.assertElementNotPresent('.loading-overlay__spinner');
await loginWithBalanceValidation(driver);
await new HeaderNavbar(driver).openSettingsPage();
const generalSettings = new GeneralSettings(driver);
await generalSettings.check_pageIsLoaded();

// Select "Dansk" language
await generalSettings.changeLanguage('Dansk');
await driver.clickElement(selectors.advanceText);
const advancedSettings = new AdvancedSettings(driver);
await advancedSettings.check_pageIsLoaded();

// Confirm that the language change is reflected in search box water text
const isWaterTextChanged = await driver.isElementPresent(
Expand Down Expand Up @@ -132,22 +116,30 @@ describe('Settings - general tab @no-mmi', function (this: Suite) {
});

it('validate "Deutsch" language on error messages', async function () {
const languageIndex = 7;
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test?.fullTitle(),
},

async ({ driver }: { driver: Driver }) => {
await unlockWallet(driver);
await changeLanguage(driver, languageIndex);
await driver.navigate();
await driver.clickElement(selectors.ethOverviewSend);
await driver.pasteIntoField(
selectors.ensInput,
// use wrong checksum address; other inputs don't show error until snaps name-lookup has happened
await loginWithBalanceValidation(driver);
await new HeaderNavbar(driver).openSettingsPage();
const generalSettings = new GeneralSettings(driver);
await generalSettings.check_pageIsLoaded();

// Select "Deutsch" language
await generalSettings.changeLanguage('Deutsch');
await new SettingsPage(driver).closeSettingsPage();

const homepage = new Homepage(driver);
await homepage.check_pageIsLoaded();
await homepage.check_expectedBalanceIsDisplayed();
await homepage.startSendFlow();

const sendToPage = new SendTokenPage(driver);
await sendToPage.check_pageIsLoaded();
// use wrong address for recipient to allow error message to show
await sendToPage.fillRecipient(
'0xAAAA6BF26964aF9D7eEd9e03E53415D37aA96045',
);

Expand All @@ -165,18 +157,23 @@ describe('Settings - general tab @no-mmi', function (this: Suite) {
});

it('validate "मानक हिन्दी" language on tooltips', async function () {
const languageIndex = 19;
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test?.fullTitle(),
},

async ({ driver }: { driver: Driver }) => {
await unlockWallet(driver);
await changeLanguage(driver, languageIndex);
await driver.navigate();
await loginWithBalanceValidation(driver);
await new HeaderNavbar(driver).openSettingsPage();
const generalSettings = new GeneralSettings(driver);
await generalSettings.check_pageIsLoaded();

// Select "मानक हिन्दी" language
await generalSettings.changeLanguage('मानक हिन्दी');
await new SettingsPage(driver).closeSettingsPage();
const homepage = new Homepage(driver);
await homepage.check_pageIsLoaded();
await homepage.check_expectedBalanceIsDisplayed();

// Validate the account tooltip
const isAccountTooltipChanged = await driver.isElementPresent(
Expand All @@ -202,20 +199,24 @@ describe('Settings - general tab @no-mmi', function (this: Suite) {
});

it('validate "Magyar" language change on hypertext', async function () {
const languageIndex = 23;
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test?.fullTitle(),
},

async ({ driver }: { driver: Driver }) => {
await unlockWallet(driver);
// selects "Magyar" language
await changeLanguage(driver, languageIndex);
await driver.navigate();
await driver.clickElement(selectors.nftsTab);
await loginWithBalanceValidation(driver);
await new HeaderNavbar(driver).openSettingsPage();
const generalSettings = new GeneralSettings(driver);
await generalSettings.check_pageIsLoaded();

// Select "Magyar" language
await generalSettings.changeLanguage('Magyar');
await new SettingsPage(driver).closeSettingsPage();
const homepage = new Homepage(driver);
await homepage.check_pageIsLoaded();
await homepage.check_expectedBalanceIsDisplayed();
await homepage.goToNftTab();

// Validate the hypertext
const isHyperTextChanged = await driver.isElementPresent(
Expand All @@ -231,18 +232,20 @@ describe('Settings - general tab @no-mmi', function (this: Suite) {
});

it('validate "العربية" language change on page indent', async function () {
const languageIndex = 1;
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions: defaultGanacheOptions,
title: this.test?.fullTitle(),
},
async ({ driver }: { driver: Driver }) => {
await unlockWallet(driver);
await changeLanguage(driver, languageIndex);
await loginWithBalanceValidation(driver);
await new HeaderNavbar(driver).openSettingsPage();
const generalSettings = new GeneralSettings(driver);
await generalSettings.check_pageIsLoaded();

// Select "العربية" language and validate that the header text has changed
await generalSettings.changeLanguage('العربية');

// Validate the header text
const isHeaderTextChanged = await driver.isElementPresent(
selectors.headerText,
);
Expand Down

0 comments on commit 5e52a7d

Please sign in to comment.