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:
2026-04-08 18:10:42 +03:00
parent b0c02a1cdc
commit 9a9ccbfe37
67 changed files with 3809 additions and 1412 deletions
+20 -20
View File
@@ -1,6 +1,6 @@
import { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { buildTestApp } from './app.harness';
import { INestApplication } from "@nestjs/common";
import request from "supertest";
import { buildTestApp } from "./app.harness";
/**
* Auth controller integration tests.
@@ -9,7 +9,7 @@ import { buildTestApp } from './app.harness';
* exercised here (those belong to e2e tests with real credentials).
* We cover the parts that can be tested without external dependencies.
*/
describe('AuthController', () => {
describe("AuthController", () => {
let app: INestApplication;
beforeAll(async () => {
@@ -22,39 +22,39 @@ describe('AuthController', () => {
// ── GET /keys ──────────────────────────────────────────────────────────────
describe('GET /keys', () => {
it('returns 200 with a keys array', async () => {
const res = await request(app.getHttpServer()).get('/keys').expect(200);
expect(res.body).toHaveProperty('keys');
describe("GET /keys", () => {
it("returns 200 with a keys array", async () => {
const res = await request(app.getHttpServer()).get("/keys").expect(200);
expect(res.body).toHaveProperty("keys");
expect(Array.isArray(res.body.keys)).toBe(true);
});
});
// ── POST /login ────────────────────────────────────────────────────────────
describe('POST /login', () => {
it('returns 400 when body is empty', async () => {
await request(app.getHttpServer()).post('/login').send({}).expect(400);
describe("POST /login", () => {
it("returns 400 when body is empty", async () => {
await request(app.getHttpServer()).post("/login").send({}).expect(400);
});
it('returns 400 when key is missing', async () => {
it("returns 400 when key is missing", async () => {
await request(app.getHttpServer())
.post('/login')
.send({ environmentName: 'test-env' })
.post("/login")
.send({ environmentName: "test-env" })
.expect(400);
});
it('returns 400 when environmentName is missing', async () => {
it("returns 400 when environmentName is missing", async () => {
await request(app.getHttpServer())
.post('/login')
.send({ key: 'some-key' })
.post("/login")
.send({ key: "some-key" })
.expect(400);
});
it('returns 400 when key file does not exist', async () => {
it("returns 400 when key file does not exist", async () => {
await request(app.getHttpServer())
.post('/login')
.send({ key: 'nonexistent-key', environmentName: 'test-env' })
.post("/login")
.send({ key: "nonexistent-key", environmentName: "test-env" })
.expect(404); // NotFoundException for missing environment
});
});