import { wait } from "@stackframe/stack-shared/dist/utils/promises"; import { Mailbox, test } from "../helpers"; import { withPortPrefix } from "../helpers/ports"; import { Auth, InternalApiKey, Project, bumpEmailAddress, createMailbox, niceBackendFetch } from "./backend-helpers"; async function configureEmailAndWorkflow(workflowId: string, tsSource: string, enabled = true) { await Project.updateConfig({ emails: { server: { isShared: false, host: "localhost", port: Number(withPortPrefix("29")), username: "test", password: "test", senderEmail: "test@example.com", senderName: "Test Project", }, }, workflows: { availableWorkflows: { [workflowId]: { displayName: workflowId, tsSource, enabled, }, }, }, }); } const waitRetries = 25; async function waitForMailboxSubject(mailbox: Mailbox, subject: string) { for (let i = 0; i < waitRetries; i++) { const messages = await mailbox.fetchMessages(); const message = messages.find((m) => m.subject === subject); if (message) return; await wait(1_000); } throw new Error(`Message with subject ${subject} not found after ${waitRetries} tries`); } async function waitForServerMetadataNotNull(userId: string, key: string) { for (let i = 0; i < waitRetries; i++) { const user = await niceBackendFetch(`/api/v1/users/${userId}`, { accessType: "server" }); if (user.body.server_metadata?.[key]) return; await wait(1_000); } throw new Error(`Server metadata for user ${userId} with key ${key} not found after ${waitRetries} tries`); } test("onSignUp workflow sends email for client sign-up", async ({ expect }) => { await Project.createAndSwitch(); await InternalApiKey.createAndSetProjectKeys(); const mailbox = await bumpEmailAddress({ unindexed: true }); const subject = `WF client signup ${crypto.randomUUID()}`; await configureEmailAndWorkflow("wf-email", ` onSignUp(async (user) => { await stackApp.sendEmail({ userIds: [user.id], subject: ${JSON.stringify(subject)}, html: "

hi

" }); // schedule a callback as an example (we don't actually test whether it executed successfully) return scheduleCallback({ scheduleAt: new Date(Date.now() + 7_000), data: { "example": "data" }, callbackId: "my-callback", }); }); registerCallback("my-callback", async (data) => { console.log("my-callback", data); }); `); await Auth.Password.signUpWithEmail({ password: "password" }); await waitForMailboxSubject(mailbox, subject); expect(await mailbox.fetchMessages()).toMatchInlineSnapshot(` [ MailboxMessage { "attachments": [], "body": { "html": "http://localhost:12345/some-callback-url?code=%3Cstripped+query+param%3E", "text": "http://localhost:12345/some-callback-url?code=%3Cstripped+query+param%3E", }, "from": "Test Project ", "subject": "Verify your email at New Project", "to": ["@stack-generated.example.com>"],