diff --git a/e2e/analytics.spec.ts b/e2e/analytics.spec.ts index e25a1f6..69723a1 100644 --- a/e2e/analytics.spec.ts +++ b/e2e/analytics.spec.ts @@ -7,7 +7,16 @@ import { test, expect, type Page } from '@playwright/test' // the same convention e2e/visual.spec.ts uses for dashboard screenshots. const DEMO_ADDRESS = 'GBQ2X7KFY3R4VZ6N5LJ7WQH3M2PD8C9SAUTV4EXAMPLE0WALLET00ADDR' +// The mock streams in lib/mock-data.ts are seeded with startTime offsets +// relative to Date.now() at module-evaluation time (e.g. "now - 90 days"). +// Without a frozen clock, which streams fall inside a given range depends on +// exactly when the test happens to run. Freeze the clock with Playwright's +// `page.clock` so the seeded offsets — and therefore the expected counts +// below — are deterministic regardless of the current date. +const FIXED_NOW = new Date('2025-06-15T12:00:00.000Z') + async function withWallet(page: Page, address: string = DEMO_ADDRESS) { + await page.clock.install({ time: FIXED_NOW }) await page.addInitScript((walletAddress) => { localStorage.setItem('walletId', 'xbull') ;(window as any).xBullSDK = { diff --git a/e2e/contract-integration.spec.ts b/e2e/contract-integration.spec.ts index abd6a28..8e63a74 100644 --- a/e2e/contract-integration.spec.ts +++ b/e2e/contract-integration.spec.ts @@ -1,4 +1,19 @@ -import { test, expect } from '@playwright/test' +import { test, expect, type Page } from '@playwright/test' + +// The create form is wrapped in `RequireWallet`, so without a connected +// wallet it only renders a connect prompt instead of the real form fields. +// Mirrors the helper used in e2e/accessibility.spec.ts. +async function withWallet(page: Page) { + await page.addInitScript(() => { + localStorage.setItem('walletId', 'xbull') + ;(window as any).xBullSDK = { + connect: async () => ({ + publicKey: 'GA4M5Y74MXREPXU6LGRR7WOC6VLXJBLKJHZBJGDBKOFIP7GBM3MHF3G5', + }), + signXDR: async () => 'AAAAAgAAAAA...dummy-signature...', + } + }) +} test.describe('Contract Integration Tests', () => { test.describe('Wallet Connection & Dashboard', () => { @@ -34,7 +49,7 @@ test.describe('Contract Integration Tests', () => { test('should display back button on stream detail page', async ({ page }) => { await page.goto('/app/stream/test-id') - const backBtn = page.locator('text=Dashboard') + const backBtn = page.getByRole('main').getByRole('link', { name: 'Dashboard' }) await expect(backBtn).toBeVisible() }) @@ -48,6 +63,7 @@ test.describe('Contract Integration Tests', () => { test.describe('Create Stream Form Validation', () => { test('should show create form with recipient field', async ({ page }) => { + await withWallet(page) await page.goto('/app/create') // Look for input fields typical of a stream creation form const inputs = page.locator('input[type="text"], input[type="number"]') @@ -69,6 +85,7 @@ test.describe('Contract Integration Tests', () => { }) test('should handle token selection', async ({ page }) => { + await withWallet(page) await page.goto('/app/create') const tokenInputs = page.locator('input, button').filter({ hasText: /XLM|USDC|token/ }) // At least one token selector should be visible @@ -209,6 +226,7 @@ test.describe('Contract Integration Tests', () => { }) test('should have accessible form labels', async ({ page }) => { + await withWallet(page) await page.goto('/app/create') const labels = page.locator('label') const count = await labels.count() diff --git a/e2e/visual.spec.ts b/e2e/visual.spec.ts index cdc27ce..10fcdb8 100644 --- a/e2e/visual.spec.ts +++ b/e2e/visual.spec.ts @@ -85,7 +85,9 @@ test.describe("Dashboard visual states", () => { test("dashboard connected with streams", async ({ page }) => { await preparePage(page, { theme: "light", connect: true }); await page.goto("/app"); - await expect(page.locator("text=Dashboard")).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Dashboard", level: 1 }), + ).toBeVisible(); await expect(page.locator("text=New stream")).toBeVisible(); await expect(page).toHaveScreenshot("dashboard-with-streams.png", { fullPage: true, @@ -95,7 +97,9 @@ test.describe("Dashboard visual states", () => { test("dashboard tabs: receiving and sent", async ({ page }) => { await preparePage(page, { theme: "light", connect: true }); await page.goto("/app"); - await expect(page.locator("text=Dashboard")).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Dashboard", level: 1 }), + ).toBeVisible(); await page.locator('button:has-text("Receiving")').first().click(); await expect(page.locator("text=Receiving")).toBeVisible(); @@ -131,8 +135,8 @@ test.describe("Create stream form", () => { await page.click('button:has-text("Create stream")'); await expect( page - .locator("text=Review transaction") - .or(page.locator("text=Create stream")), + .getByRole("heading", { name: "Transaction Preview" }) + .or(page.getByRole("button", { name: "Create stream" })), ).toBeVisible(); await expect(page).toHaveScreenshot("create-stream-filled.png", { fullPage: true, @@ -252,7 +256,9 @@ test.describe("Wallet and modal dialogs", () => { await preparePage(page, { theme: "light", connect: true }); await page.goto("/app/stream/1"); await page.locator('button:has-text("Cancel")').first().click(); - await expect(page.locator("text=Cancel stream")).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Cancel stream" }), + ).toBeVisible(); await expect(page).toHaveScreenshot("cancel-dialog.png", { fullPage: true, });