test fixes

This commit is contained in:
Bilal Godil 2025-09-11 18:11:22 -07:00
parent d14317c787
commit f42dfc5351
3 changed files with 38 additions and 33 deletions

View File

@ -294,11 +294,17 @@ it("should return 200 and send email successfully", async ({ expect }) => {
`);
// Verify the email was actually sent by checking the mailbox
await wait(2000);
const messages = await user.mailbox.fetchMessages();
const sentEmail = messages.find(msg => msg.subject === "Custom Test Email Subject");
expect(sentEmail).toBeDefined();
expect(sentEmail!.body?.html).toMatchInlineSnapshot(`"http://localhost:8102/api/v1/emails/unsubscribe-link?code=%3Cstripped+query+param%3E"`);
const messages = await user.mailbox.waitForMessagesWithSubject("Custom Test Email Subject");
expect(messages).toMatchInlineSnapshot(`
[
MailboxMessage {
"from": "Test Project <test@example.com>",
"subject": "Custom Test Email Subject",
"to": ["<unindexed-mailbox--<stripped UUID>@stack-generated.example.com>"],
<some fields may have been hidden>,
},
]
`);
});
it("should handle user that does not exist", async ({ expect }) => {
@ -403,11 +409,7 @@ export function EmailTemplate({ user, project }: Props) {
expect(sendRes.status).toBe(200);
expect(sendRes.body.results).toHaveLength(1);
await wait(3000);
const messages = await user.mailbox.fetchMessages();
const sentEmail = messages.find(m => m.subject === "Overridden Subject");
expect(sentEmail).toBeDefined();
await user.mailbox.waitForMessagesWithSubject("Overridden Subject");
const getDraftRes = await niceBackendFetch(`/api/v1/internal/email-drafts/${draftId}`, {
method: "GET",
accessType: "admin",
@ -590,13 +592,9 @@ describe("all users", () => {
}
`);
await wait(2000);
const messagesA = await userA.mailbox.fetchMessages();
const messagesB = await userB.mailbox.fetchMessages();
const messagesC = await userC.mailbox.fetchMessages();
expect(messagesA.find(m => m.subject === subject)).toBeDefined();
expect(messagesB.find(m => m.subject === subject)).toBeDefined();
expect(messagesC.find(m => m.subject === subject)).toBeDefined();
await userA.mailbox.waitForMessagesWithSubject(subject);
await userB.mailbox.waitForMessagesWithSubject(subject);
await userC.mailbox.waitForMessagesWithSubject(subject);
});
});
@ -740,10 +738,7 @@ describe("notification categories", () => {
`);
// Verify the email was sent
await wait(2000);
const messages = await user.mailbox.fetchMessages();
const sentEmail = messages.find(msg => msg.subject === "Transactional Test Subject");
expect(sentEmail).toBeDefined();
await user.mailbox.waitForMessagesWithSubject("Transactional Test Subject");
});
it("should default to Transactional category when notification_category_name is not provided", async ({ expect }) => {
@ -782,9 +777,6 @@ describe("notification categories", () => {
`);
// Verify the email was sent
await wait(2000);
const messages = await user.mailbox.fetchMessages();
const sentEmail = messages.find(msg => msg.subject === "Default Category Test Subject");
expect(sentEmail).toBeDefined();
await user.mailbox.waitForMessagesWithSubject("Default Category Test Subject");
});
});

View File

@ -48,10 +48,8 @@ it("unsubscribe link should be sent and update notification preference", async (
`);
// Verify the email was actually sent by checking the mailbox
await wait(2000);
const messages = await user.mailbox.fetchMessages();
const sentEmail = messages.find(msg => msg.subject === "Custom Test Email Subject");
expect(sentEmail).toBeDefined();
const messages = await user.mailbox.waitForMessagesWithSubject("Custom Test Email Subject");
const sentEmail = messages[0];
expect(sentEmail!.body?.html).toMatchInlineSnapshot(`"http://localhost:8102/api/v1/emails/unsubscribe-link?code=%3Cstripped+query+param%3E"`);
// Extract the unsubscribe link and fetch it
@ -142,9 +140,8 @@ it("unsubscribe link should not be sent for emails with transactional notificati
}
`);
await wait(2000);
const messages = await user.mailbox.fetchMessages();
const sentEmail = messages.find(msg => msg.subject === "Custom Test Email Subject");
const messages = await user.mailbox.waitForMessagesWithSubject("Custom Test Email Subject");
const sentEmail = messages[0];
expect(sentEmail).toBeDefined();
expect(sentEmail!.body?.html).toMatchInlineSnapshot(`"<!DOCTYPE html PUBLIC \\"-//W3C//DTD XHTML 1.0 Transitional//EN\\" \\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\\"><html dir=\\"ltr\\" lang=\\"en\\"><head><meta content=\\"text/html; charset=UTF-8\\" http-equiv=\\"Content-Type\\"/><meta name=\\"x-apple-disable-message-reformatting\\"/></head><body style=\\"background-color:rgb(250,251,251);font-family:ui-sans-serif, system-ui, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;;font-size:1rem;line-height:1.5rem\\"><!--$--><table align=\\"center\\" width=\\"100%\\" border=\\"0\\" cellPadding=\\"0\\" cellSpacing=\\"0\\" role=\\"presentation\\" style=\\"background-color:rgb(255,255,255);padding:45px;border-radius:0.5rem;max-width:37.5em\\"><tbody><tr style=\\"width:100%\\"><td><div><h1>Test Email</h1><p>This is a test email with HTML content.</p></div></td></tr></tbody></table><!--7--><!--/$--></body></html>"`);
});

View File

@ -1,6 +1,7 @@
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
import { StackAssertionError } from "@stackframe/stack-shared/dist/utils/errors";
import { filterUndefined, omit } from "@stackframe/stack-shared/dist/utils/objects";
import { wait } from "@stackframe/stack-shared/dist/utils/promises";
import { Nicifiable } from "@stackframe/stack-shared/dist/utils/strings";
import { AsyncLocalStorage } from "node:async_hooks";
// eslint-disable-next-line no-restricted-imports
@ -129,7 +130,7 @@ export class NiceResponse implements Nicifiable {
public readonly headers: Headers,
public readonly body: any,
public readonly fromRequestInit?: NiceRequestInit,
) {}
) { }
getNicifiableKeys(): string[] {
// reorder the keys for nicer printing
@ -198,6 +199,7 @@ export const generatedEmailRegex = /[a-zA-Z0-9_.+\-]+@stack-generated\.example\.
export class Mailbox {
public readonly fetchMessages: (options?: { noBody?: boolean }) => Promise<MailboxMessage[]>;
public readonly waitForMessagesWithSubject: (subject: string) => Promise<MailboxMessage[]>;
constructor(
disclaimer: "USE_CREATE_MAILBOX_FUNCTION_INSTEAD",
@ -205,6 +207,7 @@ export class Mailbox {
) {
const mailboxName = emailAddress.split("@")[0];
const fullMessageCache = new Map<string, any>();
this.fetchMessages = async ({ noBody } = {}) => {
const res = await niceFetch(new URL(`/api/v1/mailbox/${encodeURIComponent(mailboxName)}`, INBUCKET_API_URL));
return await Promise.all((res.body as any[]).map(async (message) => {
@ -220,6 +223,19 @@ export class Mailbox {
return new MailboxMessage(messagePart);
}));
};
this.waitForMessagesWithSubject = async (subject: string) => {
const maxRetries = 20;
for (let i = 0; i < maxRetries; i++) {
const messages = await this.fetchMessages({ noBody: true });
const withSubject = messages.filter(m => m.subject === subject);
if (withSubject.length > 0) {
return withSubject;
}
await wait(200);
}
throw new Error(`Message with subject ${subject} not found`);
};
}
}