From dcfdc6fc90759edda535593199e184556ee4d7ae Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Mon, 9 Mar 2026 16:45:44 -0700 Subject: [PATCH] test(magic-link): add tests for additionalData feature - Runtime tests: passing additionalData via server API & client, validation with custom Zod schema, omitting additionalData - Type tests: infer additionalData type from custom schema, default type is Record --- .../src/plugins/magic-link/magic-link.test.ts | 124 +++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/packages/better-auth/src/plugins/magic-link/magic-link.test.ts b/packages/better-auth/src/plugins/magic-link/magic-link.test.ts index b8dfe22104..815bd02dcf 100644 --- a/packages/better-auth/src/plugins/magic-link/magic-link.test.ts +++ b/packages/better-auth/src/plugins/magic-link/magic-link.test.ts @@ -1,6 +1,8 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, expectTypeOf, it, vi } from "vitest"; +import * as z from "zod"; import { createAuthClient } from "../../client"; import { getTestInstance } from "../../test-utils/test-instance"; +import type { MagicLinkOptions } from "."; import { magicLink } from "."; import { magicLinkClient } from "./client"; import { defaultKeyHasher } from "./utils"; @@ -721,3 +723,123 @@ describe("magic link allowedAttempts", async () => { } }); }); + +describe("magic link additionalData", async () => { + it("should pass additionalData to sendMagicLink", async () => { + let receivedData: Record | undefined; + const { auth, signInWithTestUser, testUser } = await getTestInstance({ + plugins: [ + magicLink({ + async sendMagicLink(data) { + receivedData = data.additionalData; + }, + }), + ], + }); + + const { headers } = await signInWithTestUser(); + await auth.api.signInMagicLink({ + body: { + email: testUser.email, + additionalData: { message: "hello" }, + }, + headers, + }); + expect(receivedData).toEqual({ message: "hello" }); + }); + + it("should work without additionalData", async () => { + let receivedData: unknown = "not-called"; + const { auth, signInWithTestUser, testUser } = await getTestInstance({ + plugins: [ + magicLink({ + async sendMagicLink(data) { + receivedData = data.additionalData; + }, + }), + ], + }); + + const { headers } = await signInWithTestUser(); + await auth.api.signInMagicLink({ + body: { + email: testUser.email, + }, + headers, + }); + expect(receivedData).toBeUndefined(); + }); + + it("should validate additionalData with custom schema", async () => { + let receivedData: { message: string } | undefined; + const { auth, signInWithTestUser, testUser } = await getTestInstance({ + plugins: [ + magicLink({ + additionalDataSchema: z.object({ message: z.string() }), + async sendMagicLink(data) { + receivedData = data.additionalData; + }, + }), + ], + }); + + const { headers } = await signInWithTestUser(); + await auth.api.signInMagicLink({ + body: { + email: testUser.email, + additionalData: { message: "typed hello" }, + }, + headers, + }); + expect(receivedData).toEqual({ message: "typed hello" }); + }); + + it("should infer additionalData type from custom schema", () => { + const schema = z.object({ message: z.string(), count: z.number() }); + + type Opts = MagicLinkOptions; + type SendData = Parameters[0]; + + expectTypeOf().toEqualTypeOf< + { message: string; count: number } | undefined + >(); + }); + + it("should default additionalData type to Record", () => { + type DefaultOpts = MagicLinkOptions; + type SendData = Parameters[0]; + + expectTypeOf().not.toEqualTypeOf(); + expectTypeOf().toHaveProperty("additionalData"); + }); + + it("should pass additionalData from client", async () => { + let receivedData: Record | undefined; + const { customFetchImpl, testUser } = await getTestInstance({ + plugins: [ + magicLink({ + async sendMagicLink(data) { + receivedData = data.additionalData; + }, + }), + ], + }); + + const client = createAuthClient({ + plugins: [magicLinkClient()], + fetchOptions: { + customFetchImpl, + }, + baseURL: "http://localhost:3000/api/auth", + }); + + await client.signIn.magicLink({ + email: testUser.email, + additionalData: { source: "client", nested: { key: "value" } }, + }); + expect(receivedData).toEqual({ + source: "client", + nested: { key: "value" }, + }); + }); +});