Skip to content

Commit a010814

Browse files
authored
feat(e2e): Migrated backup tests (#17150)
* feat(e2e): Migrated backup tests * fix(ci): Removed device management group from cypress tests pipeline * fix(e2e): Added missing await * fix(e2e): Fixed PR review comments
1 parent 73ba107 commit a010814

14 files changed

+256
-262
lines changed

.github/workflows/test-suite-web-e2e.yml

-3
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ jobs:
9797
fail-fast: false
9898
matrix:
9999
include:
100-
- TEST_GROUP: "@group_device-management"
101-
CONTAINERS: "trezor-user-env-unix"
102-
CYPRESS_USE_TREZOR_USER_ENV_BRIDGE: "1"
103100
- TEST_GROUP: "@group_wallet"
104101
CONTAINERS: "trezor-user-env-unix bitcoin-regtest"
105102
CYPRESS_USE_TREZOR_USER_ENV_BRIDGE: "1"

.github/workflows/test-suite-web-nightly.yml

-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ jobs:
1818
- TEST_GROUP: "@group_suite"
1919
CONTAINERS: "trezor-user-env-unix"
2020
CYPRESS_USE_TREZOR_USER_ENV_BRIDGE: "1"
21-
- TEST_GROUP: "@group_device-management"
22-
CONTAINERS: "trezor-user-env-unix"
23-
CYPRESS_USE_TREZOR_USER_ENV_BRIDGE: "1"
2421
- TEST_GROUP: "@group_wallet"
2522
CONTAINERS: "trezor-user-env-unix bitcoin-regtest"
2623
CYPRESS_USE_TREZOR_USER_ENV_BRIDGE: "1"

packages/suite-desktop-core/e2e/support/pageActions/dashboardActions.ts

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class DashboardActions {
3434
readonly passphraseSubmitButton: Locator;
3535
readonly passphraseShowButton: Locator;
3636
readonly loading: Locator;
37+
readonly notificationNoBackupButton: Locator;
3738

3839
constructor(
3940
private readonly page: Page,
@@ -62,6 +63,7 @@ export class DashboardActions {
6263
this.passphraseSubmitButton = this.page.getByTestId('@passphrase/hidden/submit-button');
6364
this.passphraseShowButton = this.page.getByTestId('@passphrase/show-toggle');
6465
this.loading = this.page.getByTestId('@dashboard/loading');
66+
this.notificationNoBackupButton = this.page.getByTestId('@notification/no-backup/button');
6567
}
6668

6769
@step()

packages/suite-desktop-core/e2e/support/pageActions/onboarding/backupActions.ts

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { DevicePromptActions } from '../devicePromptActions';
55

66
export class BackupActions {
77
readonly startButton: Locator;
8+
readonly undertandWhatSeedIsCheckbox: Locator;
9+
readonly hasEnoughTimeCheckbox: Locator;
10+
readonly isInPrivateCheckbox: Locator;
811
readonly wroteSeedProperlyCheckbox: Locator;
912
readonly madeNoDigitalCopyCheckbox: Locator;
1013
readonly willHideSeedCheckbox: Locator;
@@ -15,6 +18,11 @@ export class BackupActions {
1518
private devicePrompt: DevicePromptActions,
1619
) {
1720
this.startButton = page.getByTestId('@backup/start-button');
21+
this.undertandWhatSeedIsCheckbox = page.getByTestId(
22+
'@backup/check-item/understands-what-seed-is',
23+
);
24+
this.hasEnoughTimeCheckbox = page.getByTestId('@backup/check-item/has-enough-time');
25+
this.isInPrivateCheckbox = page.getByTestId('@backup/check-item/is-in-private');
1826
this.wroteSeedProperlyCheckbox = page.getByTestId('@backup/check-item/wrote-seed-properly');
1927
this.madeNoDigitalCopyCheckbox = page.getByTestId(
2028
'@backup/check-item/made-no-digital-copy',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Locator, Page } from '@playwright/test';
2+
3+
import { step } from '../../common';
4+
5+
export class DeviceActions {
6+
readonly createMultiShareBackupButton: Locator;
7+
readonly multiShareBackupGotItButton: Locator;
8+
private readonly firstInfoSubmitButton: Locator;
9+
private readonly secondInfoSubmitButton: Locator;
10+
11+
constructor(private readonly page: Page) {
12+
this.createMultiShareBackupButton = page.getByTestId(
13+
'@settings/device/create-multi-share-backup-button',
14+
);
15+
this.multiShareBackupGotItButton = page.getByTestId(
16+
'@multi-share-backup/done/got-it-button',
17+
);
18+
this.firstInfoSubmitButton = page.getByTestId('@multi-share-backup/1st-info/submit-button');
19+
this.secondInfoSubmitButton = page.getByTestId(
20+
'@multi-share-backup/2nd-info/submit-button',
21+
);
22+
}
23+
24+
@step()
25+
async proceedMultiShareBackupModal(): Promise<void> {
26+
await this.page.getByTestId('@multi-share-backup/checkbox/1').click();
27+
await this.page.getByTestId('@multi-share-backup/checkbox/2').click();
28+
await this.firstInfoSubmitButton.click();
29+
await this.secondInfoSubmitButton.click();
30+
}
31+
}

packages/suite-desktop-core/e2e/support/pageActions/settings/settingsActions.ts

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Locator, Page, test } from '@playwright/test';
33
import { capitalizeFirstLetter } from '@trezor/utils';
44

55
import { CoinsActions } from './coinActions';
6+
import { DeviceActions } from './deviceActions';
67
import { TrezorUserEnvLinkProxy, step } from '../../common';
78
import { expect } from '../../customMatchers';
89

@@ -38,6 +39,7 @@ const backgroundImages = {
3839
export class SettingsActions {
3940
private readonly TIMES_CLICK_TO_SET_DEBUG_MODE = 5;
4041
readonly coins: CoinsActions;
42+
readonly device: DeviceActions;
4143

4244
readonly settingsMenuButton: Locator;
4345
readonly settingsHeader: Locator;
@@ -73,6 +75,7 @@ export class SettingsActions {
7375
private readonly apiURL: string,
7476
) {
7577
this.coins = new CoinsActions(page);
78+
this.device = new DeviceActions(page);
7679

7780
this.settingsMenuButton = this.page.getByTestId('@suite/menu/settings');
7881
this.settingsHeader = this.page.getByTestId('@settings/menu/title');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { EventType } from '@trezor/suite-analytics';
2+
import { ExtractByEventType } from '@trezor/suite-web/e2e/support/types';
3+
4+
import { expect, test } from '../../support/fixtures';
5+
6+
test.describe('Backup fail', { tag: ['@group=device-management'] }, () => {
7+
test.use({
8+
emulatorStartConf: { model: 'T2T1', wipe: true },
9+
emulatorSetupConf: { needs_backup: true },
10+
});
11+
12+
test.beforeEach(async ({ onboardingPage, analytics }) => {
13+
await onboardingPage.completeOnboarding();
14+
await analytics.interceptAnalytics();
15+
});
16+
17+
test('Device disconnected during action', async ({
18+
page,
19+
analytics,
20+
onboardingPage,
21+
dashboardPage,
22+
devicePrompt,
23+
trezorUserEnvLink,
24+
}) => {
25+
await dashboardPage.notificationNoBackupButton.click();
26+
await onboardingPage.backup.undertandWhatSeedIsCheckbox.click();
27+
await onboardingPage.backup.hasEnoughTimeCheckbox.click();
28+
await onboardingPage.backup.isInPrivateCheckbox.click();
29+
await onboardingPage.backup.startButton.click();
30+
await devicePrompt.confirmOnDevicePromptIsShown();
31+
await trezorUserEnvLink.pressYes();
32+
await trezorUserEnvLink.stopEmu();
33+
34+
await expect(page.getByTestId('@backup/no-device')).toBeVisible();
35+
36+
await trezorUserEnvLink.startEmu();
37+
38+
await expect(page.getByTestId('@backup/error-message')).toBeVisible({ timeout: 30000 });
39+
40+
// Now go to dashboard and see if security card and notification reflects backup failed state correctly
41+
await onboardingPage.backup.closeButton.click();
42+
await expect(page.getByTestId('@notification/failed-backup/cta')).toBeVisible();
43+
44+
const createBackupEvent = analytics.findAnalyticsEventByType<
45+
ExtractByEventType<EventType.CreateBackup>
46+
>(EventType.CreateBackup);
47+
expect(createBackupEvent.status).toEqual('error');
48+
expect(createBackupEvent.error).toMatch(
49+
/device\+disconnected\+during\+action|Device\+disconnected|session\+not\+found/,
50+
);
51+
});
52+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { expect, test } from '../../support/fixtures';
2+
3+
test.describe('Backup misc', { tag: ['@group=device-management'] }, () => {
4+
test.use({
5+
emulatorStartConf: { model: 'T2T1', wipe: true },
6+
emulatorSetupConf: { needs_backup: true },
7+
});
8+
9+
test.beforeEach(async ({ onboardingPage, dashboardPage }) => {
10+
await onboardingPage.completeOnboarding();
11+
await dashboardPage.discoveryShouldFinish();
12+
});
13+
14+
test('Backup should reset if modal is closed', async ({ onboardingPage, dashboardPage }) => {
15+
await dashboardPage.notificationNoBackupButton.click();
16+
await onboardingPage.backup.undertandWhatSeedIsCheckbox.click();
17+
await onboardingPage.backup.hasEnoughTimeCheckbox.click();
18+
await onboardingPage.backup.isInPrivateCheckbox.click();
19+
await expect(
20+
onboardingPage.backup.undertandWhatSeedIsCheckbox.locator('input'),
21+
).toBeChecked();
22+
await expect(onboardingPage.backup.hasEnoughTimeCheckbox.locator('input')).toBeChecked();
23+
await expect(onboardingPage.backup.isInPrivateCheckbox.locator('input')).toBeChecked();
24+
await onboardingPage.backup.closeButton.click();
25+
await dashboardPage.notificationNoBackupButton.click();
26+
27+
//at this moment, after modal was closed and opened again, no checkbox should be checked
28+
await expect(
29+
onboardingPage.backup.undertandWhatSeedIsCheckbox.locator('input'),
30+
).not.toBeChecked();
31+
await expect(
32+
onboardingPage.backup.hasEnoughTimeCheckbox.locator('input'),
33+
).not.toBeChecked();
34+
await expect(onboardingPage.backup.isInPrivateCheckbox.locator('input')).not.toBeChecked();
35+
});
36+
37+
test('User disconnected device that is remembered. Should not be allowed to initiate backup', async ({
38+
page,
39+
dashboardPage,
40+
onboardingPage,
41+
trezorUserEnvLink,
42+
}) => {
43+
await expect(dashboardPage.graph).toBeVisible();
44+
await dashboardPage.openDeviceSwitcher();
45+
await dashboardPage.walletAtIndex(0).click();
46+
await dashboardPage.notificationNoBackupButton.click();
47+
await onboardingPage.backup.undertandWhatSeedIsCheckbox.click();
48+
await onboardingPage.backup.hasEnoughTimeCheckbox.click();
49+
await onboardingPage.backup.isInPrivateCheckbox.click();
50+
51+
await trezorUserEnvLink.stopEmu();
52+
await expect(page.getByTestId('@backup/no-device')).toBeVisible();
53+
});
54+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { EventType } from '@trezor/suite-analytics';
2+
import { ExtractByEventType } from '@trezor/suite-web/e2e/support/types';
3+
4+
import { expect, test } from '../../support/fixtures';
5+
6+
test.describe('Backup success', { tag: ['@group=device-management'] }, () => {
7+
test.use({
8+
emulatorStartConf: { model: 'T2T1', wipe: true },
9+
emulatorSetupConf: { needs_backup: true, mnemonic: 'mnemonic_all' },
10+
});
11+
12+
test.beforeEach(async ({ onboardingPage, analytics }) => {
13+
await analytics.interceptAnalytics();
14+
await onboardingPage.completeOnboarding();
15+
});
16+
17+
test('Successful backup happy path', async ({
18+
analytics,
19+
onboardingPage,
20+
dashboardPage,
21+
devicePrompt,
22+
trezorUserEnvLink,
23+
}) => {
24+
// access from notification
25+
await dashboardPage.notificationNoBackupButton.click();
26+
27+
await onboardingPage.backup.undertandWhatSeedIsCheckbox.click();
28+
await onboardingPage.backup.hasEnoughTimeCheckbox.click();
29+
await onboardingPage.backup.isInPrivateCheckbox.click();
30+
31+
// Create backup on device
32+
await onboardingPage.backup.startButton.click();
33+
34+
await devicePrompt.confirmOnDevicePromptIsShown();
35+
36+
//await trezorUserEnvLink.readAndConfirmMnemonicEmu(); should be used here, but it is flaky
37+
// TODO: https://github.com/trezor/trezor-suite/issues/17148
38+
await trezorUserEnvLink.pressYes();
39+
await trezorUserEnvLink.pressYes();
40+
await trezorUserEnvLink.swipeEmu('up');
41+
await trezorUserEnvLink.swipeEmu('up');
42+
await trezorUserEnvLink.pressYes();
43+
await trezorUserEnvLink.inputEmu('all');
44+
await trezorUserEnvLink.inputEmu('all');
45+
await trezorUserEnvLink.inputEmu('all');
46+
await trezorUserEnvLink.pressYes();
47+
await trezorUserEnvLink.pressYes();
48+
49+
// Click all after checkboxes and close backup modal
50+
await expect(onboardingPage.backup.closeButton).toBeDisabled();
51+
await onboardingPage.backup.wroteSeedProperlyCheckbox.click();
52+
await onboardingPage.backup.madeNoDigitalCopyCheckbox.click();
53+
await onboardingPage.backup.willHideSeedCheckbox.click();
54+
await expect(onboardingPage.backup.closeButton).toBeEnabled();
55+
56+
const createBackupEvent = analytics.findAnalyticsEventByType<
57+
ExtractByEventType<EventType.CreateBackup>
58+
>(EventType.CreateBackup);
59+
expect(createBackupEvent.status).toEqual('finished');
60+
expect(createBackupEvent.error).toEqual('');
61+
});
62+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { MNEMONICS } from '@trezor/trezor-user-env-link';
2+
3+
import { test } from '../../support/fixtures';
4+
5+
test.describe('Create additional share', { tag: ['@group=device-management'] }, () => {
6+
test.use({
7+
emulatorSetupConf: { mnemonic: 'mnemonic_academic' },
8+
});
9+
10+
test.beforeEach(async ({ onboardingPage }) => {
11+
await onboardingPage.completeOnboarding({ enableViewOnly: true });
12+
});
13+
14+
test('Successfuly added additional share', async ({
15+
page,
16+
settingsPage,
17+
trezorUserEnvLink,
18+
}) => {
19+
await settingsPage.navigateTo('device');
20+
await settingsPage.device.createMultiShareBackupButton.click();
21+
await settingsPage.device.proceedMultiShareBackupModal();
22+
23+
// [device screen] check your backup?
24+
await trezorUserEnvLink.pressYes();
25+
26+
// [device screen] select the number of words in your backup
27+
await trezorUserEnvLink.inputEmu('20');
28+
29+
// [device screen] backup instructions
30+
await trezorUserEnvLink.pressYes();
31+
32+
for (const word of MNEMONICS.mnemonic_academic.split(' ')) {
33+
// [device screen] enter next word
34+
await trezorUserEnvLink.inputEmu(word);
35+
}
36+
37+
// [device screen] create additional backup?
38+
await page.waitForTimeout(1000); // without this timeout, backup on device simply disappears, it stinks TODO: https://github.com/trezor/trezor-suite/issues/17128
39+
await trezorUserEnvLink.pressYes();
40+
await trezorUserEnvLink.readAndConfirmShamirMnemonicEmu({ shares: 3, threshold: 2 });
41+
42+
await settingsPage.device.multiShareBackupGotItButton.click();
43+
});
44+
});

packages/suite-web/e2e/tests/backup/t2t1-fail.test.ts

-55
This file was deleted.

0 commit comments

Comments
 (0)