From 613c1bc5190bc29cdda54d7e4aa722955e2b3867 Mon Sep 17 00:00:00 2001 From: Martin Vere Cihlar Date: Fri, 6 Dec 2024 18:53:39 +0100 Subject: [PATCH 1/5] feat(e2e): Convert coins.test.ts from cy to pw minor refactoring some verification commented out and will be part of future refactoring --- .../e2e/playwright.config.ts | 2 +- .../e2e/support/customMatchers.ts | 26 ++++ .../e2e/support/fixtures.ts | 3 +- .../support/pageActions/settingsActions.ts | 9 +- .../e2e/tests/settings/coins.test.ts | 113 +++++++++++++++ .../e2e/tests/settings/coins.test.ts | 133 ------------------ 6 files changed, 147 insertions(+), 139 deletions(-) create mode 100644 packages/suite-desktop-core/e2e/support/customMatchers.ts create mode 100644 packages/suite-desktop-core/e2e/tests/settings/coins.test.ts delete mode 100644 packages/suite-web/e2e/tests/settings/coins.test.ts diff --git a/packages/suite-desktop-core/e2e/playwright.config.ts b/packages/suite-desktop-core/e2e/playwright.config.ts index 80bc55de55b..3ce863e1669 100644 --- a/packages/suite-desktop-core/e2e/playwright.config.ts +++ b/packages/suite-desktop-core/e2e/playwright.config.ts @@ -34,7 +34,7 @@ const config: PlaywrightTestConfig = { reporter: process.env.GITHUB_ACTION ? [['list'], ['@currents/playwright'], ['html', { open: 'never' }]] : [['list'], ['html', { open: 'never' }]], - timeout: 1000 * 60 * 5, + timeout: 1000 * 60 * 1, outputDir: path.join(__dirname, 'test-results'), }; diff --git a/packages/suite-desktop-core/e2e/support/customMatchers.ts b/packages/suite-desktop-core/e2e/support/customMatchers.ts new file mode 100644 index 00000000000..abd004213c6 --- /dev/null +++ b/packages/suite-desktop-core/e2e/support/customMatchers.ts @@ -0,0 +1,26 @@ +import { Locator , expect as baseExpect } from '@playwright/test'; + +export const expect = baseExpect.extend({ + async toBeEnabledCoin(locator: Locator) { + const isActive = await locator.getAttribute('data-active'); + + return { + pass: isActive === 'true', + message: () => + isActive === null + ? `expected ${locator} to have attribute 'data-active', but it does not have this attribute at all` + : `expected ${locator} to have attribute 'data-active' set to 'true', but got '${isActive}'`, + }; + }, + async toBeDisabledCoin(locator: Locator) { + const isActive = await locator.getAttribute('data-active'); + + return { + pass: isActive === 'false', + message: () => + isActive === null + ? `expected ${locator} to have attribute 'data-active', but it does not have this attribute at all` + : `expected ${locator} to have attribute 'data-active' set to 'false', but got '${isActive}'`, + }; + }, +}); diff --git a/packages/suite-desktop-core/e2e/support/fixtures.ts b/packages/suite-desktop-core/e2e/support/fixtures.ts index 4500e15088c..55b1537ea1a 100644 --- a/packages/suite-desktop-core/e2e/support/fixtures.ts +++ b/packages/suite-desktop-core/e2e/support/fixtures.ts @@ -1,5 +1,4 @@ /* eslint-disable react-hooks/rules-of-hooks */ - import { test as base, ElectronApplication, Page } from '@playwright/test'; import { @@ -115,4 +114,4 @@ const test = base.extend({ }); export { test }; -export { expect } from '@playwright/test'; +export { expect } from './customMatchers'; diff --git a/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts b/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts index ccf20402d98..49b3f95a00d 100644 --- a/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts +++ b/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts @@ -1,7 +1,10 @@ -import { expect, Locator, Page } from '@playwright/test'; +import { Locator, Page } from '@playwright/test'; import { BackendType, NetworkSymbol } from '@suite-common/wallet-config'; +import { expect } from '../customMatchers'; + + export class SettingsActions { private readonly window: Page; private readonly TIMES_CLICK_TO_SET_DEBUG_MODE = 5; @@ -79,12 +82,12 @@ export class SettingsActions { async enableCoin(coin: NetworkSymbol) { await this.coinNetworkButton(coin).click(); - await expect(this.coinNetworkButton(coin)).toHaveAttribute('data-active', 'true'); + await expect(this.coinNetworkButton(coin)).toBeEnabledCoin(); } async disableCoin(coin: NetworkSymbol) { await this.coinNetworkButton(coin).click(); - await expect(this.coinNetworkButton(coin)).toHaveAttribute('data-active', 'false'); + await expect(this.coinNetworkButton(coin)).toBeDisabledCoin(); } async changeCoinBackend(backend: BackendType, backendUrl: string) { diff --git a/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts b/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts new file mode 100644 index 00000000000..6e0f51962ec --- /dev/null +++ b/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts @@ -0,0 +1,113 @@ +import { SuiteAnalyticsEvent } from '@trezor/suite-analytics'; +import { Requests, EventPayload } from '@trezor/suite-web/e2e/support/types'; +import { urlSearchParams } from '@trezor/suite/src/utils/suite/metadata'; +import { NetworkSymbol } from '@suite-common/wallet-config'; + +import { test, expect } from '../../support/fixtures'; + +//TODO: #15811 To be refactored +export const findAnalyticsEventByType = ( + requests: Requests, + eventType: T['type'], +) => { + const event = requests.find(req => req.c_type === eventType) as EventPayload; + + if (!event) { + throw new Error(`Event with type ${eventType} not found.`); + } + + return event; +}; + +let requests: Requests; + +test.describe('Coin Settings', { tag: ['@group=settings'] }, () => { + test.use({ emulatorStartConf: { wipe: true } }); + test.beforeEach(async ({ onboardingPage, settingsPage }) => { + await onboardingPage.completeOnboarding(); + await settingsPage.navigateTo(); + await settingsPage.coinsTabButton.click(); + + requests = []; + + //TODO: #15811 To be refactored + await onboardingPage.window.route('**://data.trezor.io/suite/log/**', route => { + const url = route.request().url(); + const params = urlSearchParams(url); + requests.push(params); + route.continue(); + }); + }); + + test('go to wallet settings page, check BTC, activate all coins, deactivate all coins, set custom backend', async ({ + dashboardPage, + settingsPage, + window: page, + }) => { + const defaultUnchecked: NetworkSymbol[] = [ + 'ltc', + 'eth', + 'etc', + 'xrp', + 'bch', + 'btg', + 'dash', + 'dgb', + 'doge', + 'nmc', + 'vtc', + 'zec', + 'ada', + 'sol', + 'test', + 'tsep', + 'thol', + 'txrp', + 'tada', + 'dsol', + ]; + + await expect(settingsPage.coinNetworkButton('btc')).toBeEnabledCoin(); + for (const network of defaultUnchecked) { + await expect(settingsPage.coinNetworkButton(network)).toBeDisabledCoin(); + } + + await settingsPage.disableCoin('btc'); + + // check dashboard with all coins disabled + await dashboardPage.navigateTo(); + await page.pause(); + // check that there is no assets grid + await expect(page.getByTestId('@dashboard/wallet-ready')).toContainText( + 'Your wallet is ready to use!', + ); + + await settingsPage.navigateTo(); + await settingsPage.coinsTabButton.click(); + // just do some clicking on switches and check result + for (const network of ['btc', ...defaultUnchecked] as NetworkSymbol[]) { + await settingsPage.enableCoin(network); + } + + //TODO: #15811 this is just not useful validation. To be refactored + // const settingsCoinsEvent = findAnalyticsEventByType< + // ExtractByEventType + // >(requests, EventType.SettingsCoins); + // expect(settingsCoinsEvent.symbol).to.be.oneOf(['btc', ...defaultUnchecked]); + // expect(settingsCoinsEvent.value).to.be.oneOf(['true', 'false']); + + // custom eth backend + await page.getByTestId('@settings/wallet/network/eth/advance').click(); + await page.getByTestId('@settings/advance/select-type/input').click(); + await page.getByTestId('@settings/advance/select-type/option/blockbook').click(); + // sometimes select stays open after click, no idea why, experimenting with wait + await page.getByTestId('@settings/advance/url').fill('https://eth.marek.pl/'); + await page.getByTestId('@settings/advance/button/save').click(); + + //TODO: #15811 this is just not useful validation. To be refactored + // const settingsCoinsBackendEvent = findAnalyticsEventByType>(requests, EventType.SettingsCoinsBackend) + // expect(settingsCoinsBackendEvent.type).to.equal('blockbook'); + // expect(settingsCoinsBackendEvent.totalRegular).to.equal('1'); + // expect(settingsCoinsBackendEvent.totalOnion).to.equal('0'); + }); +}); diff --git a/packages/suite-web/e2e/tests/settings/coins.test.ts b/packages/suite-web/e2e/tests/settings/coins.test.ts deleted file mode 100644 index 84827cc992a..00000000000 --- a/packages/suite-web/e2e/tests/settings/coins.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -// @group_settings -// @retry=2 - -import { EventType } from '@trezor/suite-analytics'; - -import { ExtractByEventType, Requests } from '../../support/types'; -import { onNavBar } from '../../support/pageObjects/topBarObject'; - -let requests: Requests; - -describe('Coin Settings', () => { - beforeEach(() => { - cy.task('startEmu', { wipe: true }); - cy.task('setupEmu'); - cy.task('startBridge'); - cy.viewport('macbook-13').resetDb(); - cy.prefixedVisit('/'); - cy.passThroughInitialRun(); - - requests = []; - cy.interceptDataTrezorIo(requests); - }); - - it('go to wallet settings page, check BTC, activate all coins, deactivate all coins, set custom backend', () => { - const defaultUnchecked = [ - 'ltc', - 'eth', - 'etc', - 'xrp', - 'bch', - 'btg', - 'dash', - 'dgb', - 'doge', - 'nmc', - 'vtc', - 'zec', - 'ada', - // 'sol', FIXME: disabled till available in trezor-user-env - 'test', - 'tsep', - 'thol', - 'txrp', - 'tada', - // 'dsol', FIXME: disabled till available in trezor-user-env - ]; - - onNavBar.openSettings(); - cy.getTestElement('@settings/menu/wallet').click(); - - // only btc is selected by default; - cy.getTestElement('@settings/wallet/network/btc').should( - 'have.attr', - 'data-active', - 'true', - ); - - // other coins are not selected - defaultUnchecked.forEach(network => { - cy.getTestElement(`@settings/wallet/network/${network}`).should( - 'have.attr', - 'data-active', - 'false', - ); - }); - - // // this helps with unstable click to btc - cy.contains('span', 'Got it!').should('be.visible').click({ scrollBehavior: 'bottom' }); - cy.wait(500); - // disable Bitcoin - cy.getTestElement('@settings/wallet/network/btc').click(); - cy.getTestElement('@settings/wallet/network/btc').should( - 'have.attr', - 'data-active', - 'false', - ); - // check dashboard with all coins disabled - cy.getTestElement('@suite/menu/suite-index').click(); - - // check that there is no assets grid - cy.get('[class^="AssetsView__Grid"] > [class^="Card"]').should('not.exist'); - - onNavBar.openSettings(); - cy.getTestElement('@settings/menu/wallet').click(); - // just do some clicking on switches and check result - ['btc', ...defaultUnchecked].forEach(network => { - cy.getTestElement(`@settings/wallet/network/${network}`).should( - 'have.attr', - 'data-active', - 'false', - ); - }); - - ['btc', ...defaultUnchecked].forEach(network => { - cy.getTestElement(`@settings/wallet/network/${network}`).click({ force: true }); - }); - - ['btc', ...defaultUnchecked].forEach(network => { - cy.getTestElement(`@settings/wallet/network/${network}`).should( - 'have.attr', - 'data-active', - 'true', - ); - }); - - cy.findAnalyticsEventByType>( - requests, - EventType.SettingsCoins, - ).then(settingsCoinsEvent => { - expect(settingsCoinsEvent.symbol).to.be.oneOf(['btc', ...defaultUnchecked]); - expect(settingsCoinsEvent.value).to.be.oneOf(['true', 'false']); - }); - - // custom eth backend - cy.getTestElement('@settings/wallet/network/eth/advance').click(); - cy.getTestElement('@settings/advance/select-type/input').click(); - cy.getTestElement('@settings/advance/select-type/option/blockbook').click(); - // sometimes select stays open after click, no idea why, experimenting with wait - cy.wait(100); - cy.getTestElement('@settings/advance/url').type('https://eth.marek.pl/'); - cy.getTestElement('@settings/advance/button/save').click(); - - cy.findAnalyticsEventByType>( - requests, - EventType.SettingsCoinsBackend, - ).then(settingsCoinsBackendEvent => { - expect(settingsCoinsBackendEvent.symbol).to.equal('eth'); - expect(settingsCoinsBackendEvent.type).to.equal('blockbook'); - expect(settingsCoinsBackendEvent.totalRegular).to.equal('1'); - expect(settingsCoinsBackendEvent.totalOnion).to.equal('0'); - }); - }); -}); From 40420f4188514bfded533f679b2e074fcf138321 Mon Sep 17 00:00:00 2001 From: Martin Vere Cihlar Date: Mon, 9 Dec 2024 11:11:24 +0100 Subject: [PATCH 2/5] feat(e2e): Convert cy test file custom-firmware.test.ts to PW --- .../e2e/fixtures/trezor-2.5.1.bin | Bin .../support/pageActions/settingsActions.ts | 3 +- .../tests/settings/custom-firmware.test.ts | 35 ++++++++++ .../tests/settings/custom-firmware.test.ts | 64 ------------------ .../firmware/SelectCustomFirmware.tsx | 11 ++- 5 files changed, 45 insertions(+), 68 deletions(-) rename packages/{suite-web => suite-desktop-core}/e2e/fixtures/trezor-2.5.1.bin (100%) create mode 100644 packages/suite-desktop-core/e2e/tests/settings/custom-firmware.test.ts delete mode 100644 packages/suite-web/e2e/tests/settings/custom-firmware.test.ts diff --git a/packages/suite-web/e2e/fixtures/trezor-2.5.1.bin b/packages/suite-desktop-core/e2e/fixtures/trezor-2.5.1.bin similarity index 100% rename from packages/suite-web/e2e/fixtures/trezor-2.5.1.bin rename to packages/suite-desktop-core/e2e/fixtures/trezor-2.5.1.bin diff --git a/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts b/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts index 49b3f95a00d..294efddc2c3 100644 --- a/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts +++ b/packages/suite-desktop-core/e2e/support/pageActions/settingsActions.ts @@ -4,7 +4,6 @@ import { BackendType, NetworkSymbol } from '@suite-common/wallet-config'; import { expect } from '../customMatchers'; - export class SettingsActions { private readonly window: Page; private readonly TIMES_CLICK_TO_SET_DEBUG_MODE = 5; @@ -59,7 +58,7 @@ export class SettingsActions { async navigateTo() { await this.settingsMenuButton.click(); - await expect(this.settingsHeader).toHaveText('Settings'); + await expect(this.settingsHeader).toHaveText('Settings', { timeout: 10000 }); } async toggleDebugModeInSettings() { diff --git a/packages/suite-desktop-core/e2e/tests/settings/custom-firmware.test.ts b/packages/suite-desktop-core/e2e/tests/settings/custom-firmware.test.ts new file mode 100644 index 00000000000..c96e241d453 --- /dev/null +++ b/packages/suite-desktop-core/e2e/tests/settings/custom-firmware.test.ts @@ -0,0 +1,35 @@ +import path from 'node:path'; + +import { test, expect } from '../../support/fixtures'; + +const firmwarePath = path.join(__dirname, '../../fixtures/trezor-2.5.1.bin'); + +test.describe('Custom firmware', { tag: ['@group=settings'] }, () => { + test.use({ emulatorStartConf: { wipe: true } }); + test.beforeEach(async ({ onboardingPage, settingsPage }) => { + await onboardingPage.completeOnboarding(); + await settingsPage.navigateTo(); + await settingsPage.deviceTabButton.click(); + }); + + test('Custom firmware installation', async ({ window: page }) => { + await test.step('Start `Install firmware` flow', async () => { + await page.getByTestId('@settings/device/custom-firmware-modal-button').click(); + await expect(page.getByTestId('@firmware-modal/install-button')).toBeDisabled(); + }); + + await test.step('Select the custom firmware', async () => { + const fileChooserPromise = page.waitForEvent('filechooser'); + await page.getByTestId('@firmware-modal/input-area').click(); + const fileChooser = await fileChooserPromise; + await fileChooser.setFiles(firmwarePath); + }); + + await test.step('Complete the FW installation on the device', async () => { + await page.getByTestId('@firmware-modal/install-button').click(); + await page.getByTestId('@firmware/confirm-seed-checkbox').click(); + await page.getByTestId('@firmware/confirm-seed-button').click(); + await expect(page.getByTestId('@firmware/reconnect-device')).toBeVisible(); + }); + }); +}); diff --git a/packages/suite-web/e2e/tests/settings/custom-firmware.test.ts b/packages/suite-web/e2e/tests/settings/custom-firmware.test.ts deleted file mode 100644 index b4cb42ab939..00000000000 --- a/packages/suite-web/e2e/tests/settings/custom-firmware.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -// @group_settings - -import { onNavBar } from '../../support/pageObjects/topBarObject'; - -// @retry=2 -describe('Install custom firmware', () => { - beforeEach(() => { - cy.task('startEmu', { wipe: true }); - cy.task('setupEmu'); - cy.task('startBridge'); - cy.viewport(1920, 1080).resetDb(); - cy.prefixedVisit('/'); - cy.passThroughInitialRun(); - cy.discoveryShouldFinish(); - }); - - /* - * 1. Navigate to `Settings/Device` - * 2. Click on `Install firmware` - * 3. Select the custom firmware - * 4. Complete the FW instalation on the device - */ - //TODO: skipped due to #13926 - it('go to device settings and check if custom FW modal appears', () => { - // - // Test preparation - // - const testBinFile = 'trezor-2.5.1.bin'; - - onNavBar.openSettings(); - cy.getTestElement('@settings/menu/device').click(); - cy.getTestElement('@settings/device/check-seed-button').should('be.visible'); - - cy.getTestElement('@settings/device/custom-firmware-modal-button') - .should('be.enabled') - .click({ - force: true, - }); - // - // Test execution - // - cy.getTestElement('@firmware-modal').then(fileUploadModal => { - cy.wrap(fileUploadModal) - .find('input[type=file]') - .attachFile( - { filePath: testBinFile, encoding: 'binary' }, - { subjectType: 'drag-n-drop' }, - ); - }); - cy.getTestElement('@firmware-modal').then(installFWbutton => { - cy.wrap(installFWbutton) - .find('[class*="Button"]') - .should('not.be.disabled') - .contains('Install firmware') - .click(); - }); - cy.getTestElement('@firmware/confirm-seed-checkbox').click(); - cy.getTestElement('@firmware/confirm-seed-button').click(); - // - // Assert - // - cy.getTestElement('@firmware/reconnect-device').should('be.visible'); - }); -}); diff --git a/packages/suite/src/components/firmware/SelectCustomFirmware.tsx b/packages/suite/src/components/firmware/SelectCustomFirmware.tsx index 38bc670263e..b56ee2c692b 100644 --- a/packages/suite/src/components/firmware/SelectCustomFirmware.tsx +++ b/packages/suite/src/components/firmware/SelectCustomFirmware.tsx @@ -84,10 +84,17 @@ export const SelectCustomFirmware = ({ number="2" title={} > - + + + - + From 868b52ef0af33c5d532bb7547c88115b1fe2d6d2 Mon Sep 17 00:00:00 2001 From: Martin Vere Cihlar Date: Tue, 10 Dec 2024 12:27:09 +0100 Subject: [PATCH 3/5] fix(e2e): Stabilizing new pw tests for desktop adds logic to use correct API url based on web/desktop/local/CI removes flakyness of Coins test --- .../suite-desktop-core/e2e/playwright.config.ts | 6 ++++-- packages/suite-desktop-core/e2e/support/common.ts | 15 ++++++++++++++- .../suite-desktop-core/e2e/support/fixtures.ts | 6 +++++- .../e2e/tests/settings/coins.test.ts | 9 ++++----- .../tests/settings/t2b1-device-settings.test.ts | 4 ++-- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/suite-desktop-core/e2e/playwright.config.ts b/packages/suite-desktop-core/e2e/playwright.config.ts index 3ce863e1669..7c634ae0e9c 100644 --- a/packages/suite-desktop-core/e2e/playwright.config.ts +++ b/packages/suite-desktop-core/e2e/playwright.config.ts @@ -5,6 +5,8 @@ export enum PlaywrightProjects { Web = 'web', Desktop = 'desktop', } +const timeoutCIRun = 1000 * 60; +const timeoutLocalRun = 1000 * 30; const config: PlaywrightTestConfig = { projects: [ @@ -12,7 +14,7 @@ const config: PlaywrightTestConfig = { name: PlaywrightProjects.Web, use: { browserName: 'chromium', - baseURL: process.env.BASE_URL || 'http://localhost:8000', + baseURL: process.env.BASE_URL || 'http://localhost:8000/', }, grepInvert: /@desktopOnly/, }, @@ -34,7 +36,7 @@ const config: PlaywrightTestConfig = { reporter: process.env.GITHUB_ACTION ? [['list'], ['@currents/playwright'], ['html', { open: 'never' }]] : [['list'], ['html', { open: 'never' }]], - timeout: 1000 * 60 * 1, + timeout: process.env.GITHUB_ACTION ? timeoutCIRun : timeoutLocalRun, outputDir: path.join(__dirname, 'test-results'), }; diff --git a/packages/suite-desktop-core/e2e/support/common.ts b/packages/suite-desktop-core/e2e/support/common.ts index 92bce7f1090..52f7e210d3d 100644 --- a/packages/suite-desktop-core/e2e/support/common.ts +++ b/packages/suite-desktop-core/e2e/support/common.ts @@ -1,11 +1,13 @@ /* eslint-disable no-console */ -import { _electron as electron } from '@playwright/test'; +import { _electron as electron, TestInfo } from '@playwright/test'; import path from 'path'; import fse from 'fs-extra'; import { TrezorUserEnvLink } from '@trezor/trezor-user-env-link'; +import { PlaywrightProjects } from '../playwright.config'; + // specific version of legacy bridge is requested & expected export const LEGACY_BRIDGE_VERSION = '2.0.33'; const disableHashCheckArgument = '--state.suite.settings.isFirmwareHashCheckDisabled=true'; @@ -100,3 +102,14 @@ export const launchSuite = async (params: LaunchSuiteParams = {}) => { return { electronApp, window }; }; + +export const getApiUrl = (webBaseUrl: string | undefined, testInfo: TestInfo) => { + const electronApiURL = 'file:///'; + const apiURL = + testInfo.project.name === PlaywrightProjects.Desktop ? electronApiURL : webBaseUrl; + if (!apiURL) { + throw new Error('apiURL is not defined'); + } + + return apiURL; +}; diff --git a/packages/suite-desktop-core/e2e/support/fixtures.ts b/packages/suite-desktop-core/e2e/support/fixtures.ts index 55b1537ea1a..11ca4ae10d5 100644 --- a/packages/suite-desktop-core/e2e/support/fixtures.ts +++ b/packages/suite-desktop-core/e2e/support/fixtures.ts @@ -9,7 +9,7 @@ import { } from '@trezor/trezor-user-env-link'; import { DashboardActions } from './pageActions/dashboardActions'; -import { launchSuite } from './common'; +import { getApiUrl, launchSuite } from './common'; import { SettingsActions } from './pageActions/settingsActions'; import { SuiteGuide } from './pageActions/suiteGuideActions'; import { WalletActions } from './pageActions/walletActions'; @@ -17,6 +17,7 @@ import { OnboardingActions } from './pageActions/onboardingActions'; import { PlaywrightProjects } from '../playwright.config'; type Fixtures = { + apiURL: string; startEmulator: boolean; emulatorStartConf: StartEmu; emulatorSetupConf: SetupEmu; @@ -34,6 +35,9 @@ const test = base.extend({ startEmulator: true, emulatorStartConf: {}, emulatorSetupConf: {}, + apiURL: async ({ baseURL }, use, testInfo) => { + await use(getApiUrl(baseURL, testInfo)); + }, /* eslint-disable-next-line no-empty-pattern */ trezorUserEnvLink: async ({}, use) => { await use(TrezorUserEnvLink); diff --git a/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts b/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts index 6e0f51962ec..07695d8879f 100644 --- a/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts +++ b/packages/suite-desktop-core/e2e/tests/settings/coins.test.ts @@ -23,8 +23,9 @@ let requests: Requests; test.describe('Coin Settings', { tag: ['@group=settings'] }, () => { test.use({ emulatorStartConf: { wipe: true } }); - test.beforeEach(async ({ onboardingPage, settingsPage }) => { + test.beforeEach(async ({ onboardingPage, dashboardPage, settingsPage }) => { await onboardingPage.completeOnboarding(); + await dashboardPage.discoveryShouldFinish(); await settingsPage.navigateTo(); await settingsPage.coinsTabButton.click(); @@ -76,10 +77,8 @@ test.describe('Coin Settings', { tag: ['@group=settings'] }, () => { // check dashboard with all coins disabled await dashboardPage.navigateTo(); - await page.pause(); - // check that there is no assets grid - await expect(page.getByTestId('@dashboard/wallet-ready')).toContainText( - 'Your wallet is ready to use!', + expect(page.getByTestId('@exception/discovery-empty')).toContainText( + 'All coins are disabled in Settings.', ); await settingsPage.navigateTo(); diff --git a/packages/suite-desktop-core/e2e/tests/settings/t2b1-device-settings.test.ts b/packages/suite-desktop-core/e2e/tests/settings/t2b1-device-settings.test.ts index 5d623bd5741..69d911a2189 100644 --- a/packages/suite-desktop-core/e2e/tests/settings/t2b1-device-settings.test.ts +++ b/packages/suite-desktop-core/e2e/tests/settings/t2b1-device-settings.test.ts @@ -28,7 +28,7 @@ test.describe.serial('T2B1 - Device settings', { tag: ['@group=settings'] }, () test('change all possible device settings', async ({ trezorUserEnvLink, window: page, - baseURL, + apiURL, }) => { const newDeviceName = 'TREVOR!'; @@ -49,7 +49,7 @@ test.describe.serial('T2B1 - Device settings', { tag: ['@group=settings'] }, () // change background // On Web the there is instability, Playwright keeps clicking the button too soon. const buttonImageLoad = page.waitForResponse( - `${baseURL}static/images/homescreens/BW_64x128/circleweb.png`, + `${apiURL}static/images/homescreens/BW_64x128/circleweb.png`, ); await page.getByTestId('@settings/device/homescreen-gallery').click(); await buttonImageLoad; From 2ce744cda16cb517095dcede78bbbad27f081b73 Mon Sep 17 00:00:00 2001 From: Martin Vere Cihlar Date: Tue, 10 Dec 2024 12:58:02 +0100 Subject: [PATCH 4/5] refactor(e2e): #15868 Refactor desktop e2e test pipeline better matrix move docker pull from tests step to improve readability pull only what is need Attach playwright report for devs who dont have currents add --forbid-only to both pipelines --- .github/workflows/test-suite-desktop-e2e.yml | 81 +++++++++++--------- .github/workflows/test-suite-web-e2e-pw.yml | 27 +++---- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/.github/workflows/test-suite-desktop-e2e.yml b/.github/workflows/test-suite-desktop-e2e.yml index bd76b541cec..38336386e28 100644 --- a/.github/workflows/test-suite-desktop-e2e.yml +++ b/.github/workflows/test-suite-desktop-e2e.yml @@ -27,10 +27,20 @@ jobs: fail-fast: false matrix: include: - - TEST_FILE: "spawn-bridge spawn-bridge-daemon suite-guide wallet-discovery" + # - TEST_GROUP: "@group=suite" + # CONTAINERS: "trezor-user-env-unix" + # - TEST_GROUP: "@group=device-management" + # CONTAINERS: "trezor-user-env-unix" + - TEST_GROUP: "@group=settings" CONTAINERS: "trezor-user-env-unix" - - TEST_FILE: "electrum" - CONTAINERS: "trezor-user-env-unix electrum-regtest" + # - TEST_GROUP: "@group=metadata" + # CONTAINERS: "trezor-user-env-unix" + # - TEST_GROUP: "@group=passphrase" + # CONTAINERS: "trezor-user-env-unix" + # - TEST_GROUP: "@group=other" + # CONTAINERS: "trezor-user-env-unix" + - TEST_GROUP: "@group=wallet" + CONTAINERS: "trezor-user-env-unix bitcoin-regtest" steps: - name: Checkout @@ -38,67 +48,66 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - name: Run and store git values for Currents - run: | - echo "COMMIT_MESSAGE=$(git show -s --pretty=%s)" >> $GITHUB_ENV - echo "COMMIT_EMAIL=$(git show -s --pretty=%ae)" >> $GITHUB_ENV - echo "COMMIT_AUTHOR=$(git show -s --pretty=%an)" >> $GITHUB_ENV - echo "COMMIT_SHA=$(git show -s --pretty=%H)" >> $GITHUB_ENV - echo "COMMIT_TIMESTAMP=$(git show -s --pretty=%ct)" >> $GITHUB_ENV - - name: Setup node uses: actions/setup-node@v4 with: node-version-file: ".nvmrc" cache: yarn - - name: Install deps and build libs + - name: Install dependencies, build libs and pull docker images + env: + COMPOSE_FILE: ./docker/docker-compose.suite-desktop-ci.yml run: | yarn install --immutable yarn message-system-sign-config yarn workspace @trezor/suite-data build:lib yarn workspace @trezor/transport-bridge build:lib + docker compose pull ${{ matrix.CONTAINERS }} - - name: Build app.js for tests + - name: Build electron app.js for tests run: | yarn workspace @trezor/suite-desktop build:app yarn workspace @trezor/suite-desktop build:ui - - name: Run e2e desktop tests + - name: Run Playwright e2e desktop tests env: - GITHUB_WORKFLOW: ${{github.workflow}} + COMPOSE_FILE: ./docker/docker-compose.suite-desktop-ci.yml GITHUB_ACTION: true - GITHUB_EVENT_NAME: ${{github.event_name}} - GITHUB_RUN_ID: ${{github.run_id}} - GITHUB_RUN_ATTEMPT: ${{github.run_attempt}} - GITHUB_REPOSITORY: ${{github.repository}} - COMMIT_INFO_BRANCH: ${{github.head_ref}} - COMMIT_INFO_MESSAGE: ${{env.COMMIT_MESSAGE}} - COMMIT_INFO_EMAIL: ${{env.COMMIT_EMAIL}} - COMMIT_INFO_AUTHOR: ${{env.COMMIT_AUTHOR}} - COMMIT_INFO_SHA: ${{env.COMMIT_SHA}} - COMMIT_INFO_TIMESTAMP: ${{env.COMMIT_TIMESTAMP}} - COMMIT_INFO_REMOTE: ${{github.repository}} CURRENTS_PROJECT_ID: 4ytF0E CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} CURRENTS_CI_BUILD_ID: pr-run-${{github.run_id}} - COMPOSE_FILE: ./docker/docker-compose.suite-desktop-ci.yml - TEST_FILE: ${{ matrix.TEST_FILE }} run: | - docker compose pull docker compose up -d ${{ matrix.CONTAINERS }} - yarn workspace @trezor/suite-desktop-core test:e2e:desktop ${{ env.TEST_FILE }} + echo "Starting Playwright Desktop test group ${{ matrix.TEST_GROUP }}" + yarn workspace @trezor/suite-desktop-core test:e2e:desktop --forbid-only --grep=${{ matrix.TEST_GROUP }} - - name: cleanup + - name: Extract Trezor-user-env logs + if: ${{ ! cancelled() }} + run: | + docker cp docker-trezor-user-env-unix-1:/trezor-user-env/logs/debugging.log trezor-user-env-debugging.log || true + docker cp docker-trezor-user-env-unix-1:/trezor-user-env/logs/emulator_bridge.log tenv-emulator-bridge-debugging.log || true + docker cp docker-trezor-user-env-unix-1:/trezor-user-env/docker/version.txt trezor-user-env-version.txt || true + + - name: Upload Trezor-user-env logs + if: ${{ ! cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: emulator-logs-${{ matrix.TEST_GROUP }} + path: | + trezor-user-env-debugging.log + tenv-emulator-bridge-debugging.log + trezor-user-env-version.txt + retention-days: 30 + + - name: Docker compose down env: COMPOSE_FILE: ./docker/docker-compose.suite-desktop-ci.yml run: docker compose down - # TODO: currently only uploads trace.zip, figure out why screens are not uploaded - - name: Upload artifacts + - name: Upload Playwright report if: ${{ ! cancelled() }} uses: actions/upload-artifact@v4 with: - name: test-artifacts-${{ matrix.TEST_FILE }} - path: | - ./packages/suite-desktop-core/e2e/test-results + name: playwright-report-${{ matrix.TEST_GROUP }} + path: ./packages/suite-desktop-core/playwright-report/ + retention-days: 30 diff --git a/.github/workflows/test-suite-web-e2e-pw.yml b/.github/workflows/test-suite-web-e2e-pw.yml index 67010647fa7..5c14ba1f5e9 100644 --- a/.github/workflows/test-suite-web-e2e-pw.yml +++ b/.github/workflows/test-suite-web-e2e-pw.yml @@ -107,12 +107,14 @@ jobs: # CONTAINERS: "trezor-user-env-unix" - TEST_GROUP: "@group=wallet" CONTAINERS: "trezor-user-env-unix bitcoin-regtest" + steps: - name: Checkout uses: actions/checkout@v4 with: ref: ${{github.event.after}} fetch-depth: 2 + - name: Setup node uses: actions/setup-node@v4 with: @@ -124,16 +126,6 @@ jobs: run: | echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT - - name: Extract commit message - id: extract_commit_message - run: | - if [ "${{ github.event_name }}" == "pull_request" ]; then - git fetch origin +refs/pull/${{ github.event.pull_request.number }}/merge: --depth=1 - echo "message=$(git log --no-merges -1 --pretty=format:"%s")" >> $GITHUB_OUTPUT - else - echo "message=$(git log --no-merges -1 --pretty=format:"%s")" >> $GITHUB_OUTPUT - fi - - name: Install dependencies and pull docker images env: COMPOSE_FILE: ./docker/docker-compose.suite-ci-pw.yml @@ -144,21 +136,18 @@ jobs: npx playwright install --with-deps chromium docker compose pull ${{ matrix.CONTAINERS }} - - name: Run Playwright e2e tests + - name: Run Playwright e2e web tests env: COMPOSE_FILE: ./docker/docker-compose.suite-ci-pw.yml BASE_URL: https://dev.suite.sldev.cz/suite-web/${{ steps.extract_branch.outputs.branch }}/web/ - ## Keep retries enabled once stabilized - ALLOW_RETRY: true - TEST_GROUP: ${{ matrix.TEST_GROUP }} GITHUB_ACTION: true CURRENTS_PROJECT_ID: Og0NOQ CURRENTS_RECORD_KEY: ${{ secrets.CURRENTS_RECORD_KEY }} CURRENTS_CI_BUILD_ID: pr-run-${{github.run_id}} run: | docker compose up -d ${{ matrix.CONTAINERS }} - echo "Starting Playwright Web test group ${TEST_GROUP}" - yarn workspace @trezor/suite-desktop-core test:e2e:web --grep=${TEST_GROUP} + echo "Starting Playwright Web test group ${{ matrix.TEST_GROUP }}" + yarn workspace @trezor/suite-desktop-core test:e2e:web --forbid-only --grep=${{ matrix.TEST_GROUP }} - name: Extract Trezor-user-env logs if: ${{ ! cancelled() }} @@ -176,6 +165,12 @@ jobs: trezor-user-env-debugging.log tenv-emulator-bridge-debugging.log trezor-user-env-version.txt + retention-days: 30 + + - name: Docker compose down + env: + COMPOSE_FILE: ./docker/docker-compose.suite-ci-pw.yml + run: docker compose down - name: Upload Playwright report if: ${{ ! cancelled() }} From 32054b9252a02df00fedbec5758b987138dfc6c2 Mon Sep 17 00:00:00 2001 From: Martin Vere Cihlar Date: Tue, 10 Dec 2024 13:55:31 +0100 Subject: [PATCH 5/5] fix(e2e): Fix start and name of electron-regtest --- .github/workflows/test-suite-desktop-e2e.yml | 4 ++-- packages/suite-desktop-core/e2e/support/customMatchers.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-suite-desktop-e2e.yml b/.github/workflows/test-suite-desktop-e2e.yml index 38336386e28..49d9bc376d3 100644 --- a/.github/workflows/test-suite-desktop-e2e.yml +++ b/.github/workflows/test-suite-desktop-e2e.yml @@ -32,7 +32,7 @@ jobs: # - TEST_GROUP: "@group=device-management" # CONTAINERS: "trezor-user-env-unix" - TEST_GROUP: "@group=settings" - CONTAINERS: "trezor-user-env-unix" + CONTAINERS: "trezor-user-env-unix electrum-regtest" # - TEST_GROUP: "@group=metadata" # CONTAINERS: "trezor-user-env-unix" # - TEST_GROUP: "@group=passphrase" @@ -40,7 +40,7 @@ jobs: # - TEST_GROUP: "@group=other" # CONTAINERS: "trezor-user-env-unix" - TEST_GROUP: "@group=wallet" - CONTAINERS: "trezor-user-env-unix bitcoin-regtest" + CONTAINERS: "trezor-user-env-unix" steps: - name: Checkout diff --git a/packages/suite-desktop-core/e2e/support/customMatchers.ts b/packages/suite-desktop-core/e2e/support/customMatchers.ts index abd004213c6..c42b8456e53 100644 --- a/packages/suite-desktop-core/e2e/support/customMatchers.ts +++ b/packages/suite-desktop-core/e2e/support/customMatchers.ts @@ -1,4 +1,4 @@ -import { Locator , expect as baseExpect } from '@playwright/test'; +import { Locator, expect as baseExpect } from '@playwright/test'; export const expect = baseExpect.extend({ async toBeEnabledCoin(locator: Locator) {