Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add integration tests for /billing endpoint #514

Merged
merged 4 commits into from
Oct 29, 2020
Merged
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
272 changes: 272 additions & 0 deletions src/app/modules/billing/__tests__/billing.routes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
import { flatten, sortBy, times } from 'lodash'
import mongoose from 'mongoose'
import { errAsync } from 'neverthrow'
import supertest, { Session } from 'supertest-session'

import getFormModel from 'src/app/models/form.server.model'
import getLoginModel from 'src/app/models/login.server.model'
import { AuthType, IUserSchema, ResponseMode } from 'src/types'

import { createAuthedSession } from 'tests/integration/helpers/express-auth'
import { setupApp } from 'tests/integration/helpers/express-setup'
import { buildCelebrateError } from 'tests/unit/backend/helpers/celebrate'
import dbHandler from 'tests/unit/backend/helpers/jest-db'

import { DatabaseError } from '../../core/core.errors'
import { BillingFactory } from '../billing.factory'
import { BillingRouter } from '../billing.routes'

const app = setupApp('/billing', BillingRouter, {
setupWithAuth: true,
})

const FormModel = getFormModel(mongoose)
const LoginModel = getLoginModel(mongoose)

describe('billing.routes', () => {
let request: Session
let defaultUser: IUserSchema

beforeAll(async () => await dbHandler.connect())
beforeEach(async () => {
request = supertest(app)
const { user } = await dbHandler.insertFormCollectionReqs()
defaultUser = user
})
afterEach(async () => {
await dbHandler.clearDatabase()
jest.restoreAllMocks()
})
afterAll(async () => await dbHandler.closeDatabase())

describe('GET /billing', () => {
const VALID_ESRVCID_1 = 'mockEsrvcId1'
const VALID_ESRVCID_2 = 'mockEsrvcId2'
const INVALID_ESRVCID = 'invalidEsrvcId'
const VALID_QUERY_YR = new Date().getFullYear()
const VALID_QUERY_MTH = new Date().getMonth()

it('should return 200 with array of results of form SPCP logins of the given esrvcId', async () => {
// Arrange
// Log in user.
const session = await createAuthedSession(defaultUser.email, request)
// Generate login statistics.
const {
generatedLoginTimes,
generatedForms,
} = await generateLoginStatistics({
user: defaultUser,
esrvcIdToCheck: VALID_ESRVCID_1,
altEsrvcId: VALID_ESRVCID_2,
})

// Act
const response = await session.get('/billing').query({
esrvcId: VALID_ESRVCID_1,
yr: VALID_QUERY_YR,
mth: VALID_QUERY_MTH,
})

// Assert
// Only first two forms returned, as those have logins with
// VALID_ESRVCID_1.
// Should not contain third form with VALID_ESRVCID_2.
const expectedStats = [
{
adminEmail: defaultUser.email,
formName: generatedForms[0].title,
total: generatedLoginTimes[0],
formId: String(generatedForms[0]._id),
authType: AuthType.SP,
},
{
adminEmail: defaultUser.email,
formName: generatedForms[1].title,
total: generatedLoginTimes[1],
formId: String(generatedForms[1]._id),
authType: AuthType.SP,
},
]
expect(response.status).toEqual(200)
// Check shape.
expect(response.body).toEqual({
loginStats: expect.any(Array),
})
// Sort by total and compare.
expect(sortBy(response.body.loginStats, ['total'])).toEqual(
sortBy(expectedStats, ['total']),
)
})

it('should return 200 with empty array when no esrvcId matches logins', async () => {
// Arrange
// Log in user.
const session = await createAuthedSession(defaultUser.email, request)

// Act
const response = await session.get('/billing').query({
esrvcId: INVALID_ESRVCID,
yr: VALID_QUERY_YR,
mth: VALID_QUERY_MTH,
})

// Assert
expect(response.status).toEqual(200)
expect(response.body).toEqual({ loginStats: [] })
})

it('should return 400 when query.esrvcId is not provided', async () => {
// Arrange
// Log in user.
const session = await createAuthedSession(defaultUser.email, request)

// Act
const response = await session.get('/billing').query({
// No esrvcId provided.
yr: VALID_QUERY_YR,
mth: VALID_QUERY_MTH,
})

// Assert
expect(response.status).toEqual(400)
expect(response.body).toEqual(
buildCelebrateError({ query: { key: 'esrvcId' } }),
)
})

it('should return 400 when query.yr is not provided', async () => {
// Arrange
// Log in user.
const session = await createAuthedSession(defaultUser.email, request)

// Act
const response = await session.get('/billing').query({
esrvcId: VALID_ESRVCID_1,
// No yr provided.
mth: VALID_QUERY_MTH,
})

// Assert
expect(response.status).toEqual(400)
expect(response.body).toEqual(
buildCelebrateError({ query: { key: 'yr' } }),
)
})

it('should return 400 when query.mth is not provided', async () => {
// Arrange
// Log in user.
const session = await createAuthedSession(defaultUser.email, request)

// Act
const response = await session.get('/billing').query({
esrvcId: VALID_ESRVCID_1,
yr: VALID_QUERY_YR,
// No mth provided.
})

// Assert
expect(response.status).toEqual(400)
expect(response.body).toEqual(
buildCelebrateError({ query: { key: 'mth' } }),
)
})

it('should return 401 when user session does not exist', async () => {
// Act
// Call endpoint directly without first logging in.
const response = await request.get('/billing').query({
esrvcId: VALID_ESRVCID_1,
yr: VALID_QUERY_YR,
mth: VALID_QUERY_MTH,
})

// Assert
expect(response.status).toEqual(401)
expect(response.body).toEqual('User is unauthorized.')
})

it('should return 500 when error occurs whilst querying the database', async () => {
// Arrange
// Log in user.
const session = await createAuthedSession(defaultUser.email, request)

// Mock database error from service call.
const retrieveStatsSpy = jest
.spyOn(BillingFactory, 'getSpLoginStats')
.mockReturnValueOnce(errAsync(new DatabaseError()))

// Act
const response = await session.get('/billing').query({
esrvcId: VALID_ESRVCID_1,
yr: VALID_QUERY_YR,
mth: VALID_QUERY_MTH,
})

// Assert
expect(retrieveStatsSpy).toBeCalled()
expect(response.status).toEqual(500)
expect(response.body).toEqual('Error in retrieving billing records')
})
})
})

/**
* Helper method to generate login statistics for testing.
*/
const generateLoginStatistics = async ({
user,
esrvcIdToCheck,
altEsrvcId,
}: {
user: IUserSchema
esrvcIdToCheck: string
altEsrvcId: string
}) => {
// Generate login statistics.
// Create 3 random forms.
const formPromises = times(3, (idx) =>
FormModel.create({
title: `example form title ${idx}`,
admin: user._id,
responseMode: ResponseMode.Email,
emails: [user.email],
}),
)
const forms = await Promise.all(formPromises)

// Login to first two forms a set number of times with the same esrvcId.
const esrvc1LoginTimes = [4, 2]
const loginPromises = flatten(
forms.map((form, idx) =>
times(esrvc1LoginTimes[idx], () =>
LoginModel.create({
form: form._id,
admin: user._id,
agency: user.agency,
authType: AuthType.SP,
esrvcId: esrvcIdToCheck,
}),
),
),
)
// Login to third form with a different esrvcId.
loginPromises.push(
...times(5, () =>
LoginModel.create({
form: forms[2]._id,
admin: user._id,
agency: user.agency,
authType: AuthType.SP,
esrvcId: altEsrvcId,
}),
),
)

await Promise.all(loginPromises)

return {
generatedLoginTimes: esrvc1LoginTimes,
generatedForms: forms,
}
}