diff --git a/app.mock.test.js b/app.mock.test.js index 79b9449..4b31a44 100644 --- a/app.mock.test.js +++ b/app.mock.test.js @@ -3,57 +3,72 @@ const request = require('supertest') const validateUsername = require('./validation/validateUsername') const validatePassword = require('./validation/validatePassword') -//Mock validateEmail to isolate tests -jest.mock('./validation/validateEmail', () => { - return jest.fn((email) => { - //Simulate real world simulation - if (!email || typeof email !== 'string') return false; - const re = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i; - return re.test(email); - }) -}) +jest.mock('./validation/validateEmail', () => jest.fn((email) => { + if (!email || typeof email !== 'string') { + return false + } + + const re = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i + + return re.test(email) +})) const validateEmail = require('./validation/validateEmail') const app = createApp(validateUsername, validatePassword, validateEmail) -describe('given correct username and password', () => { - test('return status 200', async () => { - const response = await request(app).post('/users').send({ - username: 'Username', - password: 'Password123', - email: 'student@example.com' +const validUser = { + username: 'Username', + password: 'Password123', + email: 'student@example.com' +} + +function registerUser(overrides = {}) { + return request(app) + .post('/users') + .send({ ...validUser, ...overrides }) +} + +describe('POST /users', () => { + describe('given valid user data', () => { + test('returns status 200', async () => { + const response = await registerUser() + + expect(response.statusCode).toBe(200) }) - expect(response.statusCode).toBe(200) - }) - test('returns userId', async () => { - const response = await request(app).post('/users').send({ - username: 'Username', - password: 'Password123', - email: 'student@example.com' + test('returns application json content type', async () => { + const response = await registerUser() + + expect(response.headers['content-type']).toContain('application/json') }) - expect(response.body.userId).toBeDefined(); - }) - // test response content type? - // test response message - // test response user id value - // ... -}) - -describe('given incorrect or missing username and password', () => { - test('return status 400', async () => { - const response = await request(app).post('/users').send({ - username: 'user', - password: 'password', - email: 'not-an-email' + test('returns the expected success payload', async () => { + const response = await registerUser() + + expect(response.body).toEqual({ userId: '1', message: 'Valid User' }) }) - expect(response.statusCode).toBe(400) }) - // test response message - // test that response does NOT have userId - // test incorrect username or password according to requirements - // test missing username or password - // ... + describe('given invalid user data', () => { + test.each([ + ['username is too short', { username: 'user' }], + ['username contains invalid characters', { username: 'User_name' }], + ['password is too short', { password: 'Pass12' }], + ['password is missing an uppercase letter', { password: 'password123' }], + ['password is missing a lowercase letter', { password: 'PASSWORD123' }], + ['password is missing a number', { password: 'Password' }], + ['password contains a special character', { password: 'Password123!' }], + ['email format is invalid', { email: 'not-an-email' }], + ['email is not a string', { email: { address: 'student@example.com' } }], + ['username is missing', { username: undefined }], + ['password is missing', { password: undefined }], + ['email is missing', { email: undefined }] + ])('returns status 400 when %s', async (_, overrides) => { + const response = await registerUser(overrides) + + expect(response.statusCode).toBe(400) + expect(response.body).toEqual({ error: 'Invalid User' }) + expect(response.body.userId).not.toBeDefined() + }) + }) }) \ No newline at end of file diff --git a/app.test.js b/app.test.js index f1b561d..efa7e48 100644 --- a/app.test.js +++ b/app.test.js @@ -6,44 +6,59 @@ const validateEmail = require('./validation/validateEmail') const app = createApp(validateUsername, validatePassword, validateEmail) -describe('given correct username and password', () => { - test('return status 200', async () => { - const response = await request(app).post('/users').send({ - username: 'Username', - password: 'Password123', - email: 'student@example.com' +const validUser = { + username: 'Username', + password: 'Password123', + email: 'student@example.com' +} + +function registerUser(overrides = {}) { + return request(app) + .post('/users') + .send({ ...validUser, ...overrides }) +} + +describe('POST /users', () => { + describe('given valid user data', () => { + test('returns status 200', async () => { + const response = await registerUser() + + expect(response.statusCode).toBe(200) }) - expect(response.statusCode).toBe(200) - }) - test('returns userId', async () => { - const response = await request(app).post('/users').send({ - username: 'Username', - password: 'Password123', - email: 'student@example.com' + test('returns application json content type', async () => { + const response = await registerUser() + + expect(response.headers['content-type']).toContain('application/json') }) - expect(response.body.userId).toBeDefined(); - }) - // test response content type? - // test response message - // test response user id value - // ... -}) - -describe('given incorrect or missing username and password', () => { - test('return status 400', async () => { - const response = await request(app).post('/users').send({ - username: 'user', - password: 'password', - email: 'not-an-email' + test('returns the expected success payload', async () => { + const response = await registerUser() + + expect(response.body).toEqual({ userId: '1', message: 'Valid User' }) }) - expect(response.statusCode).toBe(400) }) - // test response message - // test that response does NOT have userId - // test incorrect username or password according to requirements - // test missing username or password - // ... + describe('given invalid user data', () => { + test.each([ + ['username is too short', { username: 'user' }], + ['username contains invalid characters', { username: 'User_name' }], + ['password is too short', { password: 'Pass12' }], + ['password is missing an uppercase letter', { password: 'password123' }], + ['password is missing a lowercase letter', { password: 'PASSWORD123' }], + ['password is missing a number', { password: 'Password' }], + ['password contains a special character', { password: 'Password123!' }], + ['email format is invalid', { email: 'not-an-email' }], + ['email is not a string', { email: { address: 'student@example.com' } }], + ['username is missing', { username: undefined }], + ['password is missing', { password: undefined }], + ['email is missing', { email: undefined }] + ])('returns status 400 when %s', async (_, overrides) => { + const response = await registerUser(overrides) + + expect(response.statusCode).toBe(400) + expect(response.body).toEqual({ error: 'Invalid User' }) + expect(response.body.userId).not.toBeDefined() + }) + }) }) \ No newline at end of file diff --git a/validation/validatePassword.js b/validation/validatePassword.js index 44d8a8b..61438f7 100644 --- a/validation/validatePassword.js +++ b/validation/validatePassword.js @@ -1,4 +1,8 @@ function validatePassword(password) { + if (typeof password !== 'string') { + return false; + } + const validLength = password.length >= 8; const hasNumber = /[0-9]/g.test(password); const hasUpperCaseLetters = /[A-Z]/g.test(password); diff --git a/validation/validateUsername.js b/validation/validateUsername.js index 30213b1..ff6d5ee 100644 --- a/validation/validateUsername.js +++ b/validation/validateUsername.js @@ -1,4 +1,8 @@ function validateUsername(username) { + if (typeof username !== 'string') { + return false; + } + const validLength = username.length >= 6 && username.length <=30; const allowedcharacters = /^[a-zA-Z0-9.]+$/g.test(username);