Files
pulse-signage/test/email-otp-routes.test.js

138 lines
4.9 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
require('../src/common');
const registerAuthRoutes = require('../src/web/routes/auth');
const registerAccountRoutes = require('../src/web/routes/admin/account');
function createApp() {
const handlers = {};
return {
handlers: handlers,
get(path, ...routeHandlers) { handlers['GET ' + path] = routeHandlers; },
post(path, ...routeHandlers) { handlers['POST ' + path] = routeHandlers; }
};
}
function settingsQuery(sql) {
return String(sql).includes('SELECT id, setting_key, setting_value FROM o_app_settings');
}
test('forgot password requests a Better Auth OTP for a verified account', async () => {
let requestedEmail = '';
let renderedResetPage = null;
const app = createApp();
const pool = {
async query(sql) {
if (settingsQuery(sql)) return [[{ setting_key: 'email.smtp_enabled', setting_value: true }]];
if (String(sql).includes('SELECT id, email, email_verified FROM a_users')) {
return [[{ id: 9, email: 'person@example.test', email_verified: true }]];
}
return [[]];
}
};
registerAuthRoutes(app, {
pool: pool,
pages: {
renderResetPasswordPage(message, email) {
renderedResetPage = { message: message, email: email };
return 'reset-page';
}
},
betterAuth: {
api: {
async requestPasswordResetEmailOTP({ body }) { requestedEmail = body.email; }
}
},
parseCookies() { return {}; },
hashSessionToken(value) { return value; },
sessionCookieName: 'session'
});
const response = { send(value) { this.body = value; return this; } };
await app.handlers['POST /forgot-password'][0]({ body: { identity: 'person' } }, response, (error) => { throw error; });
assert.equal(requestedEmail, 'person@example.test');
assert.equal(response.body, 'reset-page');
assert.equal(renderedResetPage.email, '');
assert.match(renderedResetPage.message, /reset code/);
});
test('password reset verifies the OTP through Better Auth', async () => {
let resetBody = null;
const app = createApp();
const pool = { async query(sql) { return settingsQuery(sql) ? [[]] : [[]]; } };
registerAuthRoutes(app, {
pool: pool,
pages: {
renderResetPasswordPage(message, email) { return message + ':' + email; },
renderForgotPasswordPage(message) { return message; }
},
betterAuth: {
api: {
async resetPasswordEmailOTP({ body }) { resetBody = body; }
}
},
validatePasswordStrength() { return ''; },
parseCookies() { return {}; },
hashSessionToken(value) { return value; },
sessionCookieName: 'session'
});
const response = { send(value) { this.body = value; return this; } };
await app.handlers['POST /reset-password'][0]({
body: { email: 'person@example.test', otp: '123456', password: 'NewPassword!123', confirm_password: 'NewPassword!123' }
}, response, (error) => { throw error; });
assert.deepEqual(resetBody, { email: 'person@example.test', otp: '123456', password: 'NewPassword!123' });
assert.match(response.body, /Password updated/);
});
test('pending email change verifies through Better Auth and syncs the app email', async () => {
const calls = [];
const app = createApp();
const pool = {
async query(sql, params) {
calls.push([String(sql), params]);
const text = String(sql);
if (settingsQuery(text)) return [[{ setting_key: 'email.smtp_enabled', setting_value: true }]];
if (text.includes('SELECT email, email_verified, pending_email FROM a_users')) {
return [[{ email: 'old@example.test', pending_email: 'new@example.test' }]];
}
if (text.includes('SELECT id, created_at, modified_at FROM a_users')) {
return [[{ id: 7, created_at: new Date(), modified_at: new Date() }]];
}
return [{ affectedRows: 1, insertId: 1 }];
}
};
let verifiedBody = null;
registerAccountRoutes(app, {
pool: pool,
common: {},
pages: {},
betterAuth: {
api: {
async changeEmailEmailOTP({ body, headers }) {
verifiedBody = { body: body, headers: headers };
}
}
},
fromNodeHeaders(headers) { return { cookie: headers.cookie }; },
parseCookies() { return {}; },
sessionCookieName: 'session'
});
const response = { redirect(url) { this.redirectedTo = url; } };
await app.handlers['POST /account/email/verify'][0]({
body: { otp: '654321' },
headers: { cookie: 'session=token' },
currentUser: { id: 7 }
}, response, (error) => { throw error; });
assert.deepEqual(verifiedBody, { body: { newEmail: 'new@example.test', otp: '654321' }, headers: { cookie: 'session=token' } });
assert.ok(calls.some(([sql, params]) => sql.includes('UPDATE a_users SET email = ?, email_verified = 1, pending_email = NULL') && params[0] === 'new@example.test'));
assert.match(response.redirectedTo, /Email%20address%20verified/);
});