update first - 84

This commit is contained in:
thanhnv
2026-06-30 02:21:39 +09:00
commit 07ac1bdcdd
561 changed files with 88164 additions and 0 deletions
@@ -0,0 +1,83 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import request from 'supertest';
import { createTestApp, loginToken } from './helpers.js';
test('HTTP auth, role filtering, validation, and progress update are real', async () => {
const { app, prisma } = await createTestApp();
try {
await request(app.getHttpServer()).get('/api/v1/objectives').expect(401);
const employeeToken = await loginToken(app, 'employee');
const managerToken = await loginToken(app, 'manager');
const employeeObjectives = await request(app.getHttpServer())
.get('/api/v1/objectives')
.set('Authorization', `Bearer ${employeeToken}`)
.expect(200);
assert.equal(employeeObjectives.body.success, true);
assert.deepEqual(
employeeObjectives.body.data.map((objective: { ownerId: number }) => objective.ownerId),
[3],
);
const managerObjectives = await request(app.getHttpServer())
.get('/api/v1/objectives')
.set('Authorization', `Bearer ${managerToken}`)
.expect(200);
assert.equal(managerObjectives.body.data.length, 3);
await request(app.getHttpServer())
.post('/api/v1/objectives')
.set('Authorization', `Bearer ${employeeToken}`)
.send({ title: '', ownerId: 3, quarter: '2026-Q2' })
.expect(400);
const progressResponse = await request(app.getHttpServer())
.patch('/api/v1/key-results/2/progress')
.set('Authorization', `Bearer ${employeeToken}`)
.send({ progress: 70, comment: 'Updated in e2e test' })
.expect(200);
assert.equal(progressResponse.body.data.progress, 70);
await prisma.keyResult.update({ where: { id: 2 }, data: { progress: 60 } });
await prisma.progressUpdate.deleteMany({ where: { keyResultId: 2, progress: 70 } });
} finally {
await app.close();
}
});
test('golden objective list response does not drift', async () => {
const { app } = await createTestApp();
try {
const token = await loginToken(app, 'manager');
const response = await request(app.getHttpServer())
.get('/api/v1/objectives')
.set('Authorization', `Bearer ${token}`)
.expect(200);
const canonical = JSON.stringify(
{
success: response.body.success,
data: response.body.data.map((objective: { id: number; title: string; quarter: string; status: string; keyResults: { id: number; title: string; progress: number }[] }) => ({
id: objective.id,
title: objective.title,
quarter: objective.quarter,
status: objective.status,
keyResults: objective.keyResults.map((keyResult) => ({
id: keyResult.id,
title: keyResult.title,
progress: keyResult.progress,
})),
})),
meta: response.body.meta,
},
null,
2,
);
const fixture = await fs.readFile(path.resolve('test/golden/objectives.manager.json'), 'utf8');
assert.equal(`${canonical}\n`, fixture);
} finally {
await app.close();
}
});
@@ -0,0 +1,57 @@
{
"success": true,
"data": [
{
"id": 1,
"title": "POC AI for SQL Injection prevention",
"quarter": "Q2/2026",
"status": "IN_PROGRESS",
"keyResults": [
{
"id": 1,
"title": "Complete 3 POC sessions with security team",
"progress": 33
},
{
"id": 2,
"title": "Reduce manual SQL injection review effort by 30%",
"progress": 60
}
]
},
{
"id": 2,
"title": "AI for All enablement across department",
"quarter": "Q2/2026",
"status": "NOT_STARTED",
"keyResults": [
{
"id": 3,
"title": "Certify 100 department members on AI for All",
"progress": 0
}
]
},
{
"id": 3,
"title": "Improve OKR operating cadence",
"quarter": "Q2/2026",
"status": "IN_PROGRESS",
"keyResults": [
{
"id": 4,
"title": "Reach 90% weekly OKR update compliance",
"progress": 75
},
{
"id": 5,
"title": "Resolve stale OKR reports within two business days",
"progress": 45
}
]
}
],
"meta": {
"total": 3
}
}
@@ -0,0 +1,30 @@
import { ValidationPipe } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import type { INestApplication } from '@nestjs/common';
import { PrismaService } from '../src/prisma/prisma.service.js';
import { AppModule } from '../src/app.module.js';
export async function createTestApp(): Promise<{ app: INestApplication; prisma: PrismaService }> {
const moduleRef = await Test.createTestingModule({ imports: [AppModule] }).compile();
const app = moduleRef.createNestApplication();
app.setGlobalPrefix('api/v1');
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
await app.init();
return { app, prisma: app.get(PrismaService) };
}
export async function loginToken(app: INestApplication, username = 'employee'): Promise<string> {
const request = await import('supertest');
const response = await request
.default(app.getHttpServer())
.post('/api/v1/auth/login')
.send({ username, password: 'Password@123' })
.expect(201);
return response.body.data.token as string;
}
@@ -0,0 +1,62 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { JwtService } from '@nestjs/jwt';
import { ForbiddenException, UnauthorizedException } from '@nestjs/common';
import { AuthService } from '../src/auth/auth.service.js';
import type { JwtUser } from '../src/common/auth.types.js';
import { KeyResultsService } from '../src/key-results/key-results.service.js';
import { ObjectivesService } from '../src/objectives/objectives.service.js';
import { PrismaService } from '../src/prisma/prisma.service.js';
const employeeUser: JwtUser = {
sub: 3,
email: 'employee@okr.local',
role: 'EMPLOYEE',
name: 'Nguyen Van A',
};
const managerUser: JwtUser = {
sub: 2,
email: 'manager@okr.local',
role: 'MANAGER',
name: 'Nguyen Van Manager',
};
test('AuthService rejects invalid passwords and signs valid users', async () => {
const prisma = new PrismaService();
await prisma.$connect();
const service = new AuthService(prisma, new JwtService({ secret: 'test-secret' }));
await assert.rejects(() => service.login('employee', 'wrong-password'), UnauthorizedException);
const result = await service.login('employee', 'Password@123');
assert.equal(result.user.email, 'employee@okr.local');
assert.ok(result.token.length > 20);
await prisma.$disconnect();
});
test('ObjectivesService applies employee role filtering', async () => {
const prisma = new PrismaService();
await prisma.$connect();
const service = new ObjectivesService(prisma);
const employeeObjectives = await service.list(employeeUser);
const managerObjectives = await service.list(managerUser);
assert.deepEqual(employeeObjectives.map((objective) => objective.ownerId), [employeeUser.sub]);
assert.ok(managerObjectives.length > employeeObjectives.length);
await prisma.$disconnect();
});
test('KeyResultsService blocks employee updates to another owner and recalculates owned progress', async () => {
const prisma = new PrismaService();
await prisma.$connect();
const service = new KeyResultsService(prisma);
await assert.rejects(
() => service.updateProgress(3, { progress: 50, comment: 'Not mine' }, employeeUser),
ForbiddenException,
);
const updated = await service.updateProgress(1, { progress: 100, comment: 'Completed' }, employeeUser);
assert.equal(updated.progress, 100);
const objective = await prisma.objective.findUniqueOrThrow({ where: { id: updated.objectiveId } });
assert.equal(objective.status, 'IN_PROGRESS');
await prisma.keyResult.update({ where: { id: 1 }, data: { progress: 33 } });
await prisma.progressUpdate.deleteMany({ where: { keyResultId: 1 } });
await prisma.$disconnect();
});