diff --git a/.gitignore b/.gitignore index e5ca655..a2bf320 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ dist-ssr # PWA dev stuff dev-dist .solid +/test-results/ +/tests-examples/ +/playwright-report/ +/playwright/.cache/ diff --git a/e2e/load.spec.ts b/e2e/load.spec.ts new file mode 100644 index 0000000..44301f5 --- /dev/null +++ b/e2e/load.spec.ts @@ -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"]); +}); diff --git a/package.json b/package.json index 92ec212..d4caca8 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..694e2e9 --- /dev/null +++ b/playwright.config.ts @@ -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 + } +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 622ddf1..ae155a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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'} diff --git a/src/components/CopyableQR.tsx b/src/components/CopyableQR.tsx index 465d395..1538a8f 100644 --- a/src/components/CopyableQR.tsx +++ b/src/components/CopyableQR.tsx @@ -5,7 +5,7 @@ import { useCopy } from "~/utils/useCopy"; export function CopyableQR(props: { value: string }) { const [copy, copied] = useCopy({ copiedTimeout: 1000 }); return ( -
copy(props.value)}> +
copy(props.value)}>

Copied

diff --git a/src/components/layout/BackButton.tsx b/src/components/layout/BackButton.tsx index b6caf20..02b8c7a 100644 --- a/src/components/layout/BackButton.tsx +++ b/src/components/layout/BackButton.tsx @@ -1,5 +1,18 @@ import { Back } from "~/assets/svg/Back"; -export function BackButton(props: { onClick: () => void, title?: string }) { - return () +export function BackButton(props: { + onClick: () => void; + title?: string; + showOnDesktop?: boolean; +}) { + return ( + + ); } \ No newline at end of file diff --git a/src/routes/Receive.tsx b/src/routes/Receive.tsx index 37bc755..3c72e4b 100644 --- a/src/routes/Receive.tsx +++ b/src/routes/Receive.tsx @@ -266,7 +266,7 @@ export default function Receive() { }> - setReceiveState("edit")} title="Edit" /> + setReceiveState("edit")} title="Edit" showOnDesktop /> Checking}> Receive Bitcoin