import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import request from 'supertest'; import { App } from 'supertest/types'; import { AppModule } from './../src/app.module'; import { MailService } from './../src/mail/mail.service'; interface AuthResponseBody { accessToken?: string; refreshToken?: string; user: { id?: string; email: string; verified: boolean; }; } interface ListTemplateResponseBody { id: string; name: string; kind: string; items: { id: string; title: string; checked?: boolean; }[]; } describe('AppController (e2e)', () => { let app: INestApplication; let mailService: MailService; beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); mailService = moduleFixture.get(MailService); app = moduleFixture.createNestApplication(); await app.init(); }); it('/ (GET)', () => { return request(app.getHttpServer()) .get('/') .expect(200) .expect('Hello World!'); }); it('/auth register, verify and login', async () => { const registerResponse = await request(app.getHttpServer()) .post('/auth/register') .send({ email: 'user@example.com', password: 'password123', }) .expect(201); const registerBody = registerResponse.body as unknown as AuthResponseBody; expect(registerBody.user.email).toBe('user@example.com'); expect(registerBody.user.verified).toBe(false); await request(app.getHttpServer()) .post('/auth/login') .send({ email: 'user@example.com', password: 'password123', }) .expect(401); const verificationUrl = mailService.getSentEmails()[0].verificationUrl; const token = new URL(verificationUrl).searchParams.get('token'); const verifyResponse = await request(app.getHttpServer()) .get('/auth/verify-email') .query({ token }) .expect(200); const verifyBody = verifyResponse.body as unknown as AuthResponseBody; expect(verifyBody.user.verified).toBe(true); const loginResponse = await request(app.getHttpServer()) .post('/auth/login') .send({ email: 'user@example.com', password: 'password123', }) .expect(200); const loginBody = loginResponse.body as unknown as AuthResponseBody; expect(loginBody.accessToken).toBeDefined(); expect(loginBody.refreshToken).toBeDefined(); expect(loginBody.user.email).toBe('user@example.com'); const refreshResponse = await request(app.getHttpServer()) .post('/auth/refresh') .send({ refreshToken: loginBody.refreshToken, }) .expect(201); const refreshBody = refreshResponse.body as unknown as AuthResponseBody; expect(refreshBody.accessToken).toBeDefined(); expect(refreshBody.refreshToken).toBeDefined(); expect(refreshBody.refreshToken).not.toBe(loginBody.refreshToken); await request(app.getHttpServer()) .post('/auth/refresh') .send({ refreshToken: loginBody.refreshToken, }) .expect(401); }); it('/list-templates creates, updates and uses a template', async () => { const accessToken = await registerVerifiedUserAndGetAccessToken( 'template-user@example.com', ); const initialTemplatesResponse = await request(app.getHttpServer()) .get('/list-templates') .set('Authorization', `Bearer ${accessToken}`) .expect(200); const initialTemplates = initialTemplatesResponse.body as unknown as ListTemplateResponseBody[]; expect(initialTemplates).toHaveLength(3); expect(initialTemplates.map((template) => template.name)).toContain( 'Urlaub', ); const createTemplateResponse = await request(app.getHttpServer()) .post('/list-templates') .set('Authorization', `Bearer ${accessToken}`) .send({ name: 'Urlaub', kind: 'packing', items: [{ title: 'Pass' }, { title: 'Tickets' }], }) .expect(201); const createdTemplate = createTemplateResponse.body as unknown as ListTemplateResponseBody; expect(createdTemplate.name).toBe('Urlaub'); expect(createdTemplate.items).toHaveLength(2); const updateTemplateResponse = await request(app.getHttpServer()) .patch(`/list-templates/${createdTemplate.id}`) .set('Authorization', `Bearer ${accessToken}`) .send({ name: 'Sommerurlaub', }) .expect(200); const updatedTemplate = updateTemplateResponse.body as unknown as ListTemplateResponseBody; expect(updatedTemplate.name).toBe('Sommerurlaub'); const createListResponse = await request(app.getHttpServer()) .post(`/list-templates/${createdTemplate.id}/lists`) .set('Authorization', `Bearer ${accessToken}`) .send({ name: 'Sommerurlaub 2026', }) .expect(201); const createdList = createListResponse.body as unknown as ListTemplateResponseBody; expect(createdList.name).toBe('Sommerurlaub 2026'); expect(createdList.items[0].title).toBe('Pass'); expect(createdList.items[0].checked).toBe(false); }); it('/lists creates, updates and reads a concrete list', async () => { const accessToken = await registerVerifiedUserAndGetAccessToken( 'list-user@example.com', ); const createListResponse = await request(app.getHttpServer()) .post('/lists') .set('Authorization', `Bearer ${accessToken}`) .send({ name: 'Wocheneinkauf', kind: 'shopping', }) .expect(201); const createdList = createListResponse.body as unknown as ListTemplateResponseBody; expect(createdList.name).toBe('Wocheneinkauf'); expect(createdList.items).toHaveLength(0); const addItemResponse = await request(app.getHttpServer()) .post(`/lists/${createdList.id}/items`) .set('Authorization', `Bearer ${accessToken}`) .send({ title: 'Milch', quantity: 2, }) .expect(201); const listWithItem = addItemResponse.body as unknown as ListTemplateResponseBody; expect(listWithItem.items).toHaveLength(1); expect(listWithItem.items[0].title).toBe('Milch'); await request(app.getHttpServer()) .patch(`/lists/${createdList.id}/items/${listWithItem.items[0].id}`) .set('Authorization', `Bearer ${accessToken}`) .send({ checked: true, }) .expect(200); const getListResponse = await request(app.getHttpServer()) .get(`/lists/${createdList.id}`) .set('Authorization', `Bearer ${accessToken}`) .expect(200); const fetchedList = getListResponse.body as unknown as ListTemplateResponseBody; expect(fetchedList.items[0].checked).toBe(true); }); async function registerVerifiedUserAndGetAccessToken( email: string, ): Promise { await request(app.getHttpServer()) .post('/auth/register') .send({ email, password: 'password123', }) .expect(201); const verificationUrl = mailService.getSentEmails()[mailService.getSentEmails().length - 1] .verificationUrl; const token = new URL(verificationUrl).searchParams.get('token'); await request(app.getHttpServer()) .get('/auth/verify-email') .query({ token }) .expect(200); const loginResponse = await request(app.getHttpServer()) .post('/auth/login') .send({ email, password: 'password123', }) .expect(200); const loginBody = loginResponse.body as unknown as AuthResponseBody; expect(loginBody.accessToken).toBeDefined(); return loginBody.accessToken ?? ''; } afterEach(async () => { await app.close(); }); });