Skip to content

Commit ddf2c89

Browse files
committed
refactor: poll instead of waiting in email-queue
waiting can often lead to timeout issues/ race conditions. Polling with early exit is a better pattern. We refactor to bring things in line with the other tests
1 parent e1e1249 commit ddf2c89

1 file changed

Lines changed: 20 additions & 44 deletions

File tree

apps/e2e/tests/backend/endpoints/api/v1/emails/email-queue.test.ts

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,15 @@ describe("email queue edge cases", () => {
9797
});
9898
expect(deleteResponse.status).toBe(200);
9999

100-
// Wait for email processing
101-
await wait(10_000);
100+
// Poll until outbox shows SKIPPED with USER_ACCOUNT_DELETED
101+
const outboxEmails = await waitForOutboxEmailWithStatus("Slow Render Test Email", "skipped");
102+
expect(outboxEmails.length).toBe(1);
103+
expect(outboxEmails[0].skipped_reason).toBe("USER_ACCOUNT_DELETED");
102104

103105
// Verify no email was received (user was deleted)
104106
const messages = await mailbox.fetchMessages();
105107
const testEmails = messages.filter(m => m.subject === "Slow Render Test Email");
106108
expect(testEmails).toHaveLength(0);
107-
108-
// Verify outbox shows SKIPPED with USER_ACCOUNT_DELETED
109-
const outboxEmails = await getOutboxEmails({ subject: "Slow Render Test Email" });
110-
expect(outboxEmails.length).toBe(1);
111-
expect(outboxEmails[0].status).toBe("skipped");
112-
expect(outboxEmails[0].skipped_reason).toBe("USER_ACCOUNT_DELETED");
113109
});
114110

115111
it("should skip email when user removes primary email after email is queued", async ({ expect }) => {
@@ -168,19 +164,15 @@ describe("email queue edge cases", () => {
168164
});
169165
expect(deleteChannelResponse.status).toBe(200);
170166

171-
// Wait for email processing to complete (rendering + sending)
172-
await wait(10_000);
167+
// Poll until outbox shows SKIPPED with USER_HAS_NO_PRIMARY_EMAIL
168+
const outboxEmails = await waitForOutboxEmailWithStatus("Slow Render Test Email", "skipped");
169+
expect(outboxEmails.length).toBe(1);
170+
expect(outboxEmails[0].skipped_reason).toBe("USER_HAS_NO_PRIMARY_EMAIL");
173171

174172
// Verify no email with our subject was received (primary email was removed before sending)
175173
const messages = await mailbox.fetchMessages();
176174
const testEmails = messages.filter(m => m.subject === "Slow Render Test Email");
177175
expect(testEmails).toHaveLength(0);
178-
179-
// Verify outbox shows SKIPPED with USER_HAS_NO_PRIMARY_EMAIL
180-
const outboxEmails = await getOutboxEmails({ subject: "Slow Render Test Email" });
181-
expect(outboxEmails.length).toBe(1);
182-
expect(outboxEmails[0].status).toBe("skipped");
183-
expect(outboxEmails[0].skipped_reason).toBe("USER_HAS_NO_PRIMARY_EMAIL");
184176
});
185177

186178
it("should skip email when user unsubscribes after email is queued", async ({ expect }) => {
@@ -236,19 +228,15 @@ describe("email queue edge cases", () => {
236228
);
237229
expect(unsubscribeResponse.status).toBe(200);
238230

239-
// Wait for email processing
240-
await wait(10_000);
231+
// Poll until outbox shows SKIPPED with USER_UNSUBSCRIBED
232+
const outboxEmails = await waitForOutboxEmailWithStatus("Slow Render Test Email", "skipped");
233+
expect(outboxEmails.length).toBe(1);
234+
expect(outboxEmails[0].skipped_reason).toBe("USER_UNSUBSCRIBED");
241235

242236
// Verify no email with our subject was received (user unsubscribed)
243237
const messages = await backendContext.value.mailbox.fetchMessages();
244238
const testEmails = messages.filter(m => m.subject === "Slow Render Test Email");
245239
expect(testEmails).toHaveLength(0);
246-
247-
// Verify outbox shows SKIPPED with USER_UNSUBSCRIBED
248-
const outboxEmails = await getOutboxEmails({ subject: "Slow Render Test Email" });
249-
expect(outboxEmails.length).toBe(1);
250-
expect(outboxEmails[0].status).toBe("skipped");
251-
expect(outboxEmails[0].skipped_reason).toBe("USER_UNSUBSCRIBED");
252240
});
253241

254242
it("should NOT skip transactional email even when user unsubscribes from marketing", async ({ expect }) => {
@@ -1360,10 +1348,7 @@ describe("theme and template deletion after scheduling", () => {
13601348
// For a proper test, we'd need to pause the email, but the send-email endpoint
13611349
// doesn't support is_paused directly.
13621350

1363-
// Wait for email processing
1364-
await wait(5_000);
1365-
1366-
// Verify the email was sent successfully
1351+
// Poll until email is received (waitForMessagesWithSubject already does polling)
13671352
const messages = await mailbox.waitForMessagesWithSubject("Theme Fallback Test Email");
13681353
expect(messages.length).toBeGreaterThanOrEqual(1);
13691354

@@ -1445,10 +1430,7 @@ describe("theme and template deletion after scheduling", () => {
14451430
}
14461431
}
14471432

1448-
// Wait for email processing
1449-
await wait(5_000);
1450-
1451-
// Verify the email was sent successfully
1433+
// Poll until email is received (waitForMessagesWithSubject already does polling)
14521434
const messages = await mailbox.waitForMessagesWithSubject("Theme Fallback Test Email");
14531435
expect(messages.length).toBeGreaterThanOrEqual(1);
14541436

@@ -1535,10 +1517,7 @@ describe("theme and template deletion after scheduling", () => {
15351517
// that the architecture is designed to handle template deletion safely
15361518
// because the source is copied to the outbox at scheduling time.
15371519

1538-
// Wait for email processing
1539-
await wait(5_000);
1540-
1541-
// Verify the email was sent successfully
1520+
// Poll until email is received (waitForMessagesWithSubject already does polling)
15421521
const messages = await mailbox.waitForMessagesWithSubject("Template Deletion Test Email");
15431522
expect(messages.length).toBeGreaterThanOrEqual(1);
15441523
expect(messages[0].body?.html).toContain("Content from template that will be deleted");
@@ -1625,10 +1604,7 @@ describe("theme and template deletion after scheduling", () => {
16251604
});
16261605
expect(sendResponse.status).toBe(200);
16271606

1628-
// Wait for email processing
1629-
await wait(5_000);
1630-
1631-
// Verify the email was sent successfully with the custom theme
1607+
// Poll until email is received (waitForMessagesWithSubject already does polling)
16321608
const messages = await mailbox.waitForMessagesWithSubject("Custom Theme Baseline Test Email");
16331609
expect(messages.length).toBeGreaterThanOrEqual(1);
16341610

@@ -1838,9 +1814,9 @@ describe("email outbox pagination", () => {
18381814
expect(sendResponse.status).toBe(200);
18391815
}
18401816

1841-
// Poll until all 3 emails appear in outbox
1842-
const maxAttempts = 30;
1843-
const pollInterval = 200;
1817+
// Poll until all 3 emails appear in outbox (wait up to 12s, matching waitForOutboxEmailWithStatus)
1818+
const maxAttempts = 24;
1819+
const pollInterval = 500;
18441820
let emails: Array<{ subject?: string, created_at_millis: number }> = [];
18451821

18461822
for (let attempt = 0; attempt < maxAttempts; attempt++) {
@@ -1867,6 +1843,6 @@ describe("email outbox pagination", () => {
18671843
const next = emails[i + 1];
18681844
expect(current.created_at_millis).toBeGreaterThanOrEqual(next.created_at_millis);
18691845
}
1870-
});
1846+
}, 60_000);
18711847
});
18721848

0 commit comments

Comments
 (0)