fix: bound formatter memory and improve operations workflows
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { SignatureRetirementService } from './signature-retirement.service';
|
||||
|
||||
describe('daily application messages and date formatting', () => {
|
||||
function setup() {
|
||||
const detections = [
|
||||
{ id: 'a', tenantId: 't1', applicationId: 'app1', dimensionType: 'enterprise' },
|
||||
{ id: 'b', tenantId: 't1', applicationId: 'app1', dimensionType: 'channel' },
|
||||
{ id: 'c', tenantId: 't1', applicationId: 'app2', dimensionType: 'enterprise' },
|
||||
{ id: 'd', tenantId: 't1', applicationId: null, dimensionType: 'enterprise' },
|
||||
{ id: 'e', tenantId: 't2', applicationId: null, dimensionType: 'enterprise' },
|
||||
].map((item) => ({
|
||||
...item,
|
||||
cycleId: `cycle-${item.id}`,
|
||||
notificationTitle: '预警',
|
||||
notificationContent: `冻结正文${item.id}`,
|
||||
}));
|
||||
const prisma = {
|
||||
signatureRetirementDetection: { findMany: jest.fn().mockResolvedValue(detections) },
|
||||
smsApplication: {
|
||||
findMany: jest.fn().mockResolvedValue([
|
||||
{ id: 'app1', name: '应用一' },
|
||||
{ id: 'app2', name: '应用二' },
|
||||
]),
|
||||
},
|
||||
signatureRetirementMessage: {
|
||||
findFirst: jest.fn().mockResolvedValue(null),
|
||||
create: jest.fn().mockResolvedValue({}),
|
||||
findMany: jest.fn().mockResolvedValue([]),
|
||||
},
|
||||
signatureRetirementWebhook: { findMany: jest.fn().mockResolvedValue([]) },
|
||||
};
|
||||
return { prisma, service: new SignatureRetirementService(prisma as never) };
|
||||
}
|
||||
|
||||
it('creates one frozen message per application per day including all dimensions and separate unbound tenants', async () => {
|
||||
const { prisma, service } = setup();
|
||||
expect(await service.publishNotifications('2026-09-09')).toEqual({ notificationDate: '2026-09-09', created: 4 });
|
||||
const data = prisma.signatureRetirementMessage.create.mock.calls.map(([arg]) => arg.data);
|
||||
expect(data[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
title: '应用一 · 签名清退预警',
|
||||
detectionIds: ['a', 'b'],
|
||||
content: '冻结正文a\n冻结正文b',
|
||||
}),
|
||||
);
|
||||
expect(new Set(data.map((item) => item.dailyGroupKey)).size).toBe(4);
|
||||
expect(data.every((item) => item.notificationDate.toISOString() === '2026-09-09T00:00:00.000Z')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not regenerate already-published or historical single-detection messages', async () => {
|
||||
const { prisma, service } = setup();
|
||||
prisma.signatureRetirementMessage.findFirst.mockResolvedValue({ id: 'existing' });
|
||||
expect((await service.publishNotifications('2026-09-09')).created).toBe(0);
|
||||
expect(prisma.signatureRetirementMessage.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['2024-03-01', '2024-02-29'],
|
||||
['2026-01-01', '2025-12-31'],
|
||||
['2026-09-01', '2026-08-31'],
|
||||
])('keeps T-1 semantics for %s without constructing formatters per row', async (date, expected) => {
|
||||
const prisma = {
|
||||
signatureRetirementDetection: {
|
||||
findMany: jest.fn().mockResolvedValue(
|
||||
Array.from({ length: 100 }, (_, i) => ({
|
||||
id: String(i),
|
||||
detectionDate: new Date(`${date}T00:00:00Z`),
|
||||
signatureId: 's',
|
||||
tenantId: 't',
|
||||
})),
|
||||
),
|
||||
},
|
||||
smsSignature: { findMany: jest.fn().mockResolvedValue([]) },
|
||||
smsChannel: { findMany: jest.fn().mockResolvedValue([]) },
|
||||
tenant: { findMany: jest.fn().mockResolvedValue([]) },
|
||||
channelSignatureReportTask: { findMany: jest.fn().mockResolvedValue([]) },
|
||||
};
|
||||
const spy = jest.spyOn(Intl, 'DateTimeFormat');
|
||||
try {
|
||||
const result = await new SignatureRetirementService(prisma as never).heatmap(date);
|
||||
expect(result.items.every((item) => item.activityDate === expected)).toBe(true);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
spy.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user