154 lines
4.7 KiB
TypeScript
154 lines
4.7 KiB
TypeScript
import { NotFoundException } from '@nestjs/common';
|
|
import { BugService } from './bug.service';
|
|
|
|
describe('BugService domain writes', () => {
|
|
const makeService = () => {
|
|
const workActivity = {
|
|
record: jest.fn().mockResolvedValue({ id: 'activity-1' }),
|
|
};
|
|
const prisma = {
|
|
version: {
|
|
findUnique: jest.fn(),
|
|
},
|
|
bug: {
|
|
create: jest.fn(),
|
|
delete: jest.fn(),
|
|
findFirst: jest.fn(),
|
|
findMany: jest.fn(),
|
|
update: jest.fn(),
|
|
},
|
|
};
|
|
|
|
return {
|
|
prisma,
|
|
workActivity,
|
|
service: new BugService(prisma as any, workActivity as any),
|
|
};
|
|
};
|
|
|
|
it('creates bugs directly under a version partition', async () => {
|
|
const { prisma, workActivity, service } = makeService();
|
|
prisma.version.findUnique.mockResolvedValue({ id: 'version-1', productId: 'product-1', projectId: 'project-1' });
|
|
prisma.bug.create.mockResolvedValue({ id: 'bug-1', versionId: 'version-1', title: '登录报错' });
|
|
|
|
await service.create('version-1', {
|
|
bugNo: 'BUG-001',
|
|
testCaseId: 'tc-1',
|
|
title: '登录报错',
|
|
description: '登录按钮无响应',
|
|
severity: 'critical',
|
|
priority: 'P0',
|
|
assigneeId: 'dev-1',
|
|
reportedBy: 'tester-1',
|
|
plannedFixAt: '2026-07-08T18:00:00.000Z',
|
|
} as any);
|
|
|
|
expect(prisma.bug.create).toHaveBeenCalledWith({
|
|
data: expect.objectContaining({
|
|
versionId: 'version-1',
|
|
productId: 'product-1',
|
|
projectId: 'project-1',
|
|
testCaseId: 'tc-1',
|
|
testCaseVersionId: 'version-1',
|
|
code: 'BUG-001',
|
|
title: '登录报错',
|
|
severity: 'critical',
|
|
priority: 0,
|
|
assigneeId: 'dev-1',
|
|
reporterId: 'tester-1',
|
|
plannedFixAt: new Date('2026-07-08T18:00:00.000Z'),
|
|
status: 'open',
|
|
}),
|
|
});
|
|
expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
|
|
versionId: 'version-1',
|
|
sourceType: 'bug',
|
|
sourceId: 'bug-1',
|
|
action: 'bug_created',
|
|
}));
|
|
});
|
|
|
|
it('changes status and records closing evidence inside the version partition', async () => {
|
|
const { prisma, workActivity, service } = makeService();
|
|
prisma.bug.findFirst.mockResolvedValue({
|
|
id: 'bug-1',
|
|
versionId: 'version-1',
|
|
productId: 'product-1',
|
|
projectId: 'project-1',
|
|
status: 'verifying',
|
|
title: '登录报错',
|
|
assigneeId: 'dev-1',
|
|
reporterId: 'tester-1',
|
|
});
|
|
prisma.bug.update.mockResolvedValue({
|
|
id: 'bug-1',
|
|
versionId: 'version-1',
|
|
productId: 'product-1',
|
|
projectId: 'project-1',
|
|
status: 'closed',
|
|
title: '登录报错',
|
|
assigneeId: 'dev-1',
|
|
reporterId: 'tester-1',
|
|
});
|
|
|
|
await service.updateStatus('version-1', 'bug-1', 'closed', { operator: 'tester-1', resolution: '复测通过' });
|
|
|
|
expect(prisma.bug.update).toHaveBeenCalledWith({
|
|
where: { id_versionId: { id: 'bug-1', versionId: 'version-1' } },
|
|
data: expect.objectContaining({
|
|
status: 'closed',
|
|
closedAt: expect.any(Date),
|
|
resolution: '复测通过',
|
|
}),
|
|
});
|
|
expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
|
|
versionId: 'version-1',
|
|
sourceType: 'bug',
|
|
sourceId: 'bug-1',
|
|
action: 'bug_closed',
|
|
}));
|
|
});
|
|
|
|
it('transfers bugs by id plus version id and records activity evidence', async () => {
|
|
const { prisma, workActivity, service } = makeService();
|
|
prisma.bug.findFirst.mockResolvedValue({
|
|
id: 'bug-1',
|
|
versionId: 'version-1',
|
|
productId: 'product-1',
|
|
projectId: 'project-1',
|
|
status: 'open',
|
|
title: '登录报错',
|
|
assigneeId: 'dev-1',
|
|
reporterId: 'tester-1',
|
|
});
|
|
prisma.bug.update.mockResolvedValue({
|
|
id: 'bug-1',
|
|
versionId: 'version-1',
|
|
productId: 'product-1',
|
|
projectId: 'project-1',
|
|
title: '登录报错',
|
|
assigneeId: 'dev-2',
|
|
reporterId: 'tester-1',
|
|
});
|
|
|
|
await service.transfer('version-1', 'bug-1', 'dev-2', 'tester-1');
|
|
|
|
expect(prisma.bug.update).toHaveBeenCalledWith({
|
|
where: { id_versionId: { id: 'bug-1', versionId: 'version-1' } },
|
|
data: { assigneeId: 'dev-2' },
|
|
});
|
|
expect(workActivity.record).toHaveBeenCalledWith(expect.objectContaining({
|
|
action: 'bug_transferred',
|
|
metadata: expect.objectContaining({ fromAssigneeId: 'dev-1', toAssigneeId: 'dev-2' }),
|
|
}));
|
|
});
|
|
|
|
it('rejects updates outside the version partition', async () => {
|
|
const { prisma, service } = makeService();
|
|
prisma.bug.findFirst.mockResolvedValue(null);
|
|
|
|
await expect(service.update('version-1', 'missing-bug', { title: 'Ghost' })).rejects.toBeInstanceOf(NotFoundException);
|
|
expect(prisma.bug.update).not.toHaveBeenCalled();
|
|
});
|
|
});
|