test: playwright e2e setup with onboarding, navigation and receive specs

This commit is contained in:
2026-08-19 21:36:48 +02:00
parent 1839700215
commit 05fc40263b
12 changed files with 342 additions and 1 deletions
+19
View File
@@ -0,0 +1,19 @@
import { test, expect } from '../fixtures';
test.describe('Navigation', () => {
test('hamburger opens Settings and the back button returns to the main page', async ({
page,
}) => {
// fresh device: the main page shows the welcome card
await page.goto('/');
await expect(page.getByText('Welcome to sattle')).toBeVisible();
await page.getByRole('button', { name: 'Settings' }).click();
await expect(page).toHaveURL(/#\/settings$/);
await expect(page.getByText('Settings', { exact: true })).toBeVisible();
await page.getByRole('button', { name: 'Back' }).click();
await expect(page).toHaveURL(/#\/$/);
await expect(page.getByText('Welcome to sattle')).toBeVisible();
});
});
+26
View File
@@ -0,0 +1,26 @@
import { test, expect } from '../fixtures';
test.describe('Onboarding', () => {
test('creating a wallet lands on the unlocked main screen', async ({ page }) => {
await page.goto('/#/welcome');
// "Create new" is the default tab - its create button is right there
await expect(page.getByRole('button', { name: 'Create new' })).toBeVisible();
await page.getByRole('button', { name: 'Create wallet' }).click();
// the recovery phrase is shown exactly once before the wallet opens
await expect(page.getByText('Your recovery phrase')).toBeVisible();
await page.locator('.q-checkbox', { hasText: 'I wrote it down' }).click();
await page.getByRole('button', { name: 'Continue' }).click();
// unlocked main screen: 0-sats balance card, the three actions, history
await expect(page).toHaveURL(/#\/$/);
const balanceCard = page.locator('.balance-card');
await expect(balanceCard.locator('.text-h2')).toHaveText('0');
await expect(balanceCard).toContainText('sats');
await expect(page.getByRole('button', { name: 'Receive' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Scan' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Send' })).toBeVisible();
await expect(page.getByText('History', { exact: true })).toBeVisible();
});
});
+61
View File
@@ -0,0 +1,61 @@
import { test, expect } from '../fixtures';
import type { Page } from '@playwright/test';
import { buildNoteUrl, defaultRandomSecret } from 'lnurlcash-kit';
import { MINT_ORIGIN, NOTE_PATH } from '../helpers/MintMocker';
import { createFreshWallet } from '../helpers/wallet';
const AMOUNT_MSAT = 21_000; // 21 sats
// a syntactically valid bearer note against the mock mint - the k1 is a
// fresh random secret, so every test redeems a distinct note
const freshNoteUrl = (): string =>
buildNoteUrl(`${MINT_ORIGIN}${NOTE_PATH}`, defaultRandomSecret(), AMOUNT_MSAT);
// main page -> Receive -> "Bearer note" -> paste -> redeem
const redeemNote = async (page: Page, noteUrl: string): Promise<void> => {
await page.getByRole('button', { name: 'Receive' }).click();
const chooser = page.locator('.q-dialog', { hasText: 'Paste or scan a note' });
await chooser.getByRole('button', { name: 'Bearer note' }).click();
const dialog = page.locator('.q-dialog', { hasText: 'Receive bearer note' });
await dialog.locator('textarea').fill(noteUrl);
await dialog.getByRole('button', { name: 'Receive', exact: true }).click();
};
test.describe('Receive bearer note', () => {
test('redeeming a valid note updates the balance', async ({ page, mint }) => {
await mint.mockNoteInfo({ amountMsat: AMOUNT_MSAT });
await mint.mockRotateOk();
await createFreshWallet(page);
const dialog = page.locator('.q-dialog', { hasText: 'Receive bearer note' });
await redeemNote(page, freshNoteUrl());
// success screen, then the balance reflects the redeemed amount
await expect(dialog.getByText('Received 21 sats')).toBeVisible();
// no "stored unconfirmed" / rotation banner: both mocked mint endpoints
// were really consumed (the kit bug this guards against silently fell
// back to the declared amount without any request)
await expect(dialog.locator('.q-banner')).toHaveCount(0);
await dialog.getByRole('button', { name: 'Done' }).click();
await expect(page.locator('.balance-card .text-h2')).toHaveText('21');
});
test('a spent note shows the spent error and leaves the balance untouched', async ({
page,
mint,
}) => {
await mint.mockNoteInfo({ spentReason: 'note already spent' });
await createFreshWallet(page);
await redeemNote(page, freshNoteUrl());
await expect(
page.locator('.q-banner', { hasText: 'This note has already been spent.' }),
).toBeVisible();
// nothing was stored: back on the main page the balance is still 0
await page.keyboard.press('Escape');
await expect(page.locator('.balance-card .text-h2')).toHaveText('0');
});
});