test all routes, test send + receive

This commit is contained in:
Paul Miller
2023-11-14 13:59:32 -06:00
committed by Tony Giorgio
parent d38f0d61a2
commit 8a427c62e8
5 changed files with 301 additions and 54 deletions

View File

@@ -64,7 +64,7 @@ jobs:
VITE_FEEDBACK: https://feedback-staging.mutinywallet.com
VITE_SCORER: https://scorer-staging.mutinywallet.com
VITE_PRIMAL: https://primal-cache.mutinywallet.com/api
run: pnpm exec playwright test
run: pnpm exec playwright test --grep-invert @slow
- uses: actions/upload-artifact@v3
if: always()
with:

View File

@@ -21,55 +21,3 @@ test("initial load", async ({ page }) => {
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();
await expect(
page.getByText("Keep Mutiny open to complete the payment.")
).toBeVisible();
// 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

@@ -4,7 +4,7 @@ test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:3420/");
});
test("restore from seed", async ({ page }) => {
test("restore from seed @slow", async ({ page }) => {
// should have 100k sats on-chain
const TEST_SEED_WORDS =
"rival hood review write spoon tide orange ill opera enrich clip acoustic";

92
e2e/roundtrip.spec.ts Normal file
View File

@@ -0,0 +1,92 @@
import { test, expect } from "@playwright/test";
test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:3420/");
});
test("rountrip receive and send", 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 100k button
await page.click("text=100k");
// Now the h1 should show "10,000 sats"
await expect(page.locator("h1")).toContainText(["100,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();
await expect(
page.getByText("Keep Mutiny open to complete the payment.")
).toBeVisible();
// 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");
const lightningInvoice = value?.split("lightning=")[1];
// Post the lightning invoice to the server
const _response = await fetch("https://faucet.mutinynet.com/api/lightning", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
bolt11: lightningInvoice
})
});
// Wait for an h1 to appear in the dom that says "Payment Received"
await page.waitForSelector("text=Payment Received", { timeout: 30000 });
// Click the "Nice" button
await page.click("text=Nice");
// Now we send
await page.click("text=Send");
// In the textarea with the placeholder "bitcoin:..." type refund@lnurl-staging.mutinywallet.com
const sendInput = await page.locator("textarea");
await sendInput.fill("refund@lnurl-staging.mutinywallet.com");
await page.click("text=Continue");
await page.click("text=Set Amount");
await page.click("text=10k");
await page.click("text=Set Amount");
await page.click("text=Confirm Send");
// Wait for an h1 to appear in the dom that says "Payment Received"
await page.waitForSelector("text=Payment Sent", { timeout: 30000 });
});

207
e2e/routes.spec.ts Normal file
View File

@@ -0,0 +1,207 @@
import { expect, Page, test } from "@playwright/test";
const routes = [
"/",
"/activity",
"/feedback",
"/gift",
"/receive",
"/redshift",
"/scanner",
"/send",
"/swap",
"/settings"
];
const settingsRoutes = [
"/admin",
"/backup",
"/channels",
"/connections",
"/currency",
"/emergencykit",
"/encrypt",
"/gift",
"/lnurlauth",
"/plus",
"/restore",
"/servers",
"/syncnostrcontacts"
];
const settingsRoutesPrefixed = settingsRoutes.map((route) => {
return "/settings" + route;
});
const allRoutes = routes.concat(settingsRoutesPrefixed);
// Create a JS Map of all routes so we can check them off one by one
const checklist = new Map();
allRoutes.forEach((route) => {
checklist.set(route, false);
});
// Only works if there's a link to the route on the page
async function checkRoute(
page: Page,
route: string,
expectedHeader: string,
checklist: Map<string, boolean>
) {
await page.locator(`a[href='${route}']`).first().click();
await expect(page.locator("h1").first()).toHaveText(expectedHeader);
checklist.set(route, true);
}
test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:3420/");
});
test("visit each route", async ({ page }) => {
// Start on the home page
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Mutiny Wallet/);
// Wait for an element matching the selector to appear in DOM.
await page.waitForSelector("text=0 SATS");
console.log("Page loaded.");
// Wait for a while just to make sure we can load everything
await page.waitForTimeout(1000);
checklist.set("/", true);
await checkRoute(page, "/activity", "Activity", checklist);
await page.goBack();
// Navigate to settings
await checkRoute(page, "/settings", "Settings", checklist);
// Mutiny+
await checkRoute(page, "/settings/plus", "Mutiny+", checklist);
await page.goBack();
// Lightning Channels
await checkRoute(
page,
"/settings/channels",
"Lightning Channels",
checklist
);
await page.goBack();
// Backup
await checkRoute(page, "/settings/backup", "Backup", checklist);
await page.goBack();
// Restore
await checkRoute(page, "/settings/restore", "Restore", checklist);
await page.goBack();
// Currency
await checkRoute(page, "/settings/currency", "Currency", checklist);
await page.goBack();
// Servers
await checkRoute(page, "/settings/servers", "Servers", checklist);
await page.goBack();
// Connections
await checkRoute(
page,
"/settings/connections",
"Wallet Connections",
checklist
);
await page.goBack();
// LNURL Auth
await checkRoute(page, "/settings/lnurlauth", "LNURL Auth", checklist);
await page.goBack();
// Sync Nostr Contacts
await checkRoute(
page,
"/settings/syncnostrcontacts",
"Sync Nostr Contacts",
checklist
);
await page.goBack();
// Emergency Kit
await checkRoute(
page,
"/settings/emergencykit",
"Emergency Kit",
checklist
);
await page.goBack();
// Admin
await checkRoute(page, "/settings/admin", "Secret Debug Tools", checklist);
await page.goBack();
// Go back home
await page.goBack();
// Feedback
await checkRoute(page, "/feedback", "Give us feedback!", checklist);
await page.goBack();
// Receive is covered in another test
checklist.set("/receive", true);
// Send is covered in another test
checklist.set("/send", true);
// Scanner
await page.locator(`a[href='/scanner']`).first().click();
await expect(page.locator("button").first()).toHaveText("Paste Something");
checklist.set("/scanner", true);
// Now we have to check routes that aren't linked to directly for whatever reason
await page.goto(
"http://localhost:3420/gift?amount=50000&nwc_uri=nostr%2Bwalletconnect%3A%2F%2Ff6d55dff6da0f23e0d609121905aaa8da5d2bad7759459402e2bee1162912556%3Frelay%3Dwss%253A%252F%252Fnostr.mutinywallet.com%252F%26secret%3D8a2d579a182e9091d36d5668eb1c3b301d98bc792d94e866526123df79568355"
);
await expect(page.locator("h2").nth(1)).toHaveText(
"You've been gifted some sats!"
);
checklist.set("/gift", true);
// Visit connections with AutoZap params
const autoZapParams =
"/settings/connections?return_to=https%3A%2F%2Fwww.zapplepay.com%2Fautozap%2Fnpub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s&name=AutoZap-jb55&budget_renewal=day&max_amount=420";
await page.goto("http://localhost:3420" + autoZapParams);
await expect(page.locator('[role="dialog"] h2 header').first()).toHaveText(
"Add Connection"
);
// Redshift
await page.goto("http://localhost:3420/redshift");
await expect(page.locator("h1")).toHaveText("Redshift (coming soon)");
checklist.set("/redshift", true);
await page.goBack();
// Swap
await page.goto("http://localhost:3420/swap");
await expect(page.locator("h1")).toHaveText("Swap to Lightning");
checklist.set("/swap", true);
// Gift
await page.goto("http://localhost:3420/settings/gift");
await expect(page.locator("h1")).toHaveText("Create Gift");
checklist.set("/settings/gift", true);
// Encrypt
await page.goto("http://localhost:3420/settings/encrypt");
await expect(page.locator("h1")).toHaveText(
"Encrypt your seed words (optional)"
);
checklist.set("/settings/encrypt", true);
// print how many routes we've visited
checklist.forEach((value, key) => {
console.log(`${key}: ${value}`);
});
});