diff --git a/e2e/captureSnapshot/error-pages.ts b/e2e/captureSnapshot/error-pages.ts index da28643..113ba29 100644 --- a/e2e/captureSnapshot/error-pages.ts +++ b/e2e/captureSnapshot/error-pages.ts @@ -1,21 +1,21 @@ import { resolve } from "node:path"; -import { withPlaywright } from "../utils/withPlaywright"; import { testDevices } from "../testDevices"; +import { withPlaywright } from "../utils/withPlaywright"; // Different error scenarios to capture const errorScenarios = [ { name: "404", - url: "http://localhost:4000/non-existent-page" + url: "http://localhost:4000/non-existent-page", }, { name: "invalid-project", - url: "http://localhost:4000/projects/non-existent-project" + url: "http://localhost:4000/projects/non-existent-project", }, { name: "invalid-session", - url: "http://localhost:4000/projects/sample-project/sessions/non-existent-session" - } + url: "http://localhost:4000/projects/sample-project/sessions/non-existent-session", + }, ]; for (const scenario of errorScenarios) { @@ -25,7 +25,12 @@ for (const scenario of errorScenarios) { const page = await context.newPage(); await page.goto(scenario.url); await page.screenshot({ - path: resolve("e2e", "snapshots", "errors", `${scenario.name}_${name}.png`), + path: resolve( + "e2e", + "snapshots", + "errors", + `${scenario.name}_${name}.png`, + ), fullPage: true, }); await cleanUp(); @@ -37,4 +42,4 @@ for (const scenario of errorScenarios) { }, ); } -} \ No newline at end of file +} diff --git a/e2e/captureSnapshot/home.ts b/e2e/captureSnapshot/home.ts index 1c61810..25f51ca 100644 --- a/e2e/captureSnapshot/home.ts +++ b/e2e/captureSnapshot/home.ts @@ -1,13 +1,13 @@ import { resolve } from "node:path"; -import { withPlaywright } from "../utils/withPlaywright"; import { testDevices } from "../testDevices"; +import { withPlaywright } from "../utils/withPlaywright"; for (const { device, name } of testDevices) { await withPlaywright( async ({ context, cleanUp }) => { const page = await context.newPage(); await page.goto("http://localhost:4000/"); - await page.waitForLoadState('networkidle'); + await page.waitForLoadState("networkidle"); await page.screenshot({ path: resolve("e2e", "snapshots", "root", `${name}.png`), fullPage: true, @@ -20,4 +20,4 @@ for (const { device, name } of testDevices) { }, }, ); -} \ No newline at end of file +} diff --git a/e2e/captureSnapshot/index.ts b/e2e/captureSnapshot/index.ts index c8a3c73..0cca057 100644 --- a/e2e/captureSnapshot/index.ts +++ b/e2e/captureSnapshot/index.ts @@ -1,5 +1,5 @@ import { execSync } from "node:child_process"; -import { resolve, dirname } from "node:path"; +import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const __filename = fileURLToPath(import.meta.url); @@ -7,32 +7,34 @@ const __dirname = dirname(__filename); const scripts = [ "home.ts", - "projects.ts", + "projects.ts", "project-detail.ts", "session-detail.ts", - "error-pages.ts" + "error-pages.ts", ]; async function captureAllSnapshots() { console.log("🚀 Starting screenshot capture for all pages...\n"); - + for (const script of scripts) { const scriptPath = resolve(__dirname, script); - console.log(`📸 Capturing: ${script.replace('.ts', '')}...`); - + console.log(`📸 Capturing: ${script.replace(".ts", "")}...`); + try { // Execute each script using tsx - execSync(`npx tsx "${scriptPath}"`, { - stdio: 'inherit', - cwd: resolve(__dirname, "..", "..") + execSync(`npx tsx "${scriptPath}"`, { + stdio: "inherit", + cwd: resolve(__dirname, "..", ".."), }); - console.log(`✅ Completed: ${script.replace('.ts', '')}\n`); + console.log(`✅ Completed: ${script.replace(".ts", "")}\n`); } catch (error) { - console.error(`❌ Failed: ${script.replace('.ts', '')} - ${error.message}\n`); + console.error( + `❌ Failed: ${script.replace(".ts", "")} - ${error.message}\n`, + ); } } - + console.log("🎉 All screenshot captures completed!"); } -captureAllSnapshots().catch(console.error); \ No newline at end of file +captureAllSnapshots().catch(console.error); diff --git a/e2e/captureSnapshot/project-detail.ts b/e2e/captureSnapshot/project-detail.ts index b91e3d3..a76aff7 100644 --- a/e2e/captureSnapshot/project-detail.ts +++ b/e2e/captureSnapshot/project-detail.ts @@ -1,24 +1,34 @@ import { resolve } from "node:path"; -import { withPlaywright } from "../utils/withPlaywright"; import { testDevices } from "../testDevices"; +import { withPlaywright } from "../utils/withPlaywright"; // Test different UI states on project detail page const testStates = [ - { name: 'default', action: null }, - { name: 'filters-expanded', action: async (page) => { - const filterToggle = page.locator('[data-testid="filter-toggle"], button:has-text("Filters"), .filter-toggle'); - if (await filterToggle.isVisible()) { - await filterToggle.click(); - await page.waitForTimeout(300); - } - }}, - { name: 'new-chat-modal', action: async (page) => { - const newChatButton = page.locator('button:has-text("New Chat"), [data-testid="new-chat"], .new-chat-button'); - if (await newChatButton.isVisible()) { - await newChatButton.click(); - await page.waitForTimeout(300); - } - }} + { name: "default", action: null }, + { + name: "filters-expanded", + action: async (page) => { + const filterToggle = page.locator( + '[data-testid="filter-toggle"], button:has-text("Filters"), .filter-toggle', + ); + if (await filterToggle.isVisible()) { + await filterToggle.click(); + await page.waitForTimeout(300); + } + }, + }, + { + name: "new-chat-modal", + action: async (page) => { + const newChatButton = page.locator( + 'button:has-text("New Chat"), [data-testid="new-chat"], .new-chat-button', + ); + if (await newChatButton.isVisible()) { + await newChatButton.click(); + await page.waitForTimeout(300); + } + }, + }, ]; for (const state of testStates) { @@ -27,14 +37,20 @@ for (const state of testStates) { async ({ context, cleanUp }) => { const page = await context.newPage(); await page.goto("http://localhost:4000/projects/sample-project"); - await page.waitForLoadState('networkidle'); - + await page.waitForLoadState("networkidle"); + if (state.action) { await state.action(page); } - + await page.screenshot({ - path: resolve("e2e", "snapshots", "project-detail", state.name, `${name}.png`), + path: resolve( + "e2e", + "snapshots", + "project-detail", + state.name, + `${name}.png`, + ), fullPage: true, }); await cleanUp(); @@ -46,4 +62,4 @@ for (const state of testStates) { }, ); } -} \ No newline at end of file +} diff --git a/e2e/captureSnapshot/projects.ts b/e2e/captureSnapshot/projects.ts index 10337da..8d2a936 100644 --- a/e2e/captureSnapshot/projects.ts +++ b/e2e/captureSnapshot/projects.ts @@ -1,14 +1,17 @@ import { resolve } from "node:path"; -import { withPlaywright } from "../utils/withPlaywright"; import { testDevices } from "../testDevices"; +import { withPlaywright } from "../utils/withPlaywright"; // Test different states on projects page const testStates = [ - { name: 'default', action: null }, - { name: 'empty', action: async (page) => { - // Check for empty state (this will capture whatever state exists) - await page.waitForTimeout(500); - }} + { name: "default", action: null }, + { + name: "empty", + action: async (page) => { + // Check for empty state (this will capture whatever state exists) + await page.waitForTimeout(500); + }, + }, ]; for (const state of testStates) { @@ -17,14 +20,20 @@ for (const state of testStates) { async ({ context, cleanUp }) => { const page = await context.newPage(); await page.goto("http://localhost:4000/projects"); - await page.waitForLoadState('networkidle'); - + await page.waitForLoadState("networkidle"); + if (state.action) { await state.action(page); } - + await page.screenshot({ - path: resolve("e2e", "snapshots", "projects", state.name, `${name}.png`), + path: resolve( + "e2e", + "snapshots", + "projects", + state.name, + `${name}.png`, + ), fullPage: true, }); await cleanUp(); @@ -36,4 +45,4 @@ for (const state of testStates) { }, ); } -} \ No newline at end of file +} diff --git a/e2e/captureSnapshot/session-detail.ts b/e2e/captureSnapshot/session-detail.ts index cb946a7..5888449 100644 --- a/e2e/captureSnapshot/session-detail.ts +++ b/e2e/captureSnapshot/session-detail.ts @@ -1,24 +1,29 @@ import { resolve } from "node:path"; -import { withPlaywright } from "../utils/withPlaywright"; import { testDevices } from "../testDevices"; +import { withPlaywright } from "../utils/withPlaywright"; -// Multiple session IDs to capture different session detail pages +// Multiple session IDs to capture different session detail pages const sessionIds = [ "1af7fc5e-8455-4414-9ccd-011d40f70b2a", - "5c0375b4-57a5-4f26-b12d-d022ee4e51b7", - "fe5e1c67-53e7-4862-81ae-d0e013e3270b" + "5c0375b4-57a5-4f26-b12d-d022ee4e51b7", + "fe5e1c67-53e7-4862-81ae-d0e013e3270b", ]; -// Test different sidebar states +// Test different sidebar states const testStates = [ - { name: 'default', action: null }, - { name: 'sidebar-open', action: async (page) => { - const menuButton = page.locator('[data-testid="menu-button"], button:has-text("Menu"), .menu-toggle, .hamburger'); - if (await menuButton.isVisible()) { - await menuButton.click(); - await page.waitForTimeout(300); - } - }} + { name: "default", action: null }, + { + name: "sidebar-open", + action: async (page) => { + const menuButton = page.locator( + '[data-testid="menu-button"], button:has-text("Menu"), .menu-toggle, .hamburger', + ); + if (await menuButton.isVisible()) { + await menuButton.click(); + await page.waitForTimeout(300); + } + }, + }, ]; for (const sessionId of sessionIds) { @@ -27,16 +32,24 @@ for (const sessionId of sessionIds) { await withPlaywright( async ({ context, cleanUp }) => { const page = await context.newPage(); - await page.goto(`http://localhost:4000/projects/sample-project/sessions/${sessionId}`); - await page.waitForLoadState('networkidle'); - + await page.goto( + `http://localhost:4000/projects/sample-project/sessions/${sessionId}`, + ); + await page.waitForLoadState("networkidle"); + if (state.action) { await state.action(page); } - + // Create separate directories for each session await page.screenshot({ - path: resolve("e2e", "snapshots", "session-detail", state.name, `${sessionId}_${name}.png`), + path: resolve( + "e2e", + "snapshots", + "session-detail", + state.name, + `${sessionId}_${name}.png`, + ), fullPage: true, }); await cleanUp(); @@ -49,4 +62,4 @@ for (const sessionId of sessionIds) { ); } } -} \ No newline at end of file +} diff --git a/e2e/example.ts b/e2e/example.ts index 83bc3ef..cfb1bf2 100644 --- a/e2e/example.ts +++ b/e2e/example.ts @@ -1,6 +1,6 @@ import { resolve } from "node:path"; -import { withPlaywright } from "./utils/withPlaywright"; import { testDevices } from "./testDevices"; +import { withPlaywright } from "./utils/withPlaywright"; for (const { device, name } of testDevices) { await withPlaywright( diff --git a/e2e/utils/snapshot-utils.ts b/e2e/utils/snapshot-utils.ts index 8f9f4e1..ababe02 100644 --- a/e2e/utils/snapshot-utils.ts +++ b/e2e/utils/snapshot-utils.ts @@ -1,6 +1,6 @@ import { resolve } from "node:path"; -import { withPlaywright } from "./withPlaywright"; import { testDevices } from "../testDevices"; +import { withPlaywright } from "./withPlaywright"; /** * Take screenshots for a given URL across all test devices @@ -11,7 +11,7 @@ export async function takeScreenshots( options?: { waitForSelector?: string; timeout?: number; - } + }, ) { const { waitForSelector, timeout = 5000 } = options || {}; @@ -19,21 +19,21 @@ export async function takeScreenshots( await withPlaywright( async ({ context, cleanUp }) => { const page = await context.newPage(); - + try { await page.goto(url); - + // Wait for the page to load - await page.waitForLoadState('networkidle'); - + await page.waitForLoadState("networkidle"); + // Wait for specific selector if provided if (waitForSelector) { await page.waitForSelector(waitForSelector, { timeout }); } - + // Additional wait for content to stabilize await page.waitForTimeout(1000); - + // Hide dynamic content that might cause flaky screenshots await page.addStyleTag({ content: ` @@ -51,9 +51,9 @@ export async function takeScreenshots( transition-duration: 0s !important; transition-delay: 0s !important; } - ` + `, }); - + await page.screenshot({ path: resolve("e2e", "snapshots", snapshotName, `${name}.png`), fullPage: true, @@ -66,7 +66,7 @@ export async function takeScreenshots( contextOptions: { ...device, }, - } + }, ); } } @@ -80,7 +80,7 @@ export async function takeElementScreenshots( snapshotName: string, options?: { timeout?: number; - } + }, ) { const { timeout = 5000 } = options || {}; @@ -88,25 +88,30 @@ export async function takeElementScreenshots( await withPlaywright( async ({ context, cleanUp }) => { const page = await context.newPage(); - + try { await page.goto(url); - await page.waitForLoadState('networkidle'); - + await page.waitForLoadState("networkidle"); + const element = page.locator(selector); - await element.waitFor({ state: 'visible', timeout }); - + await element.waitFor({ state: "visible", timeout }); + await page.addStyleTag({ content: ` *, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; } - ` + `, }); - + await element.screenshot({ - path: resolve("e2e", "snapshots", snapshotName, `${name}-element.png`), + path: resolve( + "e2e", + "snapshots", + snapshotName, + `${name}-element.png`, + ), }); } finally { await cleanUp(); @@ -116,7 +121,7 @@ export async function takeElementScreenshots( contextOptions: { ...device, }, - } + }, ); } -} \ No newline at end of file +}