Files
motovaultpro/backend/src/features/auth/tests/integration/auth.integration.test.ts
Eric Gullickson 754639c86d
Some checks failed
Deploy to Staging / Build Images (pull_request) Successful in 6m41s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Failing after 4m7s
Deploy to Staging / Notify Staging Ready (pull_request) Has been skipped
Deploy to Staging / Notify Staging Failure (pull_request) Successful in 9s
chore: update test fixtures and frontend for UUID identity (refs #217)
Backend test fixtures:
- Replace auth0|xxx format with UUID in all test userId values
- Update admin tests for new id/userProfileId schema
- Add missing deletionRequestedAt/deletionScheduledFor to auth test mocks
- Fix admin integration test supertest usage (app.server)

Frontend:
- AdminUser type: auth0Sub -> id + userProfileId
- admin.api.ts: all user management methods use userId (UUID) params
- useUsers/useAdmins hooks: auth0Sub -> userId/id in mutations
- AdminUsersPage + AdminUsersMobileScreen: user.auth0Sub -> user.id
- Remove encodeURIComponent (UUIDs don't need encoding)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 10:21:18 -06:00

216 lines
6.7 KiB
TypeScript

/**
* @ai-summary Integration tests for auth API endpoints
* @ai-context Tests complete request/response cycle with mocked Auth0
*/
import request from 'supertest';
import { buildApp } from '../../../../app';
import { pool } from '../../../../core/config/database';
import { auth0ManagementClient } from '../../../../core/auth/auth0-management.client';
import fastifyPlugin from 'fastify-plugin';
import { FastifyInstance } from 'fastify';
// Mock Auth0 Management client
jest.mock('../../../../core/auth/auth0-management.client');
const mockAuth0Client = jest.mocked(auth0ManagementClient);
// Mock auth plugin for protected routes
jest.mock('../../../../core/plugins/auth.plugin', () => {
return {
default: fastifyPlugin(async function (fastify) {
fastify.decorate('authenticate', async function (request, _reply) {
// JWT sub is still auth0|xxx format
request.user = { sub: 'auth0|test-user-123' };
});
}, { name: 'auth-plugin' }),
};
});
describe('Auth Integration Tests', () => {
let app: FastifyInstance;
beforeAll(async () => {
app = await buildApp();
await app.ready();
// Ensure user_profiles table exists (should be created by migrations)
// We don't need to run migration here as it should already exist
});
afterAll(async () => {
await app.close();
await pool.end();
});
beforeEach(async () => {
jest.clearAllMocks();
// Clean up test data before each test
await pool.query('DELETE FROM user_profiles WHERE auth0_sub = $1', [
'auth0|test-user-123',
]);
await pool.query('DELETE FROM user_profiles WHERE email = $1', [
'newuser@example.com',
]);
});
describe('POST /api/auth/signup', () => {
it('should create a new user successfully', async () => {
const email = 'newuser@example.com';
const password = 'Password123';
const auth0UserId = 'auth0|new-user-456';
mockAuth0Client.createUser.mockResolvedValue(auth0UserId);
const response = await request(app.server)
.post('/api/auth/signup')
.send({ email, password })
.expect(201);
expect(response.body).toMatchObject({
userId: auth0UserId,
email,
message: expect.stringContaining('check your email'),
});
expect(mockAuth0Client.createUser).toHaveBeenCalledWith({ email, password });
// Verify user was created in local database
const userResult = await pool.query(
'SELECT * FROM user_profiles WHERE auth0_sub = $1',
[auth0UserId]
);
expect(userResult.rows).toHaveLength(1);
expect(userResult.rows[0].email).toBe(email);
expect(userResult.rows[0].email_verified).toBe(false);
});
it('should reject signup with invalid email', async () => {
const response = await request(app.server)
.post('/api/auth/signup')
.send({ email: 'invalid-email', password: 'Password123' })
.expect(400);
expect(response.body.message).toContain('validation');
});
it('should reject signup with weak password', async () => {
const response = await request(app.server)
.post('/api/auth/signup')
.send({ email: 'test@example.com', password: 'weak' })
.expect(400);
expect(response.body.message).toContain('validation');
});
it('should reject signup when email already exists', async () => {
const email = 'existing@example.com';
const password = 'Password123';
mockAuth0Client.createUser.mockRejectedValue(
new Error('User already exists')
);
const response = await request(app.server)
.post('/api/auth/signup')
.send({ email, password })
.expect(409);
expect(response.body.error).toBe('Conflict');
expect(response.body.message).toContain('already exists');
});
});
describe('GET /api/auth/verify-status', () => {
beforeEach(async () => {
// Create a test user profile
await pool.query(
'INSERT INTO user_profiles (auth0_sub, email, email_verified) VALUES ($1, $2, $3)',
['auth0|test-user-123', 'test@example.com', false]
);
});
it('should return verification status', async () => {
const email = 'test@example.com';
mockAuth0Client.getUser.mockResolvedValue({
userId: 'auth0|test-user-123',
email,
emailVerified: false,
});
const response = await request(app.server)
.get('/api/auth/verify-status')
.expect(200);
expect(response.body).toMatchObject({
emailVerified: false,
email,
});
expect(mockAuth0Client.getUser).toHaveBeenCalledWith('auth0|test-user-123');
});
it('should update local database when verification status changes', async () => {
const email = 'test@example.com';
mockAuth0Client.getUser.mockResolvedValue({
userId: 'auth0|test-user-123',
email,
emailVerified: true,
});
const response = await request(app.server)
.get('/api/auth/verify-status')
.expect(200);
expect(response.body.emailVerified).toBe(true);
// Verify local database was updated
const userResult = await pool.query(
'SELECT email_verified FROM user_profiles WHERE auth0_sub = $1',
['auth0|test-user-123']
);
expect(userResult.rows[0].email_verified).toBe(true);
});
});
describe('POST /api/auth/resend-verification', () => {
beforeEach(async () => {
// Create a test user profile
await pool.query(
'INSERT INTO user_profiles (auth0_sub, email, email_verified) VALUES ($1, $2, $3)',
['auth0|test-user-123', 'test@example.com', false]
);
});
it('should resend verification email when user is not verified', async () => {
mockAuth0Client.checkEmailVerified.mockResolvedValue(false);
mockAuth0Client.resendVerificationEmail.mockResolvedValue(undefined);
const response = await request(app.server)
.post('/api/auth/resend-verification')
.expect(200);
expect(response.body.message).toContain('Verification email sent');
expect(mockAuth0Client.checkEmailVerified).toHaveBeenCalledWith(
'auth0|test-user-123'
);
expect(mockAuth0Client.resendVerificationEmail).toHaveBeenCalledWith(
'auth0|test-user-123'
);
});
it('should skip sending email when user is already verified', async () => {
mockAuth0Client.checkEmailVerified.mockResolvedValue(true);
const response = await request(app.server)
.post('/api/auth/resend-verification')
.expect(200);
expect(response.body.message).toContain('already verified');
expect(mockAuth0Client.resendVerificationEmail).not.toHaveBeenCalled();
});
});
});