import { INestApplication } from '@nestjs/common'; import { getRepositoryToken } from '@nestjs/typeorm'; import request from 'supertest'; import { buildTestApp } from './app.harness'; import { SessionEntity } from '../src/session/session.entity'; import { Repository } from 'typeorm'; /** * Browser controller integration tests. * * POST /open and POST /exec need a running Playwright browser. We test * validation rejections (no browser launched) and session-not-found paths, * which are safe to run in a headless CI environment. */ describe('BrowserController', () => { let app: INestApplication; let sessionRepo: Repository; const FAKE_SESSION = 'test-browser-session'; beforeAll(async () => { app = await buildTestApp(); sessionRepo = app.get>(getRepositoryToken(SessionEntity)); // Seed a session with minimal but valid JSON so the browser code can // deserialise it (it will still fail to open a real page, tested separately) await sessionRepo.save( sessionRepo.create({ sessionName: FAKE_SESSION, token: 'fake-token', cookies: '[]', localStorage: '{}', }), ); }); afterAll(async () => { await app.close(); }); // ── POST /open ───────────────────────────────────────────────────────────── describe('POST /open', () => { it('returns 400 when body is empty', async () => { await request(app.getHttpServer()).post('/open').send({}).expect(400); }); it('returns 400 when url is missing', async () => { await request(app.getHttpServer()) .post('/open') .send({ sessionName: FAKE_SESSION }) .expect(400); }); it('returns 404 when session does not exist', async () => { await request(app.getHttpServer()) .post('/open') .send({ sessionName: 'no-such-session', url: 'https://example.com' }) .expect(404); }); it('succeeds without a session (sessionless open)', async () => { const res = await request(app.getHttpServer()) .post('/open') .send({ url: 'https://example.com' }) .expect(201); expect(res.body).toMatchObject({ url: expect.any(String), title: expect.any(String), content: expect.any(String), }); }); it('returns only selector content when selector is provided', async () => { const res = await request(app.getHttpServer()) .post('/open') .send({ url: 'https://example.com', selector: '#mock' }) .expect(201); expect(res.body.content).toBe('
mock content
'); }); it('returns selector text content in reader mode', async () => { const res = await request(app.getHttpServer()) .post('/open') .send({ url: 'https://example.com', selector: '#mock', readerMode: true }) .expect(201); expect(res.body.content).toBe('mock content'); }); }); // ── POST /exec ───────────────────────────────────────────────────────────── describe('POST /exec', () => { it('returns 400 when body is empty', async () => { await request(app.getHttpServer()).post('/exec').send({}).expect(400); }); it('returns 400 when code is missing', async () => { await request(app.getHttpServer()) .post('/exec') .send({ sessionName: FAKE_SESSION }) .expect(400); }); it('returns 400 when code has a syntax error', async () => { await request(app.getHttpServer()) .post('/exec') .send({ sessionName: FAKE_SESSION, code: 'this is not valid {{{' }) .expect(400); }); it('returns 404 when session does not exist', async () => { await request(app.getHttpServer()) .post('/exec') .send({ sessionName: 'no-such-session', code: 'return 1;' }) .expect(404); }); it('succeeds without a session (sessionless exec)', async () => { const res = await request(app.getHttpServer()) .post('/exec') .send({ code: 'return 42;' }) .expect(201); expect(res.body).toEqual({ result: 42 }); }); }); });