diff --git a/e2e/captureSnapshot/projects.ts b/e2e/captureSnapshot/projects.ts index 5818280..fad0109 100644 --- a/e2e/captureSnapshot/projects.ts +++ b/e2e/captureSnapshot/projects.ts @@ -2,4 +2,16 @@ import { defineCapture } from "../utils/defineCapture"; export const projectsCapture = defineCapture({ href: "/projects", + cases: [ + { + name: "new-project-modal", + setup: async (page) => { + const newProjectButton = page.locator( + '[data-testid="new-project-button"]', + ); + await newProjectButton.click(); + await page.waitForTimeout(1000); + }, + }, + ], }); diff --git a/e2e/captureSnapshot/session-detail.ts b/e2e/captureSnapshot/session-detail.ts index a5d316a..2c1dd14 100644 --- a/e2e/captureSnapshot/session-detail.ts +++ b/e2e/captureSnapshot/session-detail.ts @@ -12,14 +12,14 @@ export const sessionDetailCapture = defineCapture({ ); if (await menuButton.isVisible()) { await menuButton.click(); - await page.waitForTimeout(300); + await page.waitForTimeout(1000); const sessionsTabButton = page.locator( '[data-testid="sessions-tab-button-mobile"]', ); if (await sessionsTabButton.isVisible()) { await sessionsTabButton.click(); - await page.waitForTimeout(300); + await page.waitForTimeout(1000); } } else { const sessionsTabButton = page.locator( @@ -27,7 +27,7 @@ export const sessionDetailCapture = defineCapture({ ); if (await sessionsTabButton.isVisible()) { await sessionsTabButton.click(); - await page.waitForTimeout(300); + await page.waitForTimeout(1000); } } }, @@ -41,14 +41,14 @@ export const sessionDetailCapture = defineCapture({ ); if (await menuButton.isVisible()) { await menuButton.click(); - await page.waitForTimeout(300); + await page.waitForTimeout(1000); const settingsTabButton = page.locator( '[data-testid="settings-tab-button-mobile"]', ); if (await settingsTabButton.isVisible()) { await settingsTabButton.click(); - await page.waitForTimeout(300); + await page.waitForTimeout(1000); } } else { const settingsTabButton = page.locator( @@ -56,10 +56,35 @@ export const sessionDetailCapture = defineCapture({ ); if (await settingsTabButton.isVisible()) { await settingsTabButton.click(); - await page.waitForTimeout(300); + await page.waitForTimeout(1000); } } }, }, + + { + name: "start-new-chat", + setup: async (page) => { + const menuButton = page.locator( + '[data-testid="mobile-sidebar-toggle-button"]', + ); + if (await menuButton.isVisible()) { + await menuButton.click(); + await page.waitForTimeout(1000); + + const startNewChatButton = page.locator( + '[data-testid="start-new-chat-button-mobile"]', + ); + await startNewChatButton.click(); + await page.waitForTimeout(1000); + } else { + const startNewChatButton = page.locator( + '[data-testid="start-new-chat-button"]', + ); + await startNewChatButton.click(); + await page.waitForTimeout(1000); + } + }, + }, ], }); diff --git a/e2e/utils/defineCapture.ts b/e2e/utils/defineCapture.ts index 9502e57..ed6044a 100644 --- a/e2e/utils/defineCapture.ts +++ b/e2e/utils/defineCapture.ts @@ -26,34 +26,38 @@ export const defineCapture = (options: { ) => { await withPlaywright( async ({ context, cleanUp }) => { - const page = await context.newPage(); - await page.goto(href); + try { + const page = await context.newPage(); + await page.goto(href); - await page.waitForLoadState("domcontentloaded"); - await page.waitForTimeout(1000); + await page.waitForLoadState("domcontentloaded"); + await page.waitForTimeout(1000); - if (testCase) { - await testCase.setup(page); + if (testCase) { + await testCase.setup(page); + } + + await page.waitForTimeout(1000); + + const picturePath = testCase + ? resolve( + "e2e", + "snapshots", + ...paths, + testCase.name, + `${device.name}.png`, + ) + : resolve("e2e", "snapshots", ...paths, `${device.name}.png`); + + await page.screenshot({ + path: picturePath, + fullPage: true, + }); + + console.log(`[captured] ${picturePath}`); + } finally { + await cleanUp(); } - - const picturePath = testCase - ? resolve( - "e2e", - "snapshots", - ...paths, - testCase.name, - `${device.name}.png`, - ) - : resolve("e2e", "snapshots", ...paths, `${device.name}.png`); - - await page.screenshot({ - path: picturePath, - fullPage: true, - }); - - console.log(`[captured] ${picturePath}`); - - await cleanUp(); }, { contextOptions: { diff --git a/e2e/utils/withPlaywright.ts b/e2e/utils/withPlaywright.ts index 34e3118..cd36410 100644 --- a/e2e/utils/withPlaywright.ts +++ b/e2e/utils/withPlaywright.ts @@ -1,5 +1,3 @@ -import { existsSync } from "node:fs"; -import path from "node:path"; import { type Browser, type BrowserContext, @@ -10,8 +8,6 @@ import { } from "playwright"; import prexit from "prexit"; -const STORAGE_PATH = path.join(process.cwd(), ".user-data", "session.json"); - type PlaywrightContext = { context: BrowserContext; cleanUp: () => Promise; @@ -35,7 +31,6 @@ const useBrowser = (options: BrowserOptions) => { ...launchOptions, }); context ??= await browser.newContext({ - storageState: existsSync(STORAGE_PATH) ? STORAGE_PATH : undefined, ...contextOptions, }); @@ -63,9 +58,6 @@ export const withPlaywright = async ( })(); let isClosed = false; const cleanUp = async () => { - await context.storageState({ - path: STORAGE_PATH, - }); await Promise.all(context.pages().map((page) => page.close())); await context.close(); await browser.close(); diff --git a/package.json b/package.json index c99fdd3..97ee80c 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,9 @@ "typecheck": "tsc --noEmit", "test": "vitest --run", "test:watch": "vitest", - "e2e": "./scripts/e2e.sh" + "e2e": "./scripts/e2e/exec_e2e.sh", + "e2e:start-server": "./scripts/e2e/start_server.sh", + "e2e:capture-snapshots": "./scripts/e2e/capture_snapshots.sh" }, "dependencies": { "@anthropic-ai/claude-code": "^1.0.98", diff --git a/scripts/e2e/capture_snapshots.sh b/scripts/e2e/capture_snapshots.sh new file mode 100755 index 0000000..7722d50 --- /dev/null +++ b/scripts/e2e/capture_snapshots.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export GLOBAL_CLAUDE_DIR=$(git rev-parse --show-toplevel)/mock-global-claude-dir + +pnpx tsx ./e2e/captureSnapshot/index.ts diff --git a/scripts/e2e.sh b/scripts/e2e/exec_e2e.sh similarity index 73% rename from scripts/e2e.sh rename to scripts/e2e/exec_e2e.sh index 9c87aad..4d7b271 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e/exec_e2e.sh @@ -2,12 +2,6 @@ set -euo pipefail -export PORT=4000 -export GLOBAL_CLAUDE_DIR=$(git rev-parse --show-toplevel)/mock-global-claude-dir - -echo "Check directory structure in $GLOBAL_CLAUDE_DIR:" -ls -l $GLOBAL_CLAUDE_DIR - kill_process_group() { local pid=$1 local sig=${2:-TERM} @@ -30,10 +24,10 @@ cleanup() { trap cleanup EXIT INT TERM -pnpm start & SERVER_PID=$! +./scripts/e2e/start_server.sh & SERVER_PID=$! echo "Server started. pid=$SERVER_PID" sleep 5 # 即時起動するが、一応少し待っておく -pnpx tsx ./e2e/captureSnapshot/index.ts +./scripts/e2e/capture_snapshots.sh echo "Completed capturing screenshots. Killing server..." diff --git a/scripts/e2e/start_server.sh b/scripts/e2e/start_server.sh new file mode 100755 index 0000000..8e90176 --- /dev/null +++ b/scripts/e2e/start_server.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +export PORT=4000 +export GLOBAL_CLAUDE_DIR=$(git rev-parse --show-toplevel)/mock-global-claude-dir + +echo "Check directory structure in $GLOBAL_CLAUDE_DIR:" +ls -l $GLOBAL_CLAUDE_DIR + +node ./dist/index.js diff --git a/src/app/projects/[projectId]/components/newChat/NewChatModal.tsx b/src/app/projects/[projectId]/components/newChat/NewChatModal.tsx index 066f82a..8df1f50 100644 --- a/src/app/projects/[projectId]/components/newChat/NewChatModal.tsx +++ b/src/app/projects/[projectId]/components/newChat/NewChatModal.tsx @@ -12,7 +12,7 @@ import { NewChat } from "./NewChat"; export const NewChatModal: FC<{ projectId: string; - trigger?: ReactNode; + trigger: ReactNode; }> = ({ projectId, trigger }) => { const [open, setOpen] = useState(false); @@ -22,15 +22,11 @@ export const NewChatModal: FC<{ return ( - - {trigger ?? ( - - )} - - + {trigger} + diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx index 1b1a8da..c89585c 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/SessionPageContent.tsx @@ -204,6 +204,7 @@ export const SessionPageContent: FC<{
= ({ hasNextPage={hasNextPage} isFetchingNextPage={isFetchingNextPage} onLoadMore={() => fetchNextPage()} + isMobile={true} /> ); case "mcp": diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionsTab.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionsTab.tsx index a57835a..2b377a7 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionsTab.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/sessionSidebar/SessionsTab.tsx @@ -19,6 +19,7 @@ export const SessionsTab: FC<{ hasNextPage?: boolean; isFetchingNextPage?: boolean; onLoadMore?: () => void; + isMobile?: boolean; }> = ({ sessions, currentSessionId, @@ -26,6 +27,7 @@ export const SessionsTab: FC<{ hasNextPage, isFetchingNextPage, onLoadMore, + isMobile = false, }) => { const sessionProcesses = useAtomValue(sessionProcessesAtom); @@ -70,7 +72,16 @@ export const SessionsTab: FC<{ + diff --git a/src/app/projects/components/CreateProjectDialog.tsx b/src/app/projects/components/CreateProjectDialog.tsx index 3dadbb2..b28d3e0 100644 --- a/src/app/projects/components/CreateProjectDialog.tsx +++ b/src/app/projects/components/CreateProjectDialog.tsx @@ -52,12 +52,12 @@ export const CreateProjectDialog: FC = () => { return ( - - + Create New Project