feat(scenario): run logs, lint/format tooling, CONTRIBUTING
- add ScenarioRunLogEntity to persist step script output to DB - stepLogger dual-writes to NestJS logger and DB (fire-and-forget) - add GET /scenarios/:id/run/:runId returning run, stepRuns and logs - add POST /scenarios/:id/run/:runId/wait (polls until terminal state) - 9 new integration tests for the two endpoints (136 total) - add eslint with typescript-eslint and eslint-config-prettier - add npm scripts: format, lint, lint:fix - resolve all lint errors across src and test (no any types) - add CONTRIBUTING.md covering dev workflow
This commit is contained in:
+39
-33
@@ -1,23 +1,27 @@
|
||||
import { INestApplication, ValidationPipe } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
import debug from 'debug';
|
||||
import { INestApplication, ValidationPipe } from "@nestjs/common";
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
import { ScheduleModule } from "@nestjs/schedule";
|
||||
jest.mock("@nestjs/common", () => {
|
||||
const actual = jest.requireActual("@nestjs/common");
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const log = require("debug")("test");
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const { Logger } = require("@nestjs/common/services/logger.service");
|
||||
|
||||
jest.mock('@nestjs/common', () => {
|
||||
const actual = jest.requireActual('@nestjs/common');
|
||||
const log = require('debug')('test');
|
||||
const { Logger } = require('@nestjs/common/services/logger.service');
|
||||
|
||||
Logger.prototype.error = function (message: unknown, stack?: string, context?: string) {
|
||||
const ctx = context ?? this.context ?? 'App';
|
||||
log(`[${ctx}]`, 'error', message, ...(stack ? [stack] : []));
|
||||
Logger.prototype.error = function (
|
||||
message: unknown,
|
||||
stack?: string,
|
||||
context?: string,
|
||||
) {
|
||||
const ctx = context ?? this.context ?? "App";
|
||||
log(`[${ctx}]`, "error", message, ...(stack ? [stack] : []));
|
||||
};
|
||||
|
||||
for (const level of ['log', 'warn', 'debug', 'verbose', 'fatal'] as const) {
|
||||
for (const level of ["log", "warn", "debug", "verbose", "fatal"] as const) {
|
||||
Logger.prototype[level] = function (message: unknown, context?: string) {
|
||||
const ctx = context ?? this.context ?? 'App';
|
||||
const ctx = context ?? this.context ?? "App";
|
||||
log(`[${ctx}]`, level, message);
|
||||
};
|
||||
}
|
||||
@@ -25,29 +29,30 @@ jest.mock('@nestjs/common', () => {
|
||||
return actual;
|
||||
});
|
||||
|
||||
import { AuthModule } from '../src/auth/auth.module';
|
||||
import { BrowserModule } from '../src/browser/browser.module';
|
||||
import { SessionModule } from '../src/session/session.module';
|
||||
import { EnvironmentModule } from '../src/environment/environment.module';
|
||||
import { ScenarioModule } from '../src/scenario/scenario.module';
|
||||
import { McpModule } from '../src/mcp/mcp.module';
|
||||
import { SessionEntity } from '../src/session/session.entity';
|
||||
import { EnvironmentEntity } from '../src/environment/environment.entity';
|
||||
import { ScenarioEntity } from '../src/scenario/scenario.entity';
|
||||
import { ScenarioStepEntity } from '../src/scenario/scenario-step.entity';
|
||||
import { ScenarioRunEntity } from '../src/scenario/scenario-run.entity';
|
||||
import { ScenarioRunStepEntity } from '../src/scenario/scenario-run-step.entity';
|
||||
import { HealthController } from '../src/health/health.controller';
|
||||
import { HttpExceptionFilter } from '../src/filters/http-exception.filter';
|
||||
import { LoggingInterceptor } from '../src/interceptors/logging.interceptor';
|
||||
import { AuthModule } from "../src/auth/auth.module";
|
||||
import { BrowserModule } from "../src/browser/browser.module";
|
||||
import { SessionModule } from "../src/session/session.module";
|
||||
import { EnvironmentModule } from "../src/environment/environment.module";
|
||||
import { ScenarioModule } from "../src/scenario/scenario.module";
|
||||
import { McpModule } from "../src/mcp/mcp.module";
|
||||
import { SessionEntity } from "../src/session/session.entity";
|
||||
import { EnvironmentEntity } from "../src/environment/environment.entity";
|
||||
import { ScenarioEntity } from "../src/scenario/scenario.entity";
|
||||
import { ScenarioStepEntity } from "../src/scenario/scenario-step.entity";
|
||||
import { ScenarioRunEntity } from "../src/scenario/scenario-run.entity";
|
||||
import { ScenarioRunStepEntity } from "../src/scenario/scenario-run-step.entity";
|
||||
import { ScenarioRunLogEntity } from "../src/scenario/scenario-run-log.entity";
|
||||
import { HealthController } from "../src/health/health.controller";
|
||||
import { HttpExceptionFilter } from "../src/filters/http-exception.filter";
|
||||
import { LoggingInterceptor } from "../src/interceptors/logging.interceptor";
|
||||
|
||||
export async function buildTestApp(): Promise<INestApplication> {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [
|
||||
ConfigModule.forRoot({ isGlobal: true, ignoreEnvFile: true }),
|
||||
TypeOrmModule.forRoot({
|
||||
type: 'better-sqlite3',
|
||||
database: ':memory:',
|
||||
type: "better-sqlite3",
|
||||
database: ":memory:",
|
||||
entities: [
|
||||
SessionEntity,
|
||||
EnvironmentEntity,
|
||||
@@ -55,6 +60,7 @@ export async function buildTestApp(): Promise<INestApplication> {
|
||||
ScenarioStepEntity,
|
||||
ScenarioRunEntity,
|
||||
ScenarioRunStepEntity,
|
||||
ScenarioRunLogEntity,
|
||||
],
|
||||
synchronize: true,
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user