process.env.SECRET_ENC_KEY = process.env.SECRET_ENC_KEY || 'unit-test-enc-key' process.env.DB_HOST = '127.0.0.1' process.env.DB_PORT = '59999' const { test, after, beforeEach } = require('node:test') const assert = require('node:assert/strict') const nodemailer = require('nodemailer') const emailConfig = require('../src/model/emailConfig/emailConfig.model') const authProviders = require('../src/model/authProviders/authProviders.model') const settings = require('../src/model/settings/settings.model') const mailer = require('../src/utils/mailer') const db = require('../src/utils/db') after(() => db.close()) // Restore a clean slate of stubs before each test. beforeEach(() => { emailConfig.recordStatus = async () => {} settings.get = async () => 'contact@example.com' }) test('unconfigured → mailto fallback (never throws)', async () => { emailConfig.getWithSecret = async () => null emailConfig.getSafe = async () => ({ senderEmail: null, hasRefreshToken: false, enabled: false }) const r = await mailer.sendContactMessage({ name: 'Ann', email: 'ann@player.com', message: 'hi' }) assert.deepEqual(r, { sent: false, fallback: 'mailto', email: 'contact@example.com' }) }) test('configured → builds a Gmail OAuth2 transport and sends', async () => { let transportCfg = null let sent = null nodemailer.createTransport = (cfg) => { transportCfg = cfg return { sendMail: async (opts) => { sent = opts; return { messageId: '1' } } } } emailConfig.getWithSecret = async () => ({ refreshToken: 'rt-123', senderEmail: 'shard@gmail.com', senderName: 'UOMysticmoon' }) authProviders.getWithSecret = async (id) => { assert.equal(id, 'google') return { client_id: 'cid', client_secret: 'csec' } } const r = await mailer.sendContactMessage({ name: 'Ann', email: 'ann@player.com', message: 'hi there' }) assert.equal(r.sent, true) // Transport is Gmail SMTP over XOAUTH2 with the reused Google client + stored refresh token. assert.equal(transportCfg.host, 'smtp.gmail.com') assert.equal(transportCfg.port, 465) assert.equal(transportCfg.secure, true) assert.equal(transportCfg.auth.type, 'OAuth2') assert.equal(transportCfg.auth.user, 'shard@gmail.com') assert.equal(transportCfg.auth.clientId, 'cid') assert.equal(transportCfg.auth.clientSecret, 'csec') assert.equal(transportCfg.auth.refreshToken, 'rt-123') // From uses the display name; To is the contact_email setting; replyTo is the sender. assert.equal(sent.from, '"UOMysticmoon" ') assert.equal(sent.to, 'contact@example.com') assert.equal(sent.replyTo, 'ann@player.com') }) test('send failure propagates and is recorded', async () => { let recorded = null emailConfig.recordStatus = async (s) => { recorded = s } nodemailer.createTransport = () => ({ sendMail: async () => { throw new Error('smtp boom') } }) emailConfig.getWithSecret = async () => ({ refreshToken: 'rt', senderEmail: 'shard@gmail.com', senderName: null }) authProviders.getWithSecret = async () => ({ client_id: 'cid', client_secret: 'csec' }) await assert.rejects(() => mailer.sendContactMessage({ name: 'A', email: 'a@b.com', message: 'x' }), /smtp boom/) assert.equal(recorded.status, 'error') })