diff --git a/server/routes/users.js b/server/routes/users.js index 369754c..a807754 100644 --- a/server/routes/users.js +++ b/server/routes/users.js @@ -64,6 +64,12 @@ router.post('/register', async (req, res) => { errors.push({ msg: 'Username can only contain letters, numbers, underscores, and hyphens' }); } + // Normalize and validate email format + let normalizedEmail = email ? email.trim().toLowerCase() : email; + if (normalizedEmail && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedEmail)) { + errors.push({ msg: 'Invalid email address' }); + } + // Validate custom glyph if (customGlyph && customGlyph.length > 2) { errors.push({ msg: 'Custom glyph must be at most 2 characters' }); diff --git a/tests/server/routes/index.test.js b/tests/server/routes/index.test.js index f8c613b..828e5d0 100644 --- a/tests/server/routes/index.test.js +++ b/tests/server/routes/index.test.js @@ -7,12 +7,16 @@ const express = require('express'); // Mock dependencies jest.mock('../../../server/models/User', () => ({ findRecent: jest.fn().mockResolvedValue([ - { username: 'testuser1', displayName: 'Test User 1' }, - { username: 'testuser2', displayName: 'Test User 2' } + { username: 'testuser1', displayName: 'Test User 1', lastActive: new Date() }, + { username: 'testuser2', displayName: 'Test User 2', lastActive: new Date() } + ]), + countDocuments: jest.fn().mockResolvedValue(2), + find: jest.fn().mockResolvedValue([ + { username: 'testuser1', lastActive: new Date() } ]) })); -jest.mock('../../../server/models/Item', () => ({ +jest.mock('../../../server/models/ScrapyardItem', () => ({ findRecent: jest.fn().mockResolvedValue([ { id: 1, title: 'Test Item 1' }, { id: 2, title: 'Test Item 2' } @@ -20,7 +24,8 @@ jest.mock('../../../server/models/Item', () => ({ findFeatured: jest.fn().mockResolvedValue([ { id: 3, title: 'Featured Item 1' }, { id: 4, title: 'Featured Item 2' } - ]) + ]), + countDocuments: jest.fn().mockResolvedValue(2) })); // Mock express-handlebars diff --git a/tests/server/routes/users.test.js b/tests/server/routes/users.test.js new file mode 100644 index 0000000..665c7c7 --- /dev/null +++ b/tests/server/routes/users.test.js @@ -0,0 +1,51 @@ +const request = require('supertest'); +const express = require('express'); + +// Mock User model methods used in the route +jest.mock('../../../server/models/User', () => ({ + findOne: jest.fn().mockResolvedValue(null), + create: jest.fn().mockResolvedValue({ id: 1 }) +})); + +// Create mock app +const app = express(); +app.use(express.urlencoded({ extended: false })); +app.use(express.json()); +app.set('view engine', 'handlebars'); +app.set('views', './server/views'); +app.use((req, res, next) => { + req.flash = jest.fn(); + next(); +}); +app.use((req, res, next) => { + res.render = jest.fn().mockImplementation((view, options) => { + res.status(200).send({ view, options }); + }); + next(); +}); + +const usersRouter = require('../../../server/routes/users'); +app.use('/users', usersRouter); + +describe('Users Routes', () => { + describe('POST /users/register', () => { + it('should return an error for invalid email', async () => { + const response = await request(app) + .post('/users/register') + .send({ + username: 'testuser', + email: 'invalid-email', + password: 'password', + password2: 'password' + }); + + expect(response.status).toBe(200); + expect(response.body.view).toBe('users/register'); + expect(response.body.options.errors).toEqual( + expect.arrayContaining([ + expect.objectContaining({ msg: 'Invalid email address' }) + ]) + ); + }); + }); +});