Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 74 additions & 3 deletions backend/__tests__/auth.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
process.env.NODE_ENV = 'test';
const request = require('supertest');
const mongoose = require('mongoose');
const { MongoMemoryServer } = require('mongodb-memory-server');
Expand All @@ -9,7 +10,11 @@ let mongoServer;
beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
const mongoUri = mongoServer.getUri();
process.env.MONGO_URI = mongoUri;
process.env.MONGO_URI = mongoUri;
await mongoose.connect(mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
});

afterAll(async () => {
Expand All @@ -19,7 +24,6 @@ afterAll(async () => {
});

describe('Auth API', () => {

beforeEach(async () => {
await User.deleteMany({});
});
Expand All @@ -36,7 +40,7 @@ describe('Auth API', () => {

expect(response.statusCode).toBe(201);
expect(response.body).toHaveProperty('token');

const savedUser = await User.findOne({ email: 'testuser@gmail.com' });
expect(savedUser).not.toBeNull();
expect(savedUser.defaultCurrency).toBe('USD');
Expand Down Expand Up @@ -101,4 +105,71 @@ describe('Auth API', () => {
expect(setupResponse.body.message).toBe('Default currency is required');
});

it('should allow a new user to sign up', async () => {
const newUser = {
email: 'testuser@gmail.com',
password: 'Password123!',
};

const response = await request(app).post('/api/auth/signup').send(newUser);

expect(response.statusCode).toBe(201);
expect(response.body).toHaveProperty('token');

const savedUser = await User.findOne({ email: 'testuser@gmail.com' });
expect(savedUser).not.toBeNull();
});

it('should reject signup with an existing email', async () => {
const testUser = {
email: 'duplicate@gmail.com',
password: 'Password123!',
};

await request(app).post('/api/auth/signup').send(testUser).expect(201);

const response = await request(app)
.post('/api/auth/signup')
.send(testUser)
.expect(400);

expect(response.body.message).toBe('User already exists');

const users = await User.find({ email: testUser.email });
expect(users.length).toBe(1);
});

it('should reject signup when email is missing', async () => {
const missingEmailUser = {
email: "",
password: 'Password123!',
};

const response = await request(app)
.post('/api/auth/signup')
.send(missingEmailUser)
.expect(400);

expect(response.body.message).toBe('Please enter all fields');

const users = await User.find({});
expect(users.length).toBe(0);
});

it('should reject signup when password is missing', async () => {
const missingPasswordUser = {
email: 'user@example.com',
password: "",
};

const response = await request(app)
.post('/api/auth/signup')
.send(missingPasswordUser)
.expect(400);

expect(response.body.message).toBe('Please enter all fields');

const users = await User.find({});
expect(users.length).toBe(0);
});
});
6 changes: 4 additions & 2 deletions backend/config/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ const connectDB = async () => {
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
if (process.env.NODE_ENV !== "test") {
process.exit(1);
}
}
};

module.exports = connectDB;
module.exports = connectDB;
20 changes: 16 additions & 4 deletions backend/middleware/validationMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ const { body, validationResult } = require('express-validator');
const dns = require('dns');

const validateRegistration = [
(req, res, next) => {
if (!req.body.email || !req.body.password) {
return res.status(400).json({ message: "Please enter all fields" });
}
next();
},
// Validate email
body('email')
.isEmail()
.withMessage('Please enter a valid email address.')
.bail() // Stop running validators if the previous one failed
.custom(async (email) => {
const domain = email.split('@')[1];
const domain = email.split("@")[1];

// Quick blacklist for common invalid domains
const blockedDomains = ['example.com', 'test.com', 'invalid.com'];
Expand All @@ -20,11 +26,15 @@ const validateRegistration = [
try {
const addresses = await dns.promises.resolveMx(domain);
if (!addresses || addresses.length === 0) {
return Promise.reject('Email domain does not exist or cannot receive mail.');
return Promise.reject(
'Email domain does not exist or cannot receive mail.'
);
}
} catch (error) {
// If DNS resolution fails
return Promise.reject('Email domain does not exist or cannot receive mail.');
return Promise.reject(
'Email domain does not exist or cannot receive mail.'
);
}
}),

Expand All @@ -33,7 +43,9 @@ const validateRegistration = [
.isLength({ min: 8, max: 16 })
.withMessage('Password must be between 8 and 16 characters long.')
.matches(/^(?=.*\d)(?=.*[a-zA-Z])(?=.*[\W_])/)
.withMessage('Password must contain at least one alphabet, one digit, and one symbol.'),
.withMessage(
'Password must contain at least one alphabet, one digit, and one symbol.'
),

// Middleware to handle the validation result
(req, res, next) => {
Expand Down
15 changes: 0 additions & 15 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 17 additions & 13 deletions backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ const allowedOrigins = [
"https://paisable.netlify.app",
];

app.use(cors({
origin: function(origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true
}));
app.use(
cors({
origin: function (origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
})
);
app.use(express.json());

// sanitizeMiddleware
Expand All @@ -55,9 +57,11 @@ app.get('/', (req, res) => {

const PORT = process.env.PORT || 5000;

const server = app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
const server = app.listen(PORT, () =>
console.log(`Server started on port ${PORT}`)
);

cron.schedule("*/10 * * * *", async() => {
cron.schedule("*/10 * * * *", async () => {
const keepAliveUrl = process.env.KEEP_ALIVE_URL;
if (!keepAliveUrl) {
console.error(
Expand All @@ -74,4 +78,4 @@ cron.schedule("*/10 * * * *", async() => {
}
});

module.exports = { app, server };
module.exports = { app, server };
Loading