Ocelot-Social/backend/src/schema/resolvers/user_management.spec.js
2019-11-16 20:09:05 +01:00

319 lines
8.6 KiB
JavaScript

import jwt from 'jsonwebtoken'
import CONFIG from './../../config'
import Factory from '../../seed/factories'
import { gql } from '../../helpers/jest'
import { createTestClient } from 'apollo-server-testing'
import createServer, { context } from '../../server'
import encode from '../../jwt/encode'
const factory = Factory()
let query
let mutate
let variables
let req
let user
const disable = async id => {
await factory.create('User', { id: 'u2', role: 'moderator' })
const moderatorBearerToken = encode({ id: 'u2' })
req = { headers: { authorization: `Bearer ${moderatorBearerToken}` } }
await mutate({
mutation: gql`
mutation($id: ID!) {
disable(id: $id)
}
`,
variables: { id },
})
req = { headers: {} }
}
beforeEach(() => {
user = null
req = { headers: {} }
})
beforeAll(() => {
const { server } = createServer({
context: () => {
// One of the rare occasions where we test
// the actual `context` implementation here
return context({ req })
},
})
query = createTestClient(server).query
mutate = createTestClient(server).mutate
})
afterEach(async () => {
await factory.cleanDatabase()
})
describe('isLoggedIn', () => {
const isLoggedInQuery = gql`
{
isLoggedIn
}
`
const respondsWith = async expected => {
await expect(query({ query: isLoggedInQuery })).resolves.toMatchObject(expected)
}
describe('unauthenticated', () => {
it('returns false', async () => {
await respondsWith({ data: { isLoggedIn: false } })
})
})
describe('authenticated', () => {
beforeEach(async () => {
user = await factory.create('User', { id: 'u3' })
const userBearerToken = encode({ id: 'u3' })
req = { headers: { authorization: `Bearer ${userBearerToken}` } }
})
it('returns true', async () => {
await respondsWith({ data: { isLoggedIn: true } })
})
describe('but user is disabled', () => {
beforeEach(async () => {
await disable('u3')
})
it('returns false', async () => {
await respondsWith({ data: { isLoggedIn: false } })
})
})
describe('but user is deleted', () => {
beforeEach(async () => {
await user.update({ updatedAt: new Date().toISOString(), deleted: true })
})
it('returns false', async () => {
await respondsWith({ data: { isLoggedIn: false } })
})
})
})
})
describe('currentUser', () => {
const currentUserQuery = gql`
{
currentUser {
id
slug
name
avatar
email
role
}
}
`
const respondsWith = async expected => {
await expect(query({ query: currentUserQuery, variables })).resolves.toMatchObject(expected)
}
describe('unauthenticated', () => {
it('returns null', async () => {
await respondsWith({ data: { currentUser: null } })
})
})
describe('authenticated', () => {
describe('and corresponding user in the database', () => {
beforeEach(async () => {
await factory.create('User', {
id: 'u3',
// the `id` is the only thing that has to match the decoded JWT bearer token
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
email: 'test@example.org',
name: 'Matilde Hermiston',
slug: 'matilde-hermiston',
role: 'user',
})
const userBearerToken = encode({ id: 'u3' })
req = { headers: { authorization: `Bearer ${userBearerToken}` } }
})
it('returns the whole user object', async () => {
const expected = {
data: {
currentUser: {
id: 'u3',
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg',
email: 'test@example.org',
name: 'Matilde Hermiston',
slug: 'matilde-hermiston',
role: 'user',
},
},
}
await respondsWith(expected)
})
})
})
})
describe('login', () => {
const loginMutation = gql`
mutation($email: String!, $password: String!) {
login(email: $email, password: $password)
}
`
const respondsWith = async expected => {
await expect(mutate({ mutation: loginMutation, variables })).resolves.toMatchObject(expected)
}
beforeEach(async () => {
variables = { email: 'test@example.org', password: '1234' }
user = await factory.create('User', {
...variables,
id: 'acb2d923-f3af-479e-9f00-61b12e864666',
})
})
describe('ask for a `token`', () => {
describe('with a valid email/password combination', () => {
it('responds with a JWT bearer token', async done => {
const {
data: { login: token },
} = await mutate({ mutation: loginMutation, variables })
jwt.verify(token, CONFIG.JWT_SECRET, (err, data) => {
expect(data.email).toEqual('test@example.org')
expect(err).toBeNull()
done()
})
})
describe('but user account is deleted', () => {
beforeEach(async () => {
await user.update({ updatedAt: new Date().toISOString(), deleted: true })
})
it('responds with "Incorrect email address or password."', async () => {
await respondsWith({
data: null,
errors: [{ message: 'Incorrect email address or password.' }],
})
})
})
describe('but user account is disabled', () => {
beforeEach(async () => {
await disable('acb2d923-f3af-479e-9f00-61b12e864666')
})
it('responds with "Your account has been disabled."', async () => {
await respondsWith({
data: null,
errors: [{ message: 'Your account has been disabled.' }],
})
})
})
})
describe('with a valid email but incorrect password', () => {
beforeEach(() => {
variables = { ...variables, email: 'test@example.org', password: 'wrong' }
})
it('responds with "Incorrect email address or password."', async () => {
await respondsWith({
errors: [{ message: 'Incorrect email address or password.' }],
})
})
})
describe('with a non-existing email', () => {
beforeEach(() => {
variables = {
...variables,
email: 'non-existent@example.org',
password: '1234',
}
})
it('responds with "Incorrect email address or password."', async () => {
await respondsWith({
errors: [{ message: 'Incorrect email address or password.' }],
})
})
})
})
})
describe('change password', () => {
const changePasswordMutation = gql`
mutation($oldPassword: String!, $newPassword: String!) {
changePassword(oldPassword: $oldPassword, newPassword: $newPassword)
}
`
const respondsWith = async expected => {
await expect(mutate({ mutation: changePasswordMutation, variables })).resolves.toMatchObject(
expected,
)
}
beforeEach(async () => {
variables = { ...variables, oldPassword: 'what', newPassword: 'ever' }
})
describe('unauthenticated', () => {
it('throws "Not Authorised!"', async () => {
await respondsWith({ errors: [{ message: 'Not Authorised!' }] })
})
})
describe('authenticated', () => {
beforeEach(async () => {
await factory.create('User', { id: 'u3' })
const userBearerToken = encode({ id: 'u3' })
req = { headers: { authorization: `Bearer ${userBearerToken}` } }
})
describe('old password === new password', () => {
beforeEach(() => {
variables = { ...variables, oldPassword: '1234', newPassword: '1234' }
})
it('responds with "Old password and new password should be different"', async () => {
await respondsWith({
errors: [{ message: 'Old password and new password should be different' }],
})
})
})
describe('incorrect old password', () => {
beforeEach(() => {
variables = {
...variables,
oldPassword: 'notOldPassword',
newPassword: '12345',
}
})
it('responds with "Old password isn\'t valid"', async () => {
await respondsWith({ errors: [{ message: 'Old password is not correct' }] })
})
})
describe('correct password', () => {
beforeEach(() => {
variables = {
...variables,
oldPassword: '1234',
newPassword: '12345',
}
})
it('changes the password if given correct credentials "', async () => {
await respondsWith({ data: { changePassword: expect.any(String) } })
})
})
})
})