fixed integration tests
This commit is contained in:
@@ -1,13 +1,30 @@
|
||||
// Integration test setup
|
||||
// Integration tests use a real database, so we don't mock DATABASE_URL
|
||||
|
||||
process.env.NODE_ENV = 'test';
|
||||
const path = require("path");
|
||||
require("dotenv").config({ path: path.join(__dirname, "..", ".env.test") });
|
||||
|
||||
// Ensure JWT secrets are set for integration tests
|
||||
process.env.JWT_ACCESS_SECRET = process.env.JWT_ACCESS_SECRET || 'test-access-secret';
|
||||
process.env.JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'test-refresh-secret';
|
||||
process.env.JWT_SECRET = process.env.JWT_SECRET || 'test-secret';
|
||||
process.env.NODE_ENV = "test";
|
||||
|
||||
// Set other required env vars if not already set
|
||||
process.env.GOOGLE_MAPS_API_KEY = process.env.GOOGLE_MAPS_API_KEY || 'test-key';
|
||||
process.env.STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY || 'sk_test_key';
|
||||
// Required environment variables - fail fast if missing
|
||||
const requiredEnvVars = [
|
||||
"JWT_ACCESS_SECRET",
|
||||
"JWT_REFRESH_SECRET",
|
||||
"CSRF_SECRET",
|
||||
"TOTP_ENCRYPTION_KEY",
|
||||
];
|
||||
|
||||
const missingVars = requiredEnvVars.filter((v) => !process.env[v]);
|
||||
if (missingVars.length > 0) {
|
||||
throw new Error(
|
||||
`Missing required environment variables for integration tests: ${missingVars.join(", ")}\n` +
|
||||
`Please ensure these are set in your .env.test file.`,
|
||||
);
|
||||
}
|
||||
|
||||
// Optional variables with safe defaults
|
||||
process.env.JWT_SECRET =
|
||||
process.env.JWT_SECRET || process.env.JWT_ACCESS_SECRET;
|
||||
process.env.EMAIL_ENABLED = "false";
|
||||
process.env.FRONTEND_URL = process.env.FRONTEND_URL || "http://localhost:3000";
|
||||
process.env.GOOGLE_MAPS_API_KEY = process.env.GOOGLE_MAPS_API_KEY || "test-key";
|
||||
process.env.STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY || "sk_test_key";
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
* and password reset functionality.
|
||||
*/
|
||||
|
||||
// Mock email services before importing routes
|
||||
jest.mock('../../services/email', () => ({
|
||||
auth: {
|
||||
sendVerificationEmail: jest.fn().mockResolvedValue({ success: true }),
|
||||
sendPasswordResetEmail: jest.fn().mockResolvedValue({ success: true }),
|
||||
sendPasswordChangedEmail: jest.fn().mockResolvedValue({ success: true }),
|
||||
},
|
||||
initialize: jest.fn().mockResolvedValue(),
|
||||
initialized: true,
|
||||
}));
|
||||
|
||||
const request = require('supertest');
|
||||
const express = require('express');
|
||||
const cookieParser = require('cookie-parser');
|
||||
@@ -32,6 +43,63 @@ jest.mock('../../middleware/csrf', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock sanitizeInput to avoid req.query setter issue in supertest
|
||||
// Keep the actual validation rules but skip DOMPurify sanitization
|
||||
jest.mock('../../middleware/validation', () => {
|
||||
const { body, validationResult } = require('express-validator');
|
||||
|
||||
// Validation error handler
|
||||
const handleValidationErrors = (req, res, next) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
error: 'Validation failed',
|
||||
details: errors.array().map((err) => ({
|
||||
field: err.path,
|
||||
message: err.msg,
|
||||
})),
|
||||
});
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
// Password strength validation
|
||||
const passwordStrengthRegex = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z])(?=.*[-@$!%*?&#^]).{8,}$/;
|
||||
|
||||
return {
|
||||
sanitizeInput: (req, res, next) => next(), // Skip sanitization in tests
|
||||
validateRegistration: [
|
||||
body('email').isEmail().normalizeEmail().withMessage('Please provide a valid email address'),
|
||||
body('password').isLength({ min: 8, max: 128 }).matches(passwordStrengthRegex).withMessage('Password does not meet requirements'),
|
||||
body('firstName').trim().isLength({ min: 1, max: 50 }).withMessage('First name is required'),
|
||||
body('lastName').trim().isLength({ min: 1, max: 50 }).withMessage('Last name is required'),
|
||||
handleValidationErrors,
|
||||
],
|
||||
validateLogin: [
|
||||
body('email').isEmail().normalizeEmail().withMessage('Please provide a valid email address'),
|
||||
body('password').notEmpty().withMessage('Password is required'),
|
||||
handleValidationErrors,
|
||||
],
|
||||
validateGoogleAuth: [
|
||||
body('code').notEmpty().withMessage('Authorization code is required'),
|
||||
handleValidationErrors,
|
||||
],
|
||||
validateForgotPassword: [
|
||||
body('email').isEmail().normalizeEmail().withMessage('Please provide a valid email address'),
|
||||
handleValidationErrors,
|
||||
],
|
||||
validateResetPassword: [
|
||||
body('token').notEmpty().withMessage('Token is required').isLength({ min: 64, max: 64 }).withMessage('Invalid token format'),
|
||||
body('newPassword').isLength({ min: 8, max: 128 }).matches(passwordStrengthRegex).withMessage('Password does not meet requirements'),
|
||||
handleValidationErrors,
|
||||
],
|
||||
validateVerifyResetToken: [
|
||||
body('token').notEmpty().withMessage('Token is required'),
|
||||
handleValidationErrors,
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const { sequelize, User, AlphaInvitation } = require('../../models');
|
||||
const authRoutes = require('../../routes/auth');
|
||||
|
||||
@@ -48,6 +116,14 @@ const createTestApp = () => {
|
||||
});
|
||||
|
||||
app.use('/auth', authRoutes);
|
||||
|
||||
// Error handler for tests
|
||||
app.use((err, req, res, next) => {
|
||||
res.status(err.status || 500).json({
|
||||
error: err.message || 'Internal Server Error',
|
||||
});
|
||||
});
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
@@ -98,9 +174,9 @@ describe('Auth Integration Tests', () => {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// Clean up users before each test
|
||||
await User.destroy({ where: {}, truncate: true, cascade: true });
|
||||
await AlphaInvitation.destroy({ where: {}, truncate: true, cascade: true });
|
||||
// Use destroy without truncate for safer cleanup with foreign keys
|
||||
await User.destroy({ where: {}, force: true });
|
||||
await AlphaInvitation.destroy({ where: {}, force: true });
|
||||
});
|
||||
|
||||
describe('POST /auth/register', () => {
|
||||
|
||||
Reference in New Issue
Block a user