-
Notifications
You must be signed in to change notification settings - Fork 87
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
feat(form-workspaces-be/2): add get workspaces functionality #4247
Changes from 10 commits
51a0ec3
a098ef0
f8f242c
cb550df
d420309
02bfb49
1daacb6
8179f3a
e929998
992384e
a5b1f4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { errAsync, okAsync } from 'neverthrow' | ||
import { mocked } from 'ts-jest/utils' | ||
|
||
import * as WorkspaceService from 'src/app/modules/workspace/workspace.service' | ||
|
||
import expressHandler from 'tests/unit/backend/helpers/jest-express' | ||
|
||
import { DatabaseError } from '../../core/core.errors' | ||
import * as WorkspaceController from '../workspace.controller' | ||
|
||
jest.mock('../workspace.service') | ||
const MockWorkspaceService = mocked(WorkspaceService) | ||
|
||
describe('workspace.controller', () => { | ||
beforeEach(() => jest.clearAllMocks()) | ||
|
||
describe('getWorkspaces', () => { | ||
const MOCK_REQ = expressHandler.mockRequest({ | ||
session: { | ||
user: { | ||
_id: 'exists', | ||
}, | ||
}, | ||
}) | ||
|
||
it('should return 200 with an array of workspaces', async () => { | ||
const mockRes = expressHandler.mockResponse() | ||
MockWorkspaceService.getWorkspaces.mockReturnValueOnce(okAsync([])) | ||
await WorkspaceController.getWorkspaces(MOCK_REQ, mockRes, jest.fn()) | ||
|
||
expect(mockRes.json).toHaveBeenCalledWith([]) | ||
}) | ||
|
||
it('should return 500 when database error occurs', async () => { | ||
const mockRes = expressHandler.mockResponse() | ||
const mockErrorString = 'something went wrong' | ||
MockWorkspaceService.getWorkspaces.mockReturnValueOnce( | ||
errAsync(new DatabaseError(mockErrorString)), | ||
) | ||
await WorkspaceController.getWorkspaces(MOCK_REQ, mockRes, jest.fn()) | ||
|
||
expect(mockRes.status).toBeCalledWith(500) | ||
expect(mockRes.json).toBeCalledWith({ message: mockErrorString }) | ||
}) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { ObjectId } from 'bson-ext' | ||
import mongoose from 'mongoose' | ||
import supertest, { Session } from 'supertest-session' | ||
|
||
import { getWorkspaceModel } from 'src/app/models/workspace.server.model' | ||
import { WorkspacesRouter } from 'src/app/routes/api/v3/admin/workspaces' | ||
|
||
import { | ||
createAuthedSession, | ||
logoutSession, | ||
} from 'tests/integration/helpers/express-auth' | ||
import { setupApp } from 'tests/integration/helpers/express-setup' | ||
import dbHandler from 'tests/unit/backend/helpers/jest-db' | ||
import { jsonParseStringify } from 'tests/unit/backend/helpers/serialize-data' | ||
|
||
const WorkspaceModel = getWorkspaceModel(mongoose) | ||
|
||
const app = setupApp('/workspaces', WorkspacesRouter, { | ||
setupWithAuth: true, | ||
}) | ||
|
||
const MOCK_USER_ID = new ObjectId() | ||
const MOCK_FORM_ID = new ObjectId() | ||
const MOCK_WORKSPACE_ID = new ObjectId() | ||
const MOCK_WORKSPACE_DOC = { | ||
_id: MOCK_WORKSPACE_ID, | ||
title: 'Workspace1', | ||
admin: MOCK_USER_ID, | ||
formIds: [], | ||
} | ||
|
||
describe('workspaces.routes', () => { | ||
let request: Session | ||
|
||
beforeAll(async () => await dbHandler.connect()) | ||
beforeEach(async () => { | ||
request = supertest(app) | ||
const { user } = await dbHandler.insertEncryptForm({ | ||
formId: MOCK_FORM_ID, | ||
userId: MOCK_USER_ID, | ||
}) | ||
request = await createAuthedSession(user.email, request) | ||
}) | ||
afterEach(async () => { | ||
await dbHandler.clearDatabase() | ||
jest.restoreAllMocks() | ||
}) | ||
afterAll(async () => await dbHandler.closeDatabase()) | ||
|
||
describe('GET /workspaces', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we test the ordering of workspaces as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I've added test for workspace ordering as well |
||
const GET_WORKSPACES_ENDPOINT = '/workspaces' | ||
|
||
it('should return 200 with an empty array when a user has no workspaces', async () => { | ||
const response = await request.get('/workspaces') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: should this use the |
||
|
||
expect(response.status).toEqual(200) | ||
expect(response.body).toEqual([]) | ||
}) | ||
|
||
it("should return 200 with an array of the user's workspaces sorted by title", async () => { | ||
const workspaceIds = [ | ||
MOCK_WORKSPACE_DOC._id, | ||
new ObjectId(), | ||
new ObjectId(), | ||
] | ||
const workspaceDocs = [ | ||
{ | ||
_id: workspaceIds[1], | ||
title: 'aSecondInOrder', | ||
admin: MOCK_USER_ID, | ||
formIds: [], | ||
}, | ||
{ | ||
_id: workspaceIds[2], | ||
title: 'bThirdInOrder', | ||
admin: MOCK_USER_ID, | ||
formIds: [], | ||
}, | ||
MOCK_WORKSPACE_DOC, | ||
] | ||
await WorkspaceModel.insertMany(workspaceDocs) | ||
const response = await request.get(GET_WORKSPACES_ENDPOINT) | ||
const expected = await WorkspaceModel.find({ _id: { $in: workspaceIds } }) | ||
const expectedWithVirtuals = expected.map((workspace) => | ||
workspace.toJSON(), | ||
) | ||
|
||
expect(response.status).toEqual(200) | ||
expect(response.body).toEqual(jsonParseStringify(expectedWithVirtuals)) | ||
}) | ||
|
||
it('should return 401 when user is not logged in', async () => { | ||
await logoutSession(request) | ||
const response = await request.get(GET_WORKSPACES_ENDPOINT) | ||
|
||
expect(response.status).toEqual(401) | ||
expect(response.body).toEqual({ message: 'User is unauthorized.' }) | ||
}) | ||
|
||
it('should return 500 when database errors occur', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can test for the other types of database errors as well. probably sufficient to do it just in integration tests, no need to add them in every other layer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the other testcases in the codebase, I added the test to the controller layer as we can mock the |
||
jest | ||
.spyOn(WorkspaceModel, 'getWorkspaces') | ||
.mockRejectedValueOnce(new Error('something went wrong')) | ||
const response = await request.get(GET_WORKSPACES_ENDPOINT) | ||
|
||
expect(response.status).toEqual(500) | ||
expect(response.body).toEqual({ | ||
message: 'Something went wrong. Please try again.', | ||
}) | ||
}) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import mongoose from 'mongoose' | ||
import { FormId, UserId } from 'shared/types' | ||
import { WorkspaceDto } from 'shared/types/workspace' | ||
|
||
import { getWorkspaceModel } from 'src/app/models/workspace.server.model' | ||
import * as WorkspaceService from 'src/app/modules/workspace/workspace.service' | ||
|
||
import { DatabaseError } from '../../core/core.errors' | ||
|
||
const WorkspaceModel = getWorkspaceModel(mongoose) | ||
|
||
describe('workspace.service', () => { | ||
beforeEach(async () => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
describe('getWorkspaces', () => { | ||
it('should return an array of workspaces that belong to the user', async () => { | ||
const mockWorkspaces = [ | ||
{ | ||
admin: 'user' as UserId, | ||
title: 'workspace1', | ||
formIds: [] as FormId[], | ||
}, | ||
] as WorkspaceDto[] | ||
const mockUserId = 'mockUserId' | ||
const getSpy = jest | ||
.spyOn(WorkspaceModel, 'getWorkspaces') | ||
.mockResolvedValueOnce(mockWorkspaces) | ||
const actual = await WorkspaceService.getWorkspaces(mockUserId) | ||
|
||
expect(getSpy).toHaveBeenCalledWith(mockUserId) | ||
expect(actual.isOk()).toEqual(true) | ||
expect(actual._unsafeUnwrap()).toEqual(mockWorkspaces) | ||
}) | ||
|
||
it('should return DatabaseError when error occurs whilst querying the database', async () => { | ||
const mockUserId = 'mockUserId' | ||
const getSpy = jest | ||
.spyOn(WorkspaceModel, 'getWorkspaces') | ||
.mockRejectedValueOnce(new Error('some error')) | ||
const actual = await WorkspaceService.getWorkspaces(mockUserId) | ||
|
||
expect(getSpy).toHaveBeenCalledWith(mockUserId) | ||
expect(actual.isErr()).toEqual(true) | ||
expect(actual._unsafeUnwrapErr()).toEqual(new DatabaseError()) | ||
}) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought this was the wrong type to add the
_id
in. I've reverted this change