Skip to content
Closed
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
156 changes: 97 additions & 59 deletions app.mock.test.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,97 @@
const createApp = require('./app')
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);
})
})

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'
})
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'
})
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'
})
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
// ...
})
const createApp = require('./app')
const request = require('supertest')
const validateUsername = require('./validation/validateUsername')
const validatePassword = require('./validation/validatePassword')

jest.mock('./validation/validateEmail', () => {
return 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('POST /users', () => {
test('returns 200 and the expected payload for a valid user', async () => {
const response = await request(app).post('/users').send({
username: 'User.name123',
password: 'Password123',
email: 'student@example.com'
})

expect(response.statusCode).toBe(200)
expect(response.headers['content-type']).toMatch(/json/)
expect(response.body).toEqual({
userId: '1',
message: 'Valid User'
})
})

test('accepts boundary values that still satisfy the requirements', async () => {
const response = await request(app).post('/users').send({
username: 'User.1',
password: 'Abcdefg1',
email: 'name@mail.example.org'
})

expect(response.statusCode).toBe(200)
expect(response.body.message).toBe('Valid User')
})

test.each([
['username is shorter than 6 characters', {
username: 'user1',
password: 'Password123',
email: 'student@example.com'
}],
['username contains invalid characters', {
username: 'user!name',
password: 'Password123',
email: 'student@example.com'
}],
['password is shorter than 8 characters', {
username: 'Username',
password: 'Pass12A',
email: 'student@example.com'
}],
['password is missing an uppercase letter', {
username: 'Username',
password: 'password123',
email: 'student@example.com'
}],
['password is missing a number', {
username: 'Username',
password: 'Password',
email: 'student@example.com'
}],
['password contains special characters', {
username: 'Username',
password: 'Password123!',
email: 'student@example.com'
}],
['email is missing the @ symbol', {
username: 'Username',
password: 'Password123',
email: 'studentexample.com'
}],
['email is missing a valid domain extension', {
username: 'Username',
password: 'Password123',
email: 'student@example'
}],
['username is missing entirely', {
password: 'Password123',
email: 'student@example.com'
}]
])('returns 400 when %s', async (_description, payload) => {
const response = await request(app).post('/users').send(payload)

expect(response.statusCode).toBe(400)
expect(response.headers['content-type']).toMatch(/json/)
expect(response.body).toEqual({ error: 'Invalid User' })
expect(response.body.userId).toBeUndefined()
})
})
130 changes: 85 additions & 45 deletions app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,88 @@ const createApp = require('./app')
const request = require('supertest')
const validateUsername = require('./validation/validateUsername')
const validatePassword = require('./validation/validatePassword')
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'
})
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'
})
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'
})
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
// ...
})
const validateEmail = require('./validation/validateEmail')

const app = createApp(validateUsername, validatePassword, validateEmail)

describe('POST /users', () => {
test('returns 200 and the expected payload for a valid user', async () => {
const response = await request(app).post('/users').send({
username: 'User.name123',
password: 'Password123',
email: 'student@example.com'
})

expect(response.statusCode).toBe(200)
expect(response.headers['content-type']).toMatch(/json/)
expect(response.body).toEqual({
userId: '1',
message: 'Valid User'
})
})

test('accepts boundary values that still satisfy the requirements', async () => {
const response = await request(app).post('/users').send({
username: 'User.1',
password: 'Abcdefg1',
email: 'name@mail.example.org'
})

expect(response.statusCode).toBe(200)
expect(response.body.message).toBe('Valid User')
})

test.each([
['username is shorter than 6 characters', {
username: 'user1',
password: 'Password123',
email: 'student@example.com'
}],
['username contains invalid characters', {
username: 'user!name',
password: 'Password123',
email: 'student@example.com'
}],
['password is shorter than 8 characters', {
username: 'Username',
password: 'Pass12A',
email: 'student@example.com'
}],
['password is missing an uppercase letter', {
username: 'Username',
password: 'password123',
email: 'student@example.com'
}],
['password is missing a number', {
username: 'Username',
password: 'Password',
email: 'student@example.com'
}],
['password contains special characters', {
username: 'Username',
password: 'Password123!',
email: 'student@example.com'
}],
['email is missing the @ symbol', {
username: 'Username',
password: 'Password123',
email: 'studentexample.com'
}],
['email is missing a valid domain extension', {
username: 'Username',
password: 'Password123',
email: 'student@example'
}],
['username is missing entirely', {
password: 'Password123',
email: 'student@example.com'
}]
])('returns 400 when %s', async (_description, payload) => {
const response = await request(app).post('/users').send(payload)

expect(response.statusCode).toBe(400)
expect(response.headers['content-type']).toMatch(/json/)
expect(response.body).toEqual({ error: 'Invalid User' })
expect(response.body.userId).toBeUndefined()
})
})
12 changes: 8 additions & 4 deletions validation/validatePassword.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
function validatePassword(password) {
const validLength = password.length >= 8;
const hasNumber = /[0-9]/g.test(password);
const hasUpperCaseLetters = /[A-Z]/g.test(password);
function validatePassword(password) {
if (!password || typeof password !== 'string') {
return false;
}

const validLength = password.length >= 8;
const hasNumber = /[0-9]/g.test(password);
const hasUpperCaseLetters = /[A-Z]/g.test(password);
const hasLowerCaseLetters = /[a-z]/g.test(password);
const hasSpecialCharacters = /[\W]/g.test(password);

Expand Down
16 changes: 10 additions & 6 deletions validation/validateUsername.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
function validateUsername(username) {
const validLength = username.length >= 6 && username.length <=30;
const allowedcharacters = /^[a-zA-Z0-9.]+$/g.test(username);

return validLength && allowedcharacters;
}
function validateUsername(username) {
if (!username || typeof username !== 'string') {
return false;
}

const validLength = username.length >= 6 && username.length <=30;
const allowedcharacters = /^[a-zA-Z0-9.]+$/g.test(username);

return validLength && allowedcharacters;
}
module.exports = validateUsername;
Loading