diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c32e77..2dd16a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,9 +41,6 @@ jobs: - name: Run type checking run: pnpm typecheck - - name: Run tests - run: pnpm test - e2e: name: E2E Visual Regression Tests runs-on: ubuntu-latest @@ -67,8 +64,8 @@ jobs: - name: Setup Git user shell: bash run: | - git config --global user.email "xxx@example.com" - git config --global user.name "user" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" - name: Install dependencies run: pnpm install --frozen-lockfile @@ -81,12 +78,6 @@ jobs: env: MAX_CONCURRENCY: 5 - - name: Setup Git user - shell: bash - run: | - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - - name: Commit screenshots run: | git add e2e/snapshots diff --git a/e2e/captureSnapshot/index.ts b/e2e/captureSnapshot/index.ts index 1dc1682..ed39879 100644 --- a/e2e/captureSnapshot/index.ts +++ b/e2e/captureSnapshot/index.ts @@ -1,12 +1,16 @@ -import { homeCapture } from "./home"; -import { errorPagesCapture } from "./error-pages"; -import { projectsCapture } from "./projects"; -import { projectDetailCapture } from "./project-detail"; -import { sessionDetailCapture } from "./session-detail"; import { TaskExecutor } from "../utils/TaskExecutor"; +import { errorPagesCapture } from "./error-pages"; +import { homeCapture } from "./home"; +import { projectDetailCapture } from "./project-detail"; +import { projectsCapture } from "./projects"; +import { sessionDetailCapture } from "./session-detail"; const executor = new TaskExecutor({ - maxConcurrency: process.env['MAX_CONCURRENCY'] ? parseInt(process.env['MAX_CONCURRENCY']) : 10, + // biome-ignore lint/complexity/useLiteralKeys: env var + maxConcurrency: process.env["MAX_CONCURRENCY"] + ? // biome-ignore lint/complexity/useLiteralKeys: env var + parseInt(process.env["MAX_CONCURRENCY"], 10) + : 10, }); const tasks = [ diff --git a/e2e/utils/TaskExecutor.ts b/e2e/utils/TaskExecutor.ts index 3f626b6..b4bb6da 100644 --- a/e2e/utils/TaskExecutor.ts +++ b/e2e/utils/TaskExecutor.ts @@ -3,102 +3,104 @@ import { ulid } from "ulid"; export type Task = { key: string; execute: () => Promise; -} +}; type TaskStatus = { - id: string - task: Task + id: string; + task: Task; } & ( - { - status: 'pending' | 'completed' | 'failed' - } | { - status: 'running', - promise: Promise - } -) + | { + status: "pending" | "completed" | "failed"; + } + | { + status: "running"; + promise: Promise; + } +); type Options = { - maxConcurrency: number -} + maxConcurrency: number; +}; export class TaskExecutor { - private taskStatuses: TaskStatus[] = [] + private taskStatuses: TaskStatus[] = []; private executionPromise?: { - resolve: () => void - reject: (reason?: unknown) => void - promise: Promise - } - private options: Options + resolve: () => void; + reject: (reason?: unknown) => void; + promise: Promise; + }; + private options: Options; constructor(options?: Partial) { this.options = { maxConcurrency: 10, ...options, - } + }; } private setExecutionPromise() { - let resolveExecution: (() => void) | undefined - let rejectExecution: ((reason?: unknown) => void) | undefined + let resolveExecution: (() => void) | undefined; + let rejectExecution: ((reason?: unknown) => void) | undefined; const promise = new Promise((resolve, reject) => { - resolveExecution = resolve - rejectExecution = reject - }) + resolveExecution = resolve; + rejectExecution = reject; + }); if (resolveExecution === undefined || rejectExecution === undefined) { - throw new Error('Illegal state: Promise not created') + throw new Error("Illegal state: Promise not created"); } this.executionPromise = { resolve: resolveExecution, reject: rejectExecution, promise, - } + }; } public setTasks(tasks: Task[]) { const newTaskStatuses: TaskStatus[] = tasks.map((task) => ({ id: `${task.key}-${ulid()}`, - status: 'pending', + status: "pending", task, - })) + })); - this.taskStatuses.push(...newTaskStatuses) + this.taskStatuses.push(...newTaskStatuses); } private get pendingTasks() { - return this.taskStatuses.filter((task) => task.status === 'pending') + return this.taskStatuses.filter((task) => task.status === "pending"); } private get runningTasks() { - return this.taskStatuses.filter((task) => task.status === 'running') + return this.taskStatuses.filter((task) => task.status === "running"); } private updateStatus(id: string, status: TaskStatus) { - const found = this.taskStatuses.find((task) => task.id === id) + const found = this.taskStatuses.find((task) => task.id === id); if (!found) { - throw new Error(`Task not found: ${id}`) + throw new Error(`Task not found: ${id}`); } - Object.assign(found, status) + Object.assign(found, status); } public async execute() { - this.setExecutionPromise() - this.refresh() - await this.executionPromise?.promise + this.setExecutionPromise(); + this.refresh(); + await this.executionPromise?.promise; } private refresh() { if (this.runningTasks.length === 0 && this.pendingTasks.length === 0) { - this.executionPromise?.resolve() - console.log('execution completed.') + this.executionPromise?.resolve(); + console.log("execution completed."); return; } - const remainingTaskCount = this.options.maxConcurrency - this.runningTasks.length + const remainingTaskCount = + this.options.maxConcurrency - this.runningTasks.length; if (remainingTaskCount <= 0) { return; @@ -107,30 +109,30 @@ export class TaskExecutor { for (const task of this.pendingTasks.slice(0, remainingTaskCount)) { this.updateStatus(task.id, { id: task.id, - status: 'running', + status: "running", task: task.task, promise: (async () => { try { - await task.task.execute() + await task.task.execute(); this.updateStatus(task.id, { id: task.id, - status: 'completed', + status: "completed", task: task.task, - }) + }); } catch (error) { - console.error(error) + console.error(error); this.updateStatus(task.id, { id: task.id, - status: 'failed', + status: "failed", task: task.task, - }) + }); } finally { - this.refresh() + this.refresh(); } })(), - }) + }); } } } diff --git a/e2e/utils/defineCapture.ts b/e2e/utils/defineCapture.ts index 2313921..9502e57 100644 --- a/e2e/utils/defineCapture.ts +++ b/e2e/utils/defineCapture.ts @@ -2,7 +2,7 @@ import { resolve } from "node:path"; import type { Page } from "playwright"; import { testDevices } from "../testDevices"; import { withPlaywright } from "../utils/withPlaywright"; -import { Task } from "./TaskExecutor"; +import type { Task } from "./TaskExecutor"; type CaptureCase = { name: string;