warmbox/apps/api/src/test/integration/recipes.integration.test.ts

118 lines
3.8 KiB
TypeScript

import { after, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { CampaignRecipe, MailboxRole } from '../../lib/prisma';
import { assignSatellite, createCampaign, startCampaign } from '../../services/campaign.service';
import { prisma } from '../../lib/prisma';
import {
cleanupCampaign,
cleanupInbox,
createTestInbox,
} from '../helpers/test-db';
describe('integration: recipes', () => {
const campaignIds: string[] = [];
const inboxIds: string[] = [];
after(async () => {
for (const id of campaignIds) await cleanupCampaign(id);
for (const id of inboxIds) await cleanupInbox(id);
});
async function setupCampaign(recipe: CampaignRecipe, extra?: Record<string, unknown>) {
const primary = await createTestInbox({ role: MailboxRole.primary });
const sat1 = await createTestInbox();
const sat2 = await createTestInbox();
inboxIds.push(primary.id, sat1.id, sat2.id);
const campaign = await createCampaign({
primaryMailboxId: primary.id,
name: `Test ${recipe}`,
recipe,
durationDays: 14,
minEmailsPerDay: 1,
maxEmailsPerDay: 40,
...extra,
});
campaignIds.push(campaign.id);
await assignSatellite(campaign.id, sat1.id);
await assignSatellite(campaign.id, sat2.id);
return startCampaign(campaign.id);
}
it('flat recipe persists constant plannedSends', async () => {
const campaign = await setupCampaign(CampaignRecipe.flat);
const schedules = await prisma.dailySchedule.findMany({
where: { campaignId: campaign.id },
orderBy: { dayIndex: 'asc' },
});
assert.equal(schedules.length, 14);
for (const row of schedules) {
assert.equal(row.plannedSends, 40);
}
});
it('custom recipe persists hold-last schedule', async () => {
const primary = await createTestInbox({ role: MailboxRole.primary });
const sat1 = await createTestInbox();
const sat2 = await createTestInbox();
inboxIds.push(primary.id, sat1.id, sat2.id);
const campaign = await createCampaign({
primaryMailboxId: primary.id,
name: 'Test custom',
recipe: CampaignRecipe.custom,
durationDays: 14,
customSchedule: [
{ day: 1, sends: 2 },
{ day: 2, sends: 5 },
],
});
campaignIds.push(campaign.id);
await assignSatellite(campaign.id, sat1.id);
await assignSatellite(campaign.id, sat2.id);
const started = await startCampaign(campaign.id);
const schedules = await prisma.dailySchedule.findMany({
where: { campaignId: started.id },
orderBy: { dayIndex: 'asc' },
});
assert.equal(schedules[0]!.plannedSends, 2);
assert.equal(schedules[1]!.plannedSends, 5);
assert.equal(schedules[13]!.plannedSends, 5);
});
it('randomized recipe is deterministic per campaign id seed', async () => {
const a = await setupCampaign(CampaignRecipe.randomized);
const bPrimary = await createTestInbox({ role: MailboxRole.primary });
inboxIds.push(bPrimary.id);
const b = await createCampaign({
primaryMailboxId: bPrimary.id,
name: 'Random B',
recipe: CampaignRecipe.randomized,
durationDays: 14,
});
campaignIds.push(b.id);
const satB1 = await createTestInbox();
const satB2 = await createTestInbox();
inboxIds.push(satB1.id, satB2.id);
await assignSatellite(b.id, satB1.id);
await assignSatellite(b.id, satB2.id);
const scheduleA = await prisma.dailySchedule.findMany({
where: { campaignId: a.id },
orderBy: { dayIndex: 'asc' },
});
const restarted = await startCampaign(b.id);
const scheduleB = await prisma.dailySchedule.findMany({
where: { campaignId: restarted.id },
orderBy: { dayIndex: 'asc' },
});
assert.notDeepEqual(
scheduleA.map((r) => r.plannedSends),
scheduleB.map((r) => r.plannedSends),
);
});
});