chore: fix a bit

This commit is contained in:
d-kimsuon
2025-10-12 23:06:21 +09:00
parent 6d081e54b8
commit a19d5f627c
4 changed files with 64 additions and 67 deletions

View File

@@ -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

View File

@@ -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 = [

View File

@@ -3,102 +3,104 @@ import { ulid } from "ulid";
export type Task = {
key: string;
execute: () => Promise<void>;
}
};
type TaskStatus = {
id: string
task: Task
id: string;
task: Task;
} & (
{
status: 'pending' | 'completed' | 'failed'
} | {
status: 'running',
promise: Promise<void>
}
)
| {
status: "pending" | "completed" | "failed";
}
| {
status: "running";
promise: Promise<void>;
}
);
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<void>
}
private options: Options
resolve: () => void;
reject: (reason?: unknown) => void;
promise: Promise<void>;
};
private options: Options;
constructor(options?: Partial<Options>) {
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<void>((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();
}
})(),
})
});
}
}
}

View File

@@ -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;