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

refactor: extract create logic endpoint / refactor $watchCollection #1796

Merged
merged 18 commits into from
May 17, 2021
Merged
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
143 changes: 143 additions & 0 deletions src/app/models/__tests__/form.server.model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,149 @@ describe('Form Model', () => {
})
})

describe('createFormLogic', () => {
const logicId = new ObjectId().toHexString()

const mockExistingFormLogic = {
form_logics: [
{
_id: logicId,
logicType: LogicType.ShowFields,
} as ILogicSchema,
],
}

const mockNewFormLogic = ({
logicType: LogicType.PreventSubmit,
} as unknown) as ILogicSchema

it('should return form upon successful create logic if form_logic is currently empty', async () => {
// arrange
const formParams = merge({}, MOCK_EMAIL_FORM_PARAMS, {
admin: populatedAdmin,
status: Status.Public,
responseMode: ResponseMode.Email,
form_logics: [],
})
const form = await Form.create(formParams)

// act
const modifiedForm = await Form.createFormLogic(
form._id,
mockNewFormLogic,
)

// assert
// Form should be returned
expect(modifiedForm).not.toBeNull()

// Form should have correct status, responsemode
expect(modifiedForm?.responseMode).not.toBeNull()
expect(modifiedForm?.responseMode).toEqual(ResponseMode.Email)
expect(modifiedForm?.status).not.toBeNull()
expect(modifiedForm?.status).toEqual(Status.Public)

// Check that form logic has been added
expect(modifiedForm?.form_logics).toBeDefined()
expect(modifiedForm?.form_logics).toHaveLength(1)
expect(modifiedForm!.form_logics![0].logicType).toEqual(
LogicType.PreventSubmit,
)
})

it('should allow the same logic to be added more than once and then return form if createLogic is called more than once', async () => {
tshuli marked this conversation as resolved.
Show resolved Hide resolved
// arrange
const formParams = merge({}, MOCK_EMAIL_FORM_PARAMS, {
admin: populatedAdmin,
status: Status.Public,
responseMode: ResponseMode.Email,
form_logics: [],
})
const form = await Form.create(formParams)

// act
await Form.createFormLogic(form._id, mockNewFormLogic)

const modifiedFormRepeat = await Form.createFormLogic(
form._id,
mockNewFormLogic,
)

// assert
// Form should be returned
expect(modifiedFormRepeat).not.toBeNull()

// Form should have correct status, responsemode
expect(modifiedFormRepeat?.responseMode).not.toBeNull()
expect(modifiedFormRepeat?.responseMode).toEqual(ResponseMode.Email)
expect(modifiedFormRepeat?.status).not.toBeNull()
expect(modifiedFormRepeat?.status).toEqual(Status.Public)

// Check that form logic has been added
expect(modifiedFormRepeat?.form_logics).toBeDefined()
expect(modifiedFormRepeat?.form_logics).toHaveLength(2)
expect(modifiedFormRepeat!.form_logics![0].logicType).toEqual(
LogicType.PreventSubmit,
)
expect(modifiedFormRepeat!.form_logics![1].logicType).toEqual(
LogicType.PreventSubmit,
)
})

it('should return form upon successful create logic if form_logic has existing elements', async () => {
// arrange
const formParams = merge({}, MOCK_EMAIL_FORM_PARAMS, {
admin: populatedAdmin,
status: Status.Public,
responseMode: ResponseMode.Email,
...mockExistingFormLogic,
})
const form = await Form.create(formParams)

// act
const modifiedForm = await Form.createFormLogic(
form._id,
mockNewFormLogic,
)

// assert
// Form should be returned
expect(modifiedForm).not.toBeNull()

// Form should have correct status, responsemode
expect(modifiedForm?.responseMode).not.toBeNull()
expect(modifiedForm?.responseMode).toEqual(ResponseMode.Email)
expect(modifiedForm?.status).not.toBeNull()
expect(modifiedForm?.status).toEqual(Status.Public)

// Check that form logic has been added
expect(modifiedForm?.form_logics).toBeDefined()
expect(modifiedForm?.form_logics).toHaveLength(2)
expect(modifiedForm!.form_logics![0].logicType).toEqual(
LogicType.ShowFields,
)
expect(modifiedForm!.form_logics![1].logicType).toEqual(
LogicType.PreventSubmit,
)
})

it('should return null if formId is invalid', async () => {
// arrange

const invalidFormId = new ObjectId().toHexString()

// act
const modifiedForm = await Form.createFormLogic(
invalidFormId,
mockNewFormLogic,
)

// assert
// should return null
expect(modifiedForm).toBeNull()
})
})

describe('deleteFormLogic', () => {
const logicId = new ObjectId().toHexString()
const mockFormLogic = {
Expand Down
17 changes: 17 additions & 0 deletions src/app/models/form.server.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,22 @@ const compileFormModel = (db: Mongoose): IFormModel => {
).exec()
}

// Creates specified form logic.
FormSchema.statics.createFormLogic = async function (
this: IFormModel,
formId: string,
createLogicBody: LogicDto,
): Promise<IFormSchema | null> {
return this.findByIdAndUpdate(
formId,
{ $push: { form_logics: createLogicBody } },
{
new: true,
runValidators: true,
},
).exec()
}

// Deletes specified form field by id.
FormSchema.statics.deleteFormFieldById = async function (
this: IFormModel,
Expand All @@ -693,6 +709,7 @@ const compileFormModel = (db: Mongoose): IFormModel => {
{ new: true, runValidators: true },
).exec()
}

// Updates specified form logic.
FormSchema.statics.updateFormLogic = async function (
this: IFormModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7824,6 +7824,182 @@ describe('admin-form.controller', () => {
})
})

describe('_handleCreateLogic', () => {
const MOCK_USER_ID = new ObjectId().toHexString()
const MOCK_FORM_ID = new ObjectId().toHexString()
const MOCK_USER = {
_id: MOCK_USER_ID,
email: '[email protected]',
} as IPopulatedUser

const logicId = new ObjectId().toHexString()
const mockFormLogic = {
form_logics: [
{
_id: logicId,
id: logicId,
} as ILogicSchema,
],
}

const mockCreateLogicBody = {
_id: logicId,
} as ILogicSchema

const MOCK_FORM = {
admin: MOCK_USER,
_id: MOCK_FORM_ID,
title: 'mock title',
...mockFormLogic,
} as IPopulatedForm

const mockReq = expressHandler.mockRequest({
params: {
formId: MOCK_FORM_ID,
logicId,
},
session: {
user: {
_id: MOCK_USER_ID,
},
},
body: mockCreateLogicBody,
})
const mockRes = expressHandler.mockResponse()

beforeEach(() => {
MockUserService.getPopulatedUserById.mockReturnValue(okAsync(MOCK_USER))
MockAuthService.getFormAfterPermissionChecks.mockReturnValue(
okAsync(MOCK_FORM),
)
MockAdminFormService.createFormLogic.mockReturnValue(
okAsync(mockCreateLogicBody),
)
})

it('should call all services correctly when request is valid', async () => {
await AdminFormController._handleCreateLogic(mockReq, mockRes, jest.fn())

expect(MockUserService.getPopulatedUserById).toHaveBeenCalledWith(
MOCK_USER_ID,
)
expect(MockAuthService.getFormAfterPermissionChecks).toHaveBeenCalledWith(
{
user: MOCK_USER,
formId: MOCK_FORM_ID,
level: PermissionLevel.Write,
},
)
expect(MockAdminFormService.createFormLogic).toHaveBeenCalledWith(
MOCK_FORM,
mockCreateLogicBody,
)

expect(mockRes.status).toHaveBeenCalledWith(200)
expect(mockRes.json).toHaveBeenCalledWith(mockCreateLogicBody)
})

it('should return 403 when user does not have permissions to update logic', async () => {
MockAuthService.getFormAfterPermissionChecks.mockReturnValue(
errAsync(
new ForbiddenFormError('not authorized to perform write operation'),
),
)

await AdminFormController._handleCreateLogic(mockReq, mockRes, jest.fn())

expect(MockUserService.getPopulatedUserById).toHaveBeenCalledWith(
MOCK_USER_ID,
)
expect(MockAuthService.getFormAfterPermissionChecks).toHaveBeenCalledWith(
{
user: MOCK_USER,
formId: MOCK_FORM_ID,
level: PermissionLevel.Write,
},
)
expect(MockAdminFormService.createFormLogic).not.toHaveBeenCalled()

expect(mockRes.status).toHaveBeenCalledWith(403)

expect(mockRes.json).toHaveBeenCalledWith({
message: 'not authorized to perform write operation',
})
})

it('should return 404 when form cannot be found', async () => {
MockAuthService.getFormAfterPermissionChecks.mockReturnValue(
errAsync(new FormNotFoundError()),
)

await AdminFormController._handleCreateLogic(mockReq, mockRes, jest.fn())

expect(MockUserService.getPopulatedUserById).toHaveBeenCalledWith(
MOCK_USER_ID,
)
expect(MockAuthService.getFormAfterPermissionChecks).toHaveBeenCalledWith(
{
user: MOCK_USER,
formId: MOCK_FORM_ID,
level: PermissionLevel.Write,
},
)
expect(MockAdminFormService.createFormLogic).not.toHaveBeenCalled()

expect(mockRes.status).toHaveBeenCalledWith(404)

expect(mockRes.json).toHaveBeenCalledWith({
message: 'Form not found',
})
})

it('should return 422 when user in session cannot be retrieved from the database', async () => {
MockUserService.getPopulatedUserById.mockReturnValue(
errAsync(new MissingUserError()),
)

await AdminFormController._handleCreateLogic(mockReq, mockRes, jest.fn())

expect(MockUserService.getPopulatedUserById).toHaveBeenCalledWith(
MOCK_USER_ID,
)
expect(
MockAuthService.getFormAfterPermissionChecks,
).not.toHaveBeenCalled()

expect(MockAdminFormService.createFormLogic).not.toHaveBeenCalled()

expect(mockRes.status).toHaveBeenCalledWith(422)

expect(mockRes.json).toHaveBeenCalledWith({
message: 'User not found',
})
})

it('should return 500 when database error occurs', async () => {
MockUserService.getPopulatedUserById.mockReturnValue(
errAsync(new DatabaseError()),
)

await AdminFormController._handleCreateLogic(mockReq, mockRes, jest.fn())

expect(MockUserService.getPopulatedUserById).toHaveBeenCalledWith(
MOCK_USER_ID,
)
expect(
MockAuthService.getFormAfterPermissionChecks,
).not.toHaveBeenCalled()

expect(MockAdminFormService.createFormLogic).not.toHaveBeenCalled()

expect(mockRes.status).toHaveBeenCalledWith(500)

expect(mockRes.json).toHaveBeenCalledWith({
message: 'Something went wrong. Please try again.',
})
})
})

describe('handleDeleteFormField', () => {
const MOCK_USER_ID = new ObjectId().toHexString()
const MOCK_FORM_ID = new ObjectId().toHexString()
Expand Down
Loading