const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const test = require("node:test"); const vm = require("node:vm"); const root = path.resolve(__dirname, "../.."); const source = fs.readFileSync( path.join(root, "lib/auth/email-provider.js"), "utf8" ); const EmailProvider = vm.runInNewContext( source.replace("export default EmailProvider;", "") + "\nEmailProvider;", {} ); const OriginalEmailProvider = require("next-auth/providers/email").default; const customSender = async () => {}; const options = { maxAge: 2 * 60 * 60, sendVerificationRequest: customSender }; const normalize = (provider) => { const { options: userOptions, ...defaults } = provider; return { ...defaults, ...userOptions }; }; test("local provider preserves NextAuth email provider defaults", () => { const original = OriginalEmailProvider(options); const replacement = EmailProvider(options); for (const property of ["id", "type", "name", "server", "from", "maxAge"]) { assert.deepEqual( JSON.parse(JSON.stringify(replacement[property])), JSON.parse(JSON.stringify(original[property])), `Mismatch in ${property}` ); } }); test("local provider preserves the user options contract", () => { const provider = EmailProvider(options); assert.equal(provider.options.maxAge, 7200); assert.equal(provider.options.sendVerificationRequest, customSender); }); test("normalized provider retains two-hour token expiry", () => { const original = normalize(OriginalEmailProvider(options)); const replacement = normalize(EmailProvider(options)); assert.equal(original.maxAge, 7200); assert.equal(replacement.maxAge, original.maxAge); }); test("normalized provider uses the custom verification sender", () => { const provider = normalize(EmailProvider(options)); assert.equal(provider.sendVerificationRequest, customSender); }); test("provider retains NextAuth email identity", () => { const provider = normalize(EmailProvider(options)); assert.equal(provider.id, "email"); assert.equal(provider.type, "email"); assert.equal(provider.name, "Email"); }); test("default sender fails explicitly without PEDW override", async () => { const provider = EmailProvider(); await assert.rejects( provider.sendVerificationRequest(), /requires a custom GOV\.UK Notify verification sender/ ); }); test("local provider does not import Nodemailer", () => { assert.doesNotMatch( source, /(?:require\s*\(|from\s+|import\s*\()\s*["']nodemailer/ ); }); test("authentication handler imports the local provider", () => { const authSource = fs.readFileSync( path.join(root, "pages/api/auth/[...nextauth].js"), "utf8" ); assert.match( authSource, /import EmailProvider from ["']\.\.\/\.\.\/\.\.\/lib\/auth\/email-provider["']/ ); assert.doesNotMatch(authSource, /from ["']next-auth\/providers\/email["']/); assert.match(authSource, /EmailProvider\s*\(\s*\{/); assert.match(authSource, /async sendVerificationRequest\s*\(/); assert.match(authSource, /notifyClient\.sendEmail\s*\(/); });