From 28df4ae76356e6183b17b95c61045560d35d1512 Mon Sep 17 00:00:00 2001 From: tmm Date: Thu, 29 Jan 2026 12:56:58 -0500 Subject: [PATCH 1/4] test: add more e2e tests --- biome.json | 10 +++- e2e/faucet.test.ts | 20 +++++++ e2e/passkey-accounts.test.ts | 47 +++++++++++++++ e2e/send-a-payment.test.ts | 58 +++++++++++++++++++ .../guides/steps/payments/SendPayment.tsx | 4 +- 5 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 e2e/faucet.test.ts create mode 100644 e2e/passkey-accounts.test.ts create mode 100644 e2e/send-a-payment.test.ts diff --git a/biome.json b/biome.json index 933e82b6..b1b81b1d 100644 --- a/biome.json +++ b/biome.json @@ -40,6 +40,14 @@ }, "files": { "ignoreUnknown": false, - "includes": ["**", "!dist", "!node_modules", "!specs/lib", "!src/snippets/unformatted"] + "includes": [ + "**", + "!dist", + "!node_modules", + "!playwright-report", + "!specs/lib", + "!src/snippets/unformatted", + "!test-results" + ] } } diff --git a/e2e/faucet.test.ts b/e2e/faucet.test.ts new file mode 100644 index 00000000..a5e04a6e --- /dev/null +++ b/e2e/faucet.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from '@playwright/test' + +test('fund an address via faucet', async ({ page }) => { + await page.goto('/quickstart/faucet') + + // Switch to "Fund an address" tab + const tab = page.getByRole('tab', { name: 'Fund an address' }) + await expect(tab).toBeVisible({ timeout: 60000 }) + await tab.click() + + // Enter an address + const addressInput = page.getByPlaceholder('0x...') + await addressInput.fill('0xbeefcafe54750903ac1c8909323af7beb21ea2cb') + + // Click "Add funds" button + await page.getByRole('button', { name: 'Add funds' }).click() + + // Confirm "View receipt" link is visible + await expect(page.getByRole('link', { name: 'View receipt' })).toBeVisible({ timeout: 60000 }) +}) diff --git a/e2e/passkey-accounts.test.ts b/e2e/passkey-accounts.test.ts new file mode 100644 index 00000000..9d1b8433 --- /dev/null +++ b/e2e/passkey-accounts.test.ts @@ -0,0 +1,47 @@ +import { expect, test } from '@playwright/test' + +test('sign up, sign out, then sign in with passkey', async ({ page }) => { + // Set up virtual authenticator via CDP + const client = await page.context().newCDPSession(page) + await client.send('WebAuthn.enable') + const { authenticatorId } = await client.send('WebAuthn.addVirtualAuthenticator', { + options: { + protocol: 'ctap2', + transport: 'internal', + hasResidentKey: true, + hasUserVerification: true, + isUserVerified: true, + }, + }) + + await page.goto('/guide/use-accounts/embed-passkeys') + + // Wait for the demo to load + const signUpButton = page.getByRole('button', { name: 'Sign up' }).first() + await expect(signUpButton).toBeVisible({ timeout: 60000 }) + + // Sign up with passkey + await signUpButton.click() + + // Wait for sign out button (indicates successful sign up) + const signOutButton = page.getByRole('button', { name: 'Sign out' }).first() + await expect(signOutButton).toBeVisible({ timeout: 30000 }) + + // Sign out + await signOutButton.click() + + // Wait for sign in button to reappear + const signInButton = page.getByRole('button', { name: 'Sign in' }).first() + await expect(signInButton).toBeVisible({ timeout: 10000 }) + + // Sign in with the same passkey + await signInButton.click() + + // Confirm signed in again (sign out button visible) + await expect(page.getByRole('button', { name: 'Sign out' }).first()).toBeVisible({ + timeout: 30000, + }) + + // Clean up + await client.send('WebAuthn.removeVirtualAuthenticator', { authenticatorId }) +}) diff --git a/e2e/send-a-payment.test.ts b/e2e/send-a-payment.test.ts new file mode 100644 index 00000000..d35d6238 --- /dev/null +++ b/e2e/send-a-payment.test.ts @@ -0,0 +1,58 @@ +import { expect, test } from '@playwright/test' + +test('send a payment', async ({ page }) => { + // Set up virtual authenticator via CDP + const client = await page.context().newCDPSession(page) + await client.send('WebAuthn.enable') + const { authenticatorId } = await client.send('WebAuthn.addVirtualAuthenticator', { + options: { + protocol: 'ctap2', + transport: 'internal', + hasResidentKey: true, + hasUserVerification: true, + isUserVerified: true, + }, + }) + + await page.goto('/guide/payments/send-a-payment') + + // Step 1: Sign up with passkey + const signUpButton = page.getByRole('button', { name: 'Sign up' }).first() + await expect(signUpButton).toBeVisible({ timeout: 60000 }) + await signUpButton.click() + + // Wait for sign out button (indicates successful sign up) + await expect(page.getByRole('button', { name: 'Sign out' }).first()).toBeVisible({ + timeout: 30000, + }) + + // Step 2: Add funds + const addFundsButton = page.getByRole('button', { name: 'Add funds' }).first() + await expect(addFundsButton).toBeVisible() + await addFundsButton.click() + + // Wait for "Add more funds" button (indicates funds were added) + await expect(page.getByRole('button', { name: 'Add more funds' }).first()).toBeVisible({ + timeout: 60000, + }) + + // Step 3: Send payment + const enterDetailsButton = page.getByRole('button', { name: 'Enter details' }).first() + await expect(enterDetailsButton).toBeVisible() + await enterDetailsButton.click() + + // Fill in optional memo + const memoInput = page.getByLabel('Memo (optional)').first() + await expect(memoInput).toBeVisible() + await memoInput.fill('test-memo') + + // Click send + const sendButton = page.getByRole('button', { name: 'Send' }).first() + await sendButton.click() + + // Wait for transaction receipt link + await expect(page.getByRole('link', { name: 'View receipt' })).toBeVisible({ timeout: 60000 }) + + // Clean up + await client.send('WebAuthn.removeVirtualAuthenticator', { authenticatorId }) +}) diff --git a/src/components/guides/steps/payments/SendPayment.tsx b/src/components/guides/steps/payments/SendPayment.tsx index 01b4ba2b..3f64a50e 100644 --- a/src/components/guides/steps/payments/SendPayment.tsx +++ b/src/components/guides/steps/payments/SendPayment.tsx @@ -105,6 +105,7 @@ export function SendPayment(props: DemoStepProps) { )} {switchChain.isSuccess && ( -
+
Added Tempo to {connector?.name ?? 'Wallet'}!
)} diff --git a/src/components/IndexSupplyQuery.tsx b/src/components/IndexSupplyQuery.tsx index ac18c85c..ceac85cb 100644 --- a/src/components/IndexSupplyQuery.tsx +++ b/src/components/IndexSupplyQuery.tsx @@ -246,7 +246,7 @@ export function IndexSupplyQuery(props: IndexSupplyQueryProps = {}) { return ( +

{props.title || 'IndexSupply SQL Query'}

} @@ -325,7 +325,7 @@ export function IndexSupplyQuery(props: IndexSupplyQueryProps = {}) {
{error && ( -
+
{error}
)} diff --git a/src/components/TokenSelector.tsx b/src/components/TokenSelector.tsx index df4fff2b..eca9ac78 100644 --- a/src/components/TokenSelector.tsx +++ b/src/components/TokenSelector.tsx @@ -29,7 +29,7 @@ export function TokenSelector(props: TokenSelectorProps) { name={name} value={value} onChange={(e) => onChange(e.target.value as Address)} - className="-tracking-[2%] h-[34px] rounded-lg border border-gray4 px-3.25 font-normal text-[14px] text-black dark:text-white" + className="h-[34px] rounded-lg border border-gray4 px-3.25 font-normal text-[14px] text-black -tracking-[2%] dark:text-white" > {tokens.map((token) => ( diff --git a/src/components/guides/Demo.tsx b/src/components/guides/Demo.tsx index fc26a485..a0f7c33b 100644 --- a/src/components/guides/Demo.tsx +++ b/src/components/guides/Demo.tsx @@ -51,7 +51,7 @@ export function ExplorerLink({ hash }: { hash: string }) { href={url} target="_blank" rel="noreferrer" - className="-tracking-[1%] flex items-center gap-1 text-[13px] text-accent hover:underline" + className="flex items-center gap-1 text-[13px] text-accent -tracking-[1%] hover:underline" onClick={() => trackExternalLinkClick(url, 'View receipt')} > View receipt @@ -71,7 +71,7 @@ export function ExplorerAccountLink({ address }: { address: string }) { href={url} target="_blank" rel="noreferrer" - className="-tracking-[1%] flex items-center gap-1 text-[13px] text-accent hover:underline" + className="flex items-center gap-1 text-[13px] text-accent -tracking-[1%] hover:underline" onClick={() => trackExternalLinkClick(url, 'View account')} > View account @@ -142,7 +142,7 @@ export function Container( -

+

{name}

{showBadge && ( @@ -322,7 +322,7 @@ export function Step( > {completed ? : number}
-
+
{title}
@@ -334,7 +334,7 @@ export function Step( {error && ( <>
-
+
{'shortMessage' in error ? error.shortMessage : error.message}
@@ -376,7 +376,7 @@ export function Login() {
diff --git a/src/components/guides/steps/amm/CheckFeeAmmPool.tsx b/src/components/guides/steps/amm/CheckFeeAmmPool.tsx index f644cd69..050307ff 100644 --- a/src/components/guides/steps/amm/CheckFeeAmmPool.tsx +++ b/src/components/guides/steps/amm/CheckFeeAmmPool.tsx @@ -49,7 +49,7 @@ export function CheckFeeAmmPool(props: DemoStepProps) { {active && pool && lpBalance && (
-
+
Your LP Balance diff --git a/src/components/guides/steps/amm/MintFeeAmmLiquidity.tsx b/src/components/guides/steps/amm/MintFeeAmmLiquidity.tsx index 724e3c21..e8cf3b95 100644 --- a/src/components/guides/steps/amm/MintFeeAmmLiquidity.tsx +++ b/src/components/guides/steps/amm/MintFeeAmmLiquidity.tsx @@ -115,7 +115,7 @@ export function MintFeeAmmLiquidity(props: DemoStepProps & { waitForBalance?: bo disabled={!active || mintFeeLiquidity.isPending} onClick={handleMintAll} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {mintFeeLiquidity.isPending ? 'Adding...' diff --git a/src/components/guides/steps/exchange/ApproveSpend.tsx b/src/components/guides/steps/exchange/ApproveSpend.tsx index a8e60173..3205d9e7 100644 --- a/src/components/guides/steps/exchange/ApproveSpend.tsx +++ b/src/components/guides/steps/exchange/ApproveSpend.tsx @@ -43,7 +43,7 @@ export function ApproveSpend(props: DemoStepProps) { }) }} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {approve.isPending ? 'Approving...' : 'Approve Spend'} diff --git a/src/components/guides/steps/exchange/BuySwap.tsx b/src/components/guides/steps/exchange/BuySwap.tsx index f02019c3..0648c0b5 100644 --- a/src/components/guides/steps/exchange/BuySwap.tsx +++ b/src/components/guides/steps/exchange/BuySwap.tsx @@ -76,7 +76,7 @@ export function BuySwap({ onSuccess }: { onSuccess?: () => void }) { }) }} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {sendCalls.isPending ? 'Buying...' : 'Buy'} diff --git a/src/components/guides/steps/exchange/CancelOrder.tsx b/src/components/guides/steps/exchange/CancelOrder.tsx index 37159f2c..19923ad8 100644 --- a/src/components/guides/steps/exchange/CancelOrder.tsx +++ b/src/components/guides/steps/exchange/CancelOrder.tsx @@ -45,7 +45,7 @@ export function CancelOrder(props: DemoStepProps) { } }} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {cancelOrder.isPending ? 'Canceling...' : 'Cancel Order'} diff --git a/src/components/guides/steps/exchange/PlaceOrder.tsx b/src/components/guides/steps/exchange/PlaceOrder.tsx index f8ff7378..c372fdda 100644 --- a/src/components/guides/steps/exchange/PlaceOrder.tsx +++ b/src/components/guides/steps/exchange/PlaceOrder.tsx @@ -78,7 +78,7 @@ export function PlaceOrder(props: DemoStepProps) { }) }} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {sendCalls.isPending ? 'Placing Order...' : 'Place Order'} diff --git a/src/components/guides/steps/exchange/QueryOrder.tsx b/src/components/guides/steps/exchange/QueryOrder.tsx index 6e0255a0..75ae4db9 100644 --- a/src/components/guides/steps/exchange/QueryOrder.tsx +++ b/src/components/guides/steps/exchange/QueryOrder.tsx @@ -52,7 +52,7 @@ export function QueryOrder(props: DemoStepProps) { disabled={!active || isQuerying} onClick={handleQuery} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {isQuerying ? 'Querying...' : hasQueried ? 'Query Again' : 'Query Order'} diff --git a/src/components/guides/steps/exchange/SellSwap.tsx b/src/components/guides/steps/exchange/SellSwap.tsx index e705013f..8b52cd6a 100644 --- a/src/components/guides/steps/exchange/SellSwap.tsx +++ b/src/components/guides/steps/exchange/SellSwap.tsx @@ -76,7 +76,7 @@ export function SellSwap({ onSuccess }: { onSuccess?: () => void }) { }) }} type="button" - className="-tracking-[2%] font-normal text-[14px]" + className="font-normal text-[14px] -tracking-[2%]" > {sendCalls.isPending ? 'Selling...' : 'Sell'} diff --git a/src/components/guides/steps/issuance/BurnToken.tsx b/src/components/guides/steps/issuance/BurnToken.tsx index 85586540..0f3de823 100644 --- a/src/components/guides/steps/issuance/BurnToken.tsx +++ b/src/components/guides/steps/issuance/BurnToken.tsx @@ -73,7 +73,7 @@ export function BurnToken(props: DemoStepProps) { @@ -98,11 +98,11 @@ export function BurnToken(props: DemoStepProps) {
-