v4.0.14概览和日报
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-09-02 21:11:58 +08:00
parent e5fe8b903a
commit 68a4b7f984
41 changed files with 3815 additions and 1098 deletions
+133
View File
@@ -0,0 +1,133 @@
import { describe, expect, it } from 'vitest';
import {
formatWecomReportMarkdown,
wecomReportCutoff,
wecomReportDueAt,
wecomReportPeriod,
wecomReportShouldFire,
} from './wecom-report';
const emptyStats = {
usersTotal: 10,
usersIncrement: 2,
partnersTotal: 3,
partnersIncrement: 1,
storesTotal: 4,
storesIncrement: 0,
ordersTotal: 20,
ordersIncrement: 5,
orderAmountTotal: 1000,
orderAmountIncrement: 80.5,
redeemsTotal: 8,
redeemsIncrement: 3,
redeemAmountTotal: 200,
redeemAmountIncrement: 40,
};
describe('wecomReportPeriod', () => {
it('daily is the Shanghai calendar day', () => {
const p = wecomReportPeriod('daily', new Date('2026-09-02T20:00:00+08:00'));
expect(p.periodKey).toBe('2026-09-02');
expect(p.incrementLabel).toBe('当日新增');
expect(p.start.toISOString()).toBe(new Date('2026-09-02T00:00:00+08:00').toISOString());
});
it('weekly is the previous natural week', () => {
const p = wecomReportPeriod('weekly', new Date('2026-09-02T09:00:00+08:00'));
expect(p.periodKey).toBe('2026-08-24');
expect(p.rangeLabel).toBe('2026-08-24 ~ 2026-08-30');
expect(p.incrementLabel).toBe('本期新增');
});
it('monthly is the previous natural month', () => {
const p = wecomReportPeriod('monthly', new Date('2026-09-01T09:00:00+08:00'));
expect(p.periodKey).toBe('2026-08');
expect(p.title).toBe('月报(2026年8月)');
});
});
describe('wecomReportCutoff', () => {
it('caps an in-progress daily period at now', () => {
const now = new Date('2026-09-02T20:00:00+08:00');
const p = wecomReportPeriod('daily', now);
expect(wecomReportCutoff(p, now).getTime()).toBe(now.getTime());
});
it('uses period end for a completed week', () => {
const now = new Date('2026-09-02T09:00:00+08:00');
const p = wecomReportPeriod('weekly', now);
expect(wecomReportCutoff(p, now).getTime()).toBe(p.endExclusive.getTime());
});
});
describe('wecomReportShouldFire', () => {
const base = {
enabled: true,
sendHour: 20,
sendMinute: 0,
sendWeekday: 1,
sendMonthDay: 1,
lastSentPeriod: null as string | null,
};
it('does not fire before due time', () => {
expect(
wecomReportShouldFire('daily', base, new Date('2026-09-02T19:59:00+08:00')),
).toBe(false);
});
it('fires after due time if this period not sent', () => {
expect(
wecomReportShouldFire('daily', base, new Date('2026-09-02T20:00:00+08:00')),
).toBe(true);
});
it('does not fire twice for the same period', () => {
expect(
wecomReportShouldFire(
'daily',
{ ...base, lastSentPeriod: '2026-09-02' },
new Date('2026-09-02T21:00:00+08:00'),
),
).toBe(false);
});
it('weekly fires Monday 09:00 for last week', () => {
expect(
wecomReportShouldFire(
'weekly',
{ ...base, sendHour: 9, sendMinute: 0, sendWeekday: 1 },
new Date('2026-09-07T09:00:00+08:00'),
),
).toBe(true);
});
});
describe('wecomReportDueAt', () => {
it('monthly clamps to last day of month', () => {
const due = wecomReportDueAt(
'monthly',
{
enabled: true,
sendHour: 9,
sendMinute: 0,
sendWeekday: 1,
sendMonthDay: 31,
lastSentPeriod: null,
},
new Date('2026-09-10T00:00:00+08:00'),
);
expect(due.toISOString()).toBe(new Date('2026-09-30T09:00:00+08:00').toISOString());
});
});
describe('formatWecomReportMarkdown', () => {
it('renders stock plus increment lines', () => {
const p = wecomReportPeriod('daily', new Date('2026-09-02T20:00:00+08:00'));
const md = formatWecomReportMarkdown(p, emptyStats);
expect(md).toContain('**杜康好客 · 日报(2026-09-02**');
expect(md).toContain('用户数量:10(当日新增 2');
expect(md).toContain('订单金额:1000.00(当日新增 80.50');
expect(md).toContain('核销单数量:8(当日新增 3)');
});
});