Files
liqa/test/app.harness.ts
T
ars9 00f310e899 test: add jest test suite with controller specs and mocks
- add jest, ts-jest, supertest, and related dev dependencies
- add test scripts (test, test:debug, test:watch) to package.json
- add jest.config.js with ts-jest transform and module name mappers
- add controller specs for auth, browser, environment, mcp, scenario, session
- add mocks for jsdom, playwright, and readability
- add test/tsconfig.json and exclude test dir from main tsconfig
2026-04-07 15:54:13 +03:00

79 lines
3.0 KiB
TypeScript

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';
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] : []));
};
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';
log(`[${ctx}]`, level, message);
};
}
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';
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:',
entities: [
SessionEntity,
EnvironmentEntity,
ScenarioEntity,
ScenarioStepEntity,
ScenarioRunEntity,
ScenarioRunStepEntity,
],
synchronize: true,
}),
ScheduleModule.forRoot(),
AuthModule,
BrowserModule,
SessionModule,
EnvironmentModule,
ScenarioModule,
McpModule,
],
controllers: [HealthController],
}).compile();
const app = module.createNestApplication();
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalInterceptors(new LoggingInterceptor());
await app.init();
return app;
}