Skip to content

Commit

Permalink
feat(wallet): improve e2e tests (#5472)
Browse files Browse the repository at this point in the history
* feat(wallet): improve e2e tests

* fix(tests): skip balance finder when importing wallet
  • Loading branch information
VmMad authored Feb 20, 2025
1 parent ce6e5bd commit 64010d6
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 24 deletions.
2 changes: 1 addition & 1 deletion apps/wallet/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: './tests',
/* Maximum time one test can run for. */
timeout: 30 * 1000,
timeout: 45 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
Expand Down
32 changes: 25 additions & 7 deletions apps/wallet/tests/balance-changes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { expect, test } from './fixtures';
import { createWallet, importWallet } from './utils/auth';
import { generateKeypairFromMnemonic, requestIotaFromFaucet } from './utils/localnet';
import { SHORT_TIMEOUT, LONG_TIMEOUT } from './constants/timeout.constants';

const receivedAddressMnemonic = [
'beef',
Expand Down Expand Up @@ -37,20 +38,21 @@ const currentWalletMnemonic = [
];

const COIN_TO_SEND = 20;
const timeout = 30_000;

test('request IOTA from local faucet', async ({ page, extensionUrl }) => {
test.setTimeout(timeout);
test.setTimeout(SHORT_TIMEOUT);
await createWallet(page, extensionUrl);

const originalBalance = await page.getByTestId('coin-balance').textContent();
await page.getByText(/Request localnet tokens/i).click();
await expect(page.getByTestId('coin-balance')).not.toHaveText(`${originalBalance}`, {
timeout,
timeout: SHORT_TIMEOUT,
});
});

test('send 20 IOTA to an address', async ({ page, extensionUrl }) => {
// Use long timeout in case apps-backend is not available
test.setTimeout(LONG_TIMEOUT);
const receivedKeypair = await generateKeypairFromMnemonic(receivedAddressMnemonic.join(' '));
const receivedAddress = receivedKeypair.getPublicKey().toIotaAddress();

Expand All @@ -60,21 +62,37 @@ test('send 20 IOTA to an address', async ({ page, extensionUrl }) => {
await importWallet(page, extensionUrl, currentWalletMnemonic);

await requestIotaFromFaucet(originAddress);
await expect(page.getByTestId('coin-balance')).not.toHaveText('0', { timeout });
await expect(page.getByTestId('coin-balance')).not.toHaveText('0', {
timeout: SHORT_TIMEOUT,
});

const originalBalance = await page.getByTestId('coin-balance').textContent();

await page.waitForSelector('h4:has-text("My Coins")', { timeout: LONG_TIMEOUT });

await page.getByTestId('send-coin-button').click();
await page.getByPlaceholder('0.00').fill(String(COIN_TO_SEND));
await page.getByPlaceholder('Enter Address').fill(receivedAddress);
await page.getByText('Review').click();
await page.getByText('Send Now').click();
await expect(page.getByTestId('overlay-title')).toHaveText('Transaction', { timeout });
await expect(page.getByTestId('overlay-title')).toHaveText('Transaction', {
timeout: SHORT_TIMEOUT,
});

await page.getByTestId('close-icon').click();
await page.getByTestId('nav-home').click();
await page.waitForResponse(async (res) => {
const request = res.request();

try {
const postData = request.postDataJSON();
return postData && postData.method === 'iotax_getBalance';
} catch {
return false;
}
});
await expect(page.getByTestId('coin-balance')).not.toHaveText(`${originalBalance}`, {
timeout,
timeout: SHORT_TIMEOUT,
});
});

Expand All @@ -87,7 +105,7 @@ test('check balance changes in Activity', async ({ page, extensionUrl }) => {

await requestIotaFromFaucet(originAddress);
await page.getByTestId('nav-activity').click();
await expect(page.getByTestId('link-to-txn').first()).toBeVisible({ timeout });
await expect(page.getByTestId('link-to-txn').first()).toBeVisible({ timeout: SHORT_TIMEOUT });
await page.getByTestId('link-to-txn').first().click();
await expect(page.getByText(`Successfully received`, { exact: false })).toBeVisible();
});
5 changes: 5 additions & 0 deletions apps/wallet/tests/constants/timeout.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2025 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export const SHORT_TIMEOUT = 30_000;
export const LONG_TIMEOUT = 60_000;
14 changes: 14 additions & 0 deletions apps/wallet/tests/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const test = base.extend<{
context: BrowserContext;
extensionUrl: string;
demoPageUrl: string;
extensionName: string;
}>({
// eslint-disable-next-line no-empty-pattern
context: async ({}, use) => {
Expand All @@ -37,6 +38,19 @@ export const test = base.extend<{
const extensionUrl = `chrome-extension://${extensionId}/ui.html`;
await use(extensionUrl);
},
extensionName: async ({ context, extensionUrl }, use) => {
const extensionId = extensionUrl.split('/')[2];
const manifestUrl = `chrome-extension://${extensionId}/manifest.json`;
const page = await context.newPage();
const response = await page.goto(manifestUrl);

if (!response) throw new Error('Failed to load manifest.json');

const manifest = await response.json();
const extensionName = manifest.name;
await page.close();
await use(extensionName);
},
// eslint-disable-next-line no-empty-pattern
demoPageUrl: async ({}, use) => {
await use('http://localhost:5181');
Expand Down
3 changes: 2 additions & 1 deletion apps/wallet/tests/lock.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import { expect, test } from './fixtures';
import { createWallet } from './utils/auth';
import { SHORT_TIMEOUT } from './constants/timeout.constants';

test('account lock-unlock', async ({ page, extensionUrl }) => {
await createWallet(page, extensionUrl);
Expand All @@ -30,7 +31,7 @@ test('wallet auto-lock', async ({ page, extensionUrl }) => {
await page.getByRole('button', { name: /Hour/ }).click();
await page.getByRole('button', { name: /Minute/ }).click();
await page.getByText('Save').click();
await expect(page.getByText(/Saved/i)).toBeVisible({ timeout: 30_000 });
await expect(page.getByText(/Saved/i)).toBeVisible({ timeout: SHORT_TIMEOUT });
await page.getByTestId('close-icon').click();
await page.waitForTimeout(62 * 1000);
await expect(page.getByText(/Unlock your Account/)).toBeVisible();
Expand Down
2 changes: 0 additions & 2 deletions apps/wallet/tests/sites-to-cs-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ test.describe('Wallet API', () => {

test.beforeEach(async ({ context, demoPageUrl }) => {
demoPage = await context.newPage();
await demoPage.goto(demoPageUrl);
await demoDappConnect(demoPage, demoPageUrl, context);
});
test('signing message works', async ({ context }) => {
Expand All @@ -32,7 +31,6 @@ test.describe('Wallet API', () => {
name: 'Sign',
})
.click();
await demoPage.waitForTimeout(3000);
await expect(demoPage.getByText('Error')).toHaveCount(0);
});
});
15 changes: 8 additions & 7 deletions apps/wallet/tests/sites-to-cs-messaging.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import dotenv from 'dotenv';

dotenv.config();

function getInAppMessage(page: Page, id: string) {
const walletMessageStreamIDs = generateWalletMessageStreamIdentifiers(process.env.APP_NAME);
function getInAppMessage(
page: Page,
id: string,
walletMessageStreamIDs: ReturnType<typeof generateWalletMessageStreamIdentifiers>,
) {
return page.evaluate(
({ walletMessageStreamIDs, anId }) => {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -83,13 +86,11 @@ test.describe('site to content script messages', () => {
],
] as const;
for (const [aLabel, aPayload, result] of allTests) {
test(aLabel, async ({ context, demoPageUrl }) => {
test(aLabel, async ({ context, demoPageUrl, extensionName }) => {
const page = await context.newPage();
await page.goto(demoPageUrl);
const walletMessageStreamIDs = generateWalletMessageStreamIdentifiers(
process.env.APP_NAME,
);
const nextMessage = getInAppMessage(page, aLabel);
const walletMessageStreamIDs = generateWalletMessageStreamIdentifiers(extensionName);
const nextMessage = getInAppMessage(page, aLabel, walletMessageStreamIDs);
await page.evaluate(
({ aPayload: payload, aLabel: label, walletMessageStreamIDs }) => {
window.postMessage({
Expand Down
15 changes: 11 additions & 4 deletions apps/wallet/tests/utils/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
// SPDX-License-Identifier: Apache-2.0

import type { Page } from '@playwright/test';
import { SHORT_TIMEOUT } from '../constants/timeout.constants';

export const PASSWORD = 'iota';

export async function createWallet(page: Page, extensionUrl: string) {
await page.goto(extensionUrl);
await page.getByRole('button', { name: /Add Profile/ }).click();
await page.goto(extensionUrl, { waitUntil: 'commit' });
await page.getByRole('button', { name: /Add Profile/ }).click({ timeout: SHORT_TIMEOUT });
await page.getByText('Create New').click();
await page.getByTestId('password.input').fill('iotae2etests');
await page.getByTestId('password.confirmation').fill('iotae2etests');
Expand All @@ -19,8 +20,8 @@ export async function createWallet(page: Page, extensionUrl: string) {
}

export async function importWallet(page: Page, extensionUrl: string, mnemonic: string | string[]) {
await page.goto(extensionUrl);
await page.getByRole('button', { name: /Add Profile/ }).click();
await page.goto(extensionUrl, { waitUntil: 'commit' });
await page.getByRole('button', { name: /Add Profile/ }).click({ timeout: SHORT_TIMEOUT });
await page.getByText('Mnemonic', { exact: true }).click();
await page
.getByPlaceholder('Word')
Expand All @@ -31,4 +32,10 @@ export async function importWallet(page: Page, extensionUrl: string, mnemonic: s
await page.getByTestId('password.confirmation').fill('iotae2etests');
await page.getByText('I read and agree').click();
await page.getByRole('button', { name: /Create Wallet/ }).click();

await page.waitForURL(new RegExp(/^(?!.*protect-account).*$/));

if (await page.getByText('Balance Finder').isVisible()) {
await page.getByRole('button', { name: /Skip/ }).click();
}
}
5 changes: 3 additions & 2 deletions apps/wallet/tests/utils/dappConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import type { BrowserContext, Page } from '@playwright/test';

import { expect } from '../fixtures';
import { SHORT_TIMEOUT } from '../constants/timeout.constants';

export async function demoDappConnect(page: Page, demoPageUrl: string, context: BrowserContext) {
await page.goto(demoPageUrl);
await page.goto(demoPageUrl, { waitUntil: 'commit' });
const newWalletPage = context.waitForEvent('page');
await page.getByRole('button', { name: 'Connect' }).click();
await page.getByRole('button', { name: 'Connect' }).click({ timeout: SHORT_TIMEOUT });
const walletPage = await newWalletPage;
await walletPage.waitForLoadState();
await walletPage.getByRole('button', { name: 'Continue' }).click();
Expand Down

0 comments on commit 64010d6

Please sign in to comment.