feat(marketing-pages): sendWelcomeEmail job + handler enqueues it
sendWelcomeEmailJob takes IMailerService, validates the typed input (userId + email), and delegates to mailer.sendWelcome. The onAuthUserSignedUpHandler now takes IJobQueue and enqueues "marketing-pages.send-welcome-email" with the event payload. Both binders bind a RecordingMailerService at the IMailerService symbol (production placeholder until a real adapter ships) and pass mailer / queue into the wrapped factories. Dev-seed additionally queue.register()s the slug so the in-memory queue dispatches via the wrapped job; production relies on the generated Payload event-task to resolve the wrapped handler from the container.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
// packages/marketing-pages/src/jobs/send-welcome-email.job.test.ts
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { sendWelcomeEmailJob, sendWelcomeEmailInputSchema } from "@/jobs/send-welcome-email.job";
|
||||
import { RecordingMailerService } from "@/infrastructure/services/recording-mailer.service";
|
||||
|
||||
describe("sendWelcomeEmailJob", () => {
|
||||
it("rejects unknown input fields", async () => {
|
||||
const mailer = new RecordingMailerService();
|
||||
const job = sendWelcomeEmailJob(mailer);
|
||||
await expect(job({ unexpectedField: 1 } as never)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("rejects input missing required fields", async () => {
|
||||
const mailer = new RecordingMailerService();
|
||||
const job = sendWelcomeEmailJob(mailer);
|
||||
await expect(job({ userId: "u1" } as never)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("rejects invalid email", async () => {
|
||||
const mailer = new RecordingMailerService();
|
||||
const job = sendWelcomeEmailJob(mailer);
|
||||
await expect(
|
||||
job({ userId: "u1", email: "not-an-email" }),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("sends a welcome email via the mailer on valid input", async () => {
|
||||
const mailer = new RecordingMailerService();
|
||||
const job = sendWelcomeEmailJob(mailer);
|
||||
await job({ userId: "u1", email: "u1@example.com" });
|
||||
expect(mailer.sent).toEqual([{ userId: "u1", email: "u1@example.com" }]);
|
||||
});
|
||||
|
||||
it("references its input schema", () => {
|
||||
expect(sendWelcomeEmailInputSchema).toBeDefined();
|
||||
});
|
||||
});
|
||||
20
packages/marketing-pages/src/jobs/send-welcome-email.job.ts
Normal file
20
packages/marketing-pages/src/jobs/send-welcome-email.job.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// packages/marketing-pages/src/jobs/send-welcome-email.job.ts
|
||||
import { z } from "zod";
|
||||
import type { IMailerService } from "../application/services/mailer.service.interface";
|
||||
|
||||
export const sendWelcomeEmailInputSchema = z
|
||||
.object({
|
||||
userId: z.string(),
|
||||
email: z.string().email(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export type SendWelcomeEmailInput = z.infer<typeof sendWelcomeEmailInputSchema>;
|
||||
export type ISendWelcomeEmailJob = ReturnType<typeof sendWelcomeEmailJob>;
|
||||
|
||||
export const sendWelcomeEmailJob =
|
||||
(mailer: IMailerService) =>
|
||||
async (input: SendWelcomeEmailInput): Promise<void> => {
|
||||
sendWelcomeEmailInputSchema.parse(input);
|
||||
await mailer.sendWelcome(input.userId, input.email);
|
||||
};
|
||||
Reference in New Issue
Block a user