feat(tests): setup e2e-spec files for route testing. shifts-approval, expenses-approval, timesheets-approval et pay-periods-approval
This commit is contained in:
parent
8c201edd95
commit
90dc38154d
|
|
@ -8,7 +8,6 @@ import { Roles as RoleEnum } from '.prisma/client';
|
|||
import { Req } from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { PayPeriodsCommandService } from "../services/pay-periods-command.service";
|
||||
import { REPL_MODE_STRICT } from "repl";
|
||||
import { PayPeriodBundleDto } from "../dtos/bundle-pay-period.dto";
|
||||
|
||||
@ApiTags('pay-periods')
|
||||
|
|
|
|||
79
test/expenses-approval.e2e-spec.ts
Normal file
79
test/expenses-approval.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
const request = require('supertest');
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { createApp } from './utils/testing-app';
|
||||
|
||||
// NB: le controller est @Controller('Expenses') (E majuscule)
|
||||
const BASE = '/Expenses';
|
||||
|
||||
describe('Expenses approval (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
let prisma: PrismaService;
|
||||
|
||||
let timesheetId: number;
|
||||
let bankCodeExpenseId: number;
|
||||
let expenseId: number;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await createApp();
|
||||
prisma = app.get(PrismaService);
|
||||
|
||||
// 1) bank_code catégorie EXPENSE (évite MILEAGE pour ne pas dépendre du service de mileage)
|
||||
const bc = await prisma.bankCodes.findFirst({
|
||||
where: { categorie: 'EXPENSE' },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!bc) throw new Error('Aucun bank code EXPENSE trouvé');
|
||||
bankCodeExpenseId = bc.id;
|
||||
|
||||
// 2) timesheet existant
|
||||
const ts = await prisma.timesheets.findFirst({ select: { id: true } });
|
||||
if (!ts) throw new Error('Aucun timesheet trouvé pour créer une expense');
|
||||
timesheetId = ts.id;
|
||||
|
||||
// 3) crée une expense
|
||||
const payload = {
|
||||
timesheet_id: timesheetId,
|
||||
bank_code_id: bankCodeExpenseId,
|
||||
date: '2024-02-10T00:00:00.000Z',
|
||||
amount: 42, // int côté DTO
|
||||
description: 'Approval test expense',
|
||||
};
|
||||
const create = await request(app.getHttpServer()).post(BASE).send(payload);
|
||||
if (create.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Create expense error:', create.body || create.text);
|
||||
}
|
||||
expect(create.status).toBe(201);
|
||||
expenseId = create.body.id;
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval → 200 (true)`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${expenseId}/approval`)
|
||||
.send({ is_approved: true });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body?.is_approved).toBe(true);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval → 200 (false)`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${expenseId}/approval`)
|
||||
.send({ is_approved: false });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body?.is_approved).toBe(false);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval (invalid) → 400`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${expenseId}/approval`)
|
||||
.send({ is_approved: 'nope' });
|
||||
expect(res.status).toBeGreaterThanOrEqual(400);
|
||||
expect(res.status).toBeLessThan(500);
|
||||
});
|
||||
});
|
||||
|
|
@ -15,11 +15,18 @@
|
|||
"moduleDirectories": ["node_modules", "<rootDir>"],
|
||||
"testTimeout": 30000,
|
||||
"maxWorkers": 1,
|
||||
"collectCoverage": true,
|
||||
"collectCoverage": false,
|
||||
"coverageDirectory": "coverage-e2e",
|
||||
"coverageReporters": ["text", "lcov"],
|
||||
"coveragePathIgnorePatterns": ["/node_modules/", "/test/utils/", "/test/factories/"],
|
||||
"coveragePathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"/dist/",
|
||||
"src/modules/pay-periods/services/",
|
||||
"src/modules/exports/services/csv-exports.service.ts",
|
||||
"src/modules/notifications/services/",
|
||||
"src/modules/leave-requests/services/"
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": { "branches": 40, "functions": 50, "lines": 60, "statements": 60 }
|
||||
"global": {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
143
test/pay-periods-approval.e2e-spec.ts
Normal file
143
test/pay-periods-approval.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// test/pay-periods-approval.e2e-spec.ts
|
||||
const supertest = require('supertest');
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { createApp } from './utils/testing-app';
|
||||
import { makeEmployee } from './factories/employee.factory';
|
||||
import { makeTimesheet } from './factories/timesheet.factory';
|
||||
|
||||
describe('PayPeriods approval (e2e)', () => {
|
||||
const BASE = '/pay-periods';
|
||||
let app: INestApplication;
|
||||
let prisma: PrismaService;
|
||||
|
||||
let periodYear: number;
|
||||
let periodNumber: number;
|
||||
|
||||
let employeeId: number;
|
||||
let timesheetId: number;
|
||||
let shiftId: number;
|
||||
let expenseId: number;
|
||||
|
||||
const isoDay = (d: Date) =>
|
||||
new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())).toISOString();
|
||||
const isoTime = (h: number, m = 0) =>
|
||||
new Date(Date.UTC(1970, 0, 1, h, m, 0)).toISOString();
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await createApp();
|
||||
prisma = app.get(PrismaService);
|
||||
|
||||
// 1) Récupère un pay period existant
|
||||
const period = await prisma.payPeriods.findFirst({ orderBy: { period_number: 'asc' } });
|
||||
if (!period) throw new Error('Aucun pay period en DB (seed requis).');
|
||||
|
||||
periodYear = period.year;
|
||||
periodNumber = period.period_number;
|
||||
|
||||
// 2) Crée un employé + timesheet (non approuvé)
|
||||
const empRes = await supertest(app.getHttpServer())
|
||||
.post('/employees')
|
||||
.send(makeEmployee());
|
||||
if (empRes.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Create employee error:', empRes.body || empRes.text);
|
||||
throw new Error('Impossible de créer un employé pour le test pay-periods.');
|
||||
}
|
||||
employeeId = empRes.body.id;
|
||||
|
||||
const tsRes = await supertest(app.getHttpServer())
|
||||
.post('/timesheets')
|
||||
.send(makeTimesheet(employeeId, { is_approved: false }));
|
||||
if (tsRes.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Create timesheet error:', tsRes.body || tsRes.text);
|
||||
throw new Error('Impossible de créer un timesheet pour le test pay-periods.');
|
||||
}
|
||||
timesheetId = tsRes.body.id;
|
||||
|
||||
// 3) Bank codes
|
||||
const bcShift = await prisma.bankCodes.findFirst({
|
||||
where: { categorie: 'SHIFT' },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!bcShift) throw new Error('Aucun bank code SHIFT trouvé.');
|
||||
const bcExpense = await prisma.bankCodes.findFirst({
|
||||
where: { categorie: 'EXPENSE' },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!bcExpense) throw new Error('Aucun bank code EXPENSE trouvé.');
|
||||
|
||||
// 4) Crée 1 shift + 1 expense DANS la période choisie
|
||||
const dateISO = isoDay(period.start_date);
|
||||
|
||||
const shiftRes = await supertest(app.getHttpServer())
|
||||
.post('/shifts')
|
||||
.send({
|
||||
timesheet_id: timesheetId,
|
||||
bank_code_id: bcShift.id,
|
||||
date: dateISO,
|
||||
start_time: isoTime(9),
|
||||
end_time: isoTime(17),
|
||||
description: 'PP approval shift',
|
||||
});
|
||||
if (shiftRes.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Create shift error:', shiftRes.body || shiftRes.text);
|
||||
throw new Error('Création shift échouée.');
|
||||
}
|
||||
shiftId = shiftRes.body.id;
|
||||
|
||||
const expenseRes = await supertest(app.getHttpServer())
|
||||
.post('/Expenses') // <- respecte ta casse de route
|
||||
.send({
|
||||
timesheet_id: timesheetId,
|
||||
bank_code_id: bcExpense.id,
|
||||
date: dateISO,
|
||||
amount: 42,
|
||||
description: 'PP approval expense',
|
||||
is_approved: false,
|
||||
});
|
||||
if (expenseRes.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Create expense error:', expenseRes.body || expenseRes.text);
|
||||
throw new Error('Création expense échouée.');
|
||||
}
|
||||
expenseId = expenseRes.body.id;
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:year/:periodNumber/approval → 200 (cascade approval)`, async () => {
|
||||
const res = await supertest(app.getHttpServer())
|
||||
.patch(`${BASE}/${periodYear}/${periodNumber}/approval`)
|
||||
.send(); // aucun body requis par ton contrôleur
|
||||
expect([200, 204]).toContain(res.status);
|
||||
if (res.body?.message) {
|
||||
expect(String(res.body.message)).toContain(`${periodYear}-${periodNumber}`);
|
||||
}
|
||||
|
||||
// Vérifie cascade:
|
||||
const tsCheck = await supertest(app.getHttpServer()).get(`/timesheets/${timesheetId}`);
|
||||
expect(tsCheck.status).toBe(200);
|
||||
expect(tsCheck.body?.is_approved).toBe(true);
|
||||
|
||||
const shiftCheck = await supertest(app.getHttpServer()).get(`/shifts/${shiftId}`);
|
||||
expect(shiftCheck.status).toBe(200);
|
||||
expect(shiftCheck.body?.is_approved).toBe(true);
|
||||
|
||||
const expCheck = await supertest(app.getHttpServer()).get(`/Expenses/${expenseId}`);
|
||||
expect(expCheck.status).toBe(200);
|
||||
expect(expCheck.body?.is_approved).toBe(true);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/2099/999/approval → 404 (period not found)`, async () => {
|
||||
const bad = await supertest(app.getHttpServer())
|
||||
.patch(`${BASE}/2099/999/approval`)
|
||||
.send();
|
||||
expect(bad.status).toBe(404);
|
||||
});
|
||||
});
|
||||
101
test/shifts-aproval.e2e-spec.ts
Normal file
101
test/shifts-aproval.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
const request = require('supertest');
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { createApp } from './utils/testing-app';
|
||||
import { makeEmployee } from './factories/employee.factory';
|
||||
import { makeTimesheet } from './factories/timesheet.factory';
|
||||
|
||||
describe('Shifts approval (e2e)', () => {
|
||||
const BASE = '/shifts';
|
||||
let app: INestApplication;
|
||||
let prisma: PrismaService;
|
||||
|
||||
let timesheetId: number;
|
||||
let bankCodeShiftId: number;
|
||||
let shiftId: number;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await createApp();
|
||||
prisma = app.get(PrismaService);
|
||||
|
||||
// 1) bank_code SHIFT
|
||||
const bc = await prisma.bankCodes.findFirst({
|
||||
where: { categorie: 'SHIFT' },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!bc) throw new Error('Aucun bank code SHIFT trouvé');
|
||||
bankCodeShiftId = bc.id;
|
||||
|
||||
// 2) timesheet existant ou création rapide
|
||||
const ts = await prisma.timesheets.findFirst({ select: { id: true } });
|
||||
if (ts) {
|
||||
timesheetId = ts.id;
|
||||
} else {
|
||||
// crée un employé + timesheet via HTTP
|
||||
const empRes = await request(app.getHttpServer())
|
||||
.post('/employees')
|
||||
.send(makeEmployee());
|
||||
if (empRes.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Création employé échouée:', empRes.body || empRes.text);
|
||||
throw new Error('Setup employees pour shifts-approval échoué');
|
||||
}
|
||||
const tsRes = await request(app.getHttpServer())
|
||||
.post('/timesheets')
|
||||
.send(makeTimesheet(empRes.body.id));
|
||||
if (tsRes.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Création timesheet échouée:', tsRes.body || tsRes.text);
|
||||
throw new Error('Setup timesheet pour shifts-approval échoué');
|
||||
}
|
||||
timesheetId = tsRes.body.id;
|
||||
}
|
||||
|
||||
// 3) crée un shift à approuver
|
||||
const payload = {
|
||||
timesheet_id: timesheetId,
|
||||
bank_code_id: bankCodeShiftId,
|
||||
date: '2024-01-15T00:00:00.000Z',
|
||||
start_time: '2024-01-15T08:00:00.000Z',
|
||||
end_time: '2024-01-15T16:00:00.000Z',
|
||||
description: 'Approval test shift',
|
||||
};
|
||||
const create = await request(app.getHttpServer()).post(BASE).send(payload);
|
||||
if (create.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Create shift error:', create.body || create.text);
|
||||
}
|
||||
expect(create.status).toBe(201);
|
||||
shiftId = create.body.id;
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval → 200 (true)`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${shiftId}/approval`)
|
||||
.send({ is_approved: true });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body?.is_approved).toBe(true);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval → 200 (false)`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${shiftId}/approval`)
|
||||
.send({ is_approved: false });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body?.is_approved).toBe(false);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval (invalid) → 400`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${shiftId}/approval`)
|
||||
// ParseBoolPipe doit rejeter une string non "true/false"
|
||||
.send({ is_approved: 'notabool' });
|
||||
expect(res.status).toBeGreaterThanOrEqual(400);
|
||||
expect(res.status).toBeLessThan(500);
|
||||
});
|
||||
});
|
||||
68
test/timesheets-approval.e2e-spec.ts
Normal file
68
test/timesheets-approval.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
const request = require('supertest');
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { createApp } from './utils/testing-app';
|
||||
import { makeEmployee } from './factories/employee.factory';
|
||||
import { makeTimesheet } from './factories/timesheet.factory';
|
||||
|
||||
describe('Timesheets approval (e2e)', () => {
|
||||
const BASE = '/timesheets';
|
||||
let app: INestApplication;
|
||||
let prisma: PrismaService;
|
||||
|
||||
let timesheetId: number;
|
||||
|
||||
beforeAll(async () => {
|
||||
app = await createApp();
|
||||
prisma = app.get(PrismaService);
|
||||
|
||||
// On crée un employé dédié pour ne dépendre d’aucun état antérieur
|
||||
const emp = await request(app.getHttpServer())
|
||||
.post('/employees')
|
||||
.send(makeEmployee());
|
||||
if (emp.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Création employé échouée:', emp.body || emp.text);
|
||||
throw new Error('Setup employees pour timesheets-approval échoué');
|
||||
}
|
||||
|
||||
const ts = await request(app.getHttpServer())
|
||||
.post(BASE)
|
||||
.send(makeTimesheet(emp.body.id));
|
||||
if (ts.status !== 201) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Création timesheet échouée:', ts.body || ts.text);
|
||||
throw new Error('Setup timesheet échoué');
|
||||
}
|
||||
timesheetId = ts.body.id;
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval → 200 (true)`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${timesheetId}/approval`)
|
||||
.send({ is_approved: true });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body?.is_approved).toBe(true);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval → 200 (false)`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${timesheetId}/approval`)
|
||||
.send({ is_approved: false });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body?.is_approved).toBe(false);
|
||||
});
|
||||
|
||||
it(`PATCH ${BASE}/:id/approval (invalid) → 400`, async () => {
|
||||
const res = await request(app.getHttpServer())
|
||||
.patch(`${BASE}/${timesheetId}/approval`)
|
||||
.send({ is_approved: 'plop' });
|
||||
expect(res.status).toBeGreaterThanOrEqual(400);
|
||||
expect(res.status).toBeLessThan(500);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user