Skip to content

Commit

Permalink
feat: #1222 create infra for appointment planner api
Browse files Browse the repository at this point in the history
  • Loading branch information
trankhacvy committed May 26, 2020
1 parent 22020d3 commit b668c42
Show file tree
Hide file tree
Showing 10 changed files with 504 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/web-components/scripts/build-serverless.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ const { spawn } = require('child_process')
const stage = yargs.argv.stage

// relative to the root of web-components package
const listServerlessYmlFiles = ['src/search-widget/server/serverless.yml']
const listServerlessYmlFiles = [
'src/search-widget/server/serverless.yml',
'src/appointment-planner/server/serverless.yml',
]

const buildServerlessList = () => {
listServerlessYmlFiles.forEach(file => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import { PagedResultAppointmentModel_ } from '@reapit/foundations-ts-definitions'

export const appointmentsDataStub: PagedResultAppointmentModel_ = {
_embedded: [
{
id: 'NEP1600290',
created: '2019-05-08T17:07:39',
modified: '2019-05-09T09:18:06',
start: '2019-05-11T17:30:00',
end: '2019-05-11T18:00:00',
typeId: 'VW',
recurring: false,
cancelled: true,
organiserId: 'BED160186',
},
{
id: 'BED1600537',
created: '2019-05-08T17:00:15',
modified: '2016-12-14T17:25:22',
start: '2019-10-10T22:45:00',
end: '2019-05-09T14:00:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BUC1600211',
created: '2019-05-08T16:56:37',
modified: '2019-05-12T08:19:24',
start: '2019-05-09T14:15:00',
end: '2019-05-09T14:45:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BUC1600210',
created: '2019-05-08T16:44:46',
modified: '2019-05-11T14:45:40',
start: '2019-05-09T13:30:00',
end: '2019-05-09T14:15:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'STS1600403',
created: '2019-05-08T16:18:09',
modified: '2019-05-11T10:05:34',
start: '2019-05-09T11:15:00',
end: '2019-05-09T11:45:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'STS1600401',
created: '2019-05-08T15:39:57',
modified: '2019-05-12T16:39:53',
start: '2019-05-10T15:15:00',
end: '2019-05-10T16:00:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'NEP1600288',
created: '2019-05-08T14:56:47',
modified: '2019-05-08T19:11:22',
start: '2019-05-09T16:30:00',
end: '2019-05-09T17:00:00',
typeId: 'VW',
recurring: false,
cancelled: true,
organiserId: 'BED160186',
},
{
id: 'STS1600396',
created: '2019-05-08T14:46:37',
modified: '2019-05-12T12:32:01',
start: '2019-05-08T18:00:00',
end: '2019-05-08T18:30:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'NEP1600287',
created: '2019-05-08T14:39:24',
modified: '2019-05-12T13:23:36',
start: '2019-05-12T17:30:00',
end: '2019-05-12T18:00:00',
typeId: 'VW',
recurring: false,
cancelled: true,
organiserId: 'BED160186',
},
{
id: 'BED1600534',
created: '2019-05-08T14:31:27',
modified: '2016-12-18T08:24:24',
start: '2019-05-09T15:15:00',
end: '2019-05-09T16:15:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'STS1600394',
created: '2019-05-08T14:31:25',
modified: '2019-05-12T16:18:48',
start: '2019-05-10T14:00:00',
end: '2019-05-10T14:30:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BED1600532',
created: '2019-05-08T14:05:42',
modified: '2019-05-12T17:59:02',
start: '2019-05-11T15:30:00',
end: '2019-05-11T16:30:00',
typeId: 'VL',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'MKC1600312',
created: '2019-05-08T13:33:25',
modified: '2019-05-08T13:33:25',
start: '2019-05-09T16:30:00',
end: '2019-05-09T17:00:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BED1600530',
created: '2019-05-08T13:18:59',
modified: '2019-05-12T08:33:02',
start: '2019-05-11T15:00:00',
end: '2019-05-11T17:00:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BUC1600209',
created: '2019-05-08T13:08:53',
modified: '2019-05-11T14:45:35',
start: '2019-05-09T13:00:00',
end: '2019-05-09T13:30:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BED1600525',
created: '2019-05-08T13:02:58',
modified: '2016-12-14T16:30:47',
start: '2019-05-09T13:30:00',
end: '2019-05-09T14:00:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'BED1600523',
created: '2019-05-08T12:40:52',
modified: '2016-12-13T17:12:40',
start: '2019-05-09T11:00:00',
end: '2019-05-09T12:00:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'MKC1600311',
created: '2019-05-08T12:36:02',
modified: '2019-05-11T16:40:10',
start: '2019-05-11T11:15:00',
end: '2019-05-11T11:30:00',
typeId: 'VW',
recurring: false,
cancelled: false,
organiserId: 'BED160186',
},
{
id: 'STS1600389',
created: '2019-05-08T11:48:40',
modified: '2019-05-09T14:38:50',
start: '2019-05-09T14:00:00',
end: '2019-05-09T14:30:00',
typeId: 'VW',
recurring: false,
cancelled: true,
organiserId: 'BED160186',
},
],
pageNumber: 1,
pageSize: 50,
pageCount: 50,
totalCount: 1710,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { fetcher } from '../../../../common/utils/fetcher-server'
import { appointmentsDataStub } from '../__stubs__/appointments'
import { getAppointmentSlots } from '../get-appointment-slots'
import { getServerHeaders } from '../../../../common/utils/get-server-headers'
import { Request, Response } from 'express'
import { PACKAGE_SUFFIXES } from '../../../../common/utils/constants'
import { errorHandler } from '../../../../common/utils/error-handler'

jest.mock('../../../../common/utils/fetcher-server')
jest.mock('../../../../common/utils/error-handler')

describe('getAppointmentSlots server API', () => {
it('should correctly call the fetcher for getAppointmentSlots', async () => {
process.env.PLATFORM_API_BASE_URL = 'http://localhost:3000'
;(fetcher as jest.Mock).mockImplementation(() => appointmentsDataStub)

const req = {
url: '/appointments',
} as Request

const res = ({
status: jest.fn(),
json: jest.fn(),
end: jest.fn(),
} as unknown) as Response

const headers = await getServerHeaders(req, PACKAGE_SUFFIXES.APPOINTMENT_PLANNER)

await getAppointmentSlots(req, res)

expect(fetcher).toHaveBeenCalledWith({
url: `${process.env.PLATFORM_API_BASE_URL}${req.url}`,
headers,
})
expect(res.status).toHaveBeenCalledWith(200)
expect(res.json).toHaveBeenCalledWith(appointmentsDataStub)
expect(res.end).toHaveBeenCalledTimes(1)
})

it('should correctly catch an error', async () => {
process.env.PLATFORM_API_BASE_URL = 'http://localhost:3000'
const error = new Error('Something went wrong')
;(fetcher as jest.Mock).mockImplementation(() => {
throw error
})

const req = {
url: '/appointments',
} as Request

const res = ({
status: jest.fn(),
json: jest.fn(),
end: jest.fn(),
} as unknown) as Response

await getAppointmentSlots(req, res)

expect(errorHandler).toHaveBeenCalledWith(error, res)
})

afterEach(() => {
jest.resetAllMocks()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Request, Response } from 'express'
import { fetcher } from '../../../common/utils/fetcher-server'
import { PagedResultAppointmentModel_ } from '@reapit/foundations-ts-definitions'
import { errorHandler } from '../../../common/utils/error-handler'
import { getServerHeaders } from '../../../common/utils/get-server-headers'
import { PACKAGE_SUFFIXES } from '../../../common/utils/constants'

export const getAppointmentSlots = async (req: Request, res: Response) => {
try {
const headers = await getServerHeaders(req, PACKAGE_SUFFIXES.APPOINTMENT_PLANNER)
const url = new URL(`${process.env.PLATFORM_API_BASE_URL}${req.url}`)
const response = await fetcher<PagedResultAppointmentModel_, undefined>({
url: String(url),
headers,
})

if (response) {
res.status(200)
res.json(response)
res.end()
}
} catch (err) {
errorHandler(err, res)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { APIGatewayProxyEvent, APIGatewayEventRequestContextWithAuthorizer } from 'aws-lambda'
import { appointmentPlannerHandler, parseHeadersFromEvent } from '../index'

describe('appointmentPlannerHandler', () => {
it('should launch without crashing', async () => {
try {
await appointmentPlannerHandler({} as any, {} as any)
} catch (err) {
expect(err).toBeUndefined()
}
})
})

describe('parseHeadersFromEvent', () => {
const mockEvent = {
headers: {
Accept: '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
Host: 'mockHost',
'User-Agent': 'PostmanRuntime/7.24.1',
'X-Api-Key': '123456',
'X-Forwarded-Port': '443',
'X-Forwarded-Proto': 'https',
},
requestContext: {
authorizer: {
authorization: ' mockAuthorization',
'reapit-customer': 'DXX',
principalid: 'Allow',
},
} as APIGatewayEventRequestContextWithAuthorizer<any>,
body: '',
multiValueHeaders: {},
httpMethod: 'GET',
isBase64Encoded: false,
path: '',
pathParameters: {},
queryStringParameters: null,
multiValueQueryStringParameters: null,
stageVariables: null,
resource: '',
} as APIGatewayProxyEvent
const result = parseHeadersFromEvent(mockEvent)
expect(result).toEqual({
Accept: '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
Host: 'mockHost',
'User-Agent': 'PostmanRuntime/7.24.1',
'X-Api-Key': '123456',
'X-Forwarded-Port': '443',
'X-Forwarded-Proto': 'https',
authorization: 'Bearer mockAuthorization',
principalid: 'Allow',
'reapit-customer': 'DXX',
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import routes from '../routers'

describe('routes', () => {
it('should handle get requests to appointment-slots', () => {
expect(routes.stack[0].route.path).toEqual('/appointment-slots')
expect(routes.stack[0].route.methods.get).toBe(true)
})
})
Loading

0 comments on commit b668c42

Please sign in to comment.