add simple load test and receive test

This commit is contained in:
Paul Miller
2023-06-02 17:40:14 -05:00
parent 7361e0a26b
commit 2b49b04f08
8 changed files with 192 additions and 4 deletions

4
.gitignore vendored
View File

@@ -26,3 +26,7 @@ dist-ssr
# PWA dev stuff
dev-dist
.solid
/test-results/
/tests-examples/
/playwright-report/
/playwright/.cache/

72
e2e/load.spec.ts Normal file
View File

@@ -0,0 +1,72 @@
import { test, expect } from "@playwright/test";
test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:3420/");
});
test("initial load", async ({ page }) => {
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Mutiny Wallet/);
// Wait up to 30 seconds for the "header" text to be visible
await page.waitForSelector("text=Lightning", { timeout: 30000 });
await expect(page.locator("header")).toContainText(["Lightning", "On-Chain", "Activity"]);
// Wait for an element matching the selector to appear in DOM.
await page.waitForSelector("text=0 SATS");
console.log("Page loaded.");
});
test("first receive", async ({ page }) => {
// Click the receive button
await page.click("text=Receive");
// Expect the url to conain receive
await expect(page).toHaveURL(/.*receive/);
// At least one h1 should show "0 sats"
await expect(page.locator("h1")).toContainText(["0 SATS"]);
// At least one h2 should show "0 USD"
await expect(page.locator("h2")).toContainText(["$0 USD"]);
// Click the 10k button
await page.click("text=10k");
// Now the h1 should show "10,000 sats"
await expect(page.locator("h1")).toContainText(["10,000 SATS"]);
// Click the "Set Amount" button
await page.click("text=Set Amount");
// There should be a button with the text "Continue" and it should not be disabled
const continueButton = await page.locator("button", { hasText: "Continue" });
await expect(continueButton).not.toBeDisabled();
// Wait one second
// TODO: figure out how to not get an error without waiting
await page.waitForTimeout(1000);
continueButton.click();
// Find a p with the text "Show or share this code with the sender."
await expect(page.locator("p")).toContainText(["Show or share this code with the sender."]);
// Locate an SVG inside a div with id "qr"
const qrCode = await page.locator("#qr > svg");
await expect(qrCode).toBeVisible();
const value = await qrCode.getAttribute("value");
// The SVG's value property includes "bitcoin:t"
expect(value).toContain("bitcoin:t");
// Now click thie "Edit" button
await page.click("text=Edit");
// There should not be an h1 that says "Error"
await expect(page.locator("h1")).not.toContainText(["Error"]);
});

View File

@@ -2,6 +2,7 @@
"name": "mws",
"version": "0.3.6",
"license": "MIT",
"packageManager": "pnpm@8.3.1",
"scripts": {
"dev": "solid-start dev",
"host": "solid-start dev --host",
@@ -11,6 +12,7 @@
},
"type": "module",
"devDependencies": {
"@playwright/test": "^1.34.3",
"@types/node": "^18.16.15",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",

77
playwright.config.ts Normal file
View File

@@ -0,0 +1,77 @@
import { defineConfig, devices } from "@playwright/test";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./e2e",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry"
},
/* Configure projects for major browsers */
projects: [
// {
// name: "chromium",
// use: { ...devices["Desktop Chrome"] }
// },
{
name: "firefox",
use: { ...devices["Desktop Firefox"] }
},
// {
// name: "webkit",
// use: { ...devices["Desktop Safari"] }
// },
/* Test against mobile viewports. */
{
name: "Mobile Chrome",
use: { ...devices["Pixel 5"] }
},
{
name: "Mobile Safari",
use: { ...devices["iPhone 12"] }
}
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
webServer: {
command: "pnpm run dev",
url: "http://localhost:3420",
reuseExistingServer: !process.env.CI
}
});

20
pnpm-lock.yaml generated
View File

@@ -51,6 +51,9 @@ dependencies:
version: 5.22.1
devDependencies:
'@playwright/test':
specifier: ^1.34.3
version: 1.34.3
'@types/node':
specifier: ^18.16.15
version: 18.16.15
@@ -1718,6 +1721,17 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
/@playwright/test@1.34.3:
resolution: {integrity: sha512-zPLef6w9P6T/iT6XDYG3mvGOqOyb6eHaV9XtkunYs0+OzxBtrPAAaHotc0X+PJ00WPPnLfFBTl7mf45Mn8DBmw==}
engines: {node: '>=14'}
hasBin: true
dependencies:
'@types/node': 18.16.15
playwright-core: 1.34.3
optionalDependencies:
fsevents: 2.3.2
dev: true
/@polka/url@1.0.0-next.21:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
@@ -4401,6 +4415,12 @@ packages:
resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
engines: {node: '>= 6'}
/playwright-core@1.34.3:
resolution: {integrity: sha512-2pWd6G7OHKemc5x1r1rp8aQcpvDh7goMBZlJv6Co5vCNLVcQJdhxRL09SGaY6HcyHH9aT4tiynZabMofVasBYw==}
engines: {node: '>=14'}
hasBin: true
dev: true
/polka@1.0.0-next.22:
resolution: {integrity: sha512-a7tsZy5gFbJr0aUltZS97xCkbPglXuD67AMvTyZX7BTDBH384FWf0ZQF6rPvdutSxnO1vUlXM2zSLf5tCKk5RA==}
engines: {node: '>=8'}

View File

@@ -5,7 +5,7 @@ import { useCopy } from "~/utils/useCopy";
export function CopyableQR(props: { value: string }) {
const [copy, copied] = useCopy({ copiedTimeout: 1000 });
return (
<div class="w-full bg-white rounded-xl relative" onClick={() => copy(props.value)}>
<div id="qr" class="w-full bg-white rounded-xl relative" onClick={() => copy(props.value)}>
<Show when={copied()}>
<div class="absolute w-full h-full bg-neutral-900/60 z-50 rounded-xl flex flex-col items-center justify-center transition-all">
<p class="text-xl font-bold">Copied</p>

View File

@@ -1,5 +1,18 @@
import { Back } from "~/assets/svg/Back";
export function BackButton(props: { onClick: () => void, title?: string }) {
return (<button onClick={() => props.onClick()} class="text-m-red active:text-m-red/80 text-xl font-semibold no-underline md:hidden flex items-center"><Back />{props.title ? props.title : "Home"}</button>)
export function BackButton(props: {
onClick: () => void;
title?: string;
showOnDesktop?: boolean;
}) {
return (
<button
onClick={() => props.onClick()}
class="text-m-red active:text-m-red/80 text-xl font-semibold no-underline md:hidden flex items-center"
classList={{ "md:!flex": props.showOnDesktop }}
>
<Back />
{props.title ? props.title : "Home"}
</button>
);
}

View File

@@ -266,7 +266,7 @@ export default function Receive() {
<SafeArea>
<DefaultMain>
<Show when={receiveState() === "show"} fallback={<BackLink />}>
<BackButton onClick={() => setReceiveState("edit")} title="Edit" />
<BackButton onClick={() => setReceiveState("edit")} title="Edit" showOnDesktop />
</Show>
<LargeHeader action={receiveState() === "show" && <Indicator>Checking</Indicator>}>
Receive Bitcoin