From 5328b2fe44b07227bf732f52d0d738324adc5574 Mon Sep 17 00:00:00 2001 From: Na'aman Hirschfeld Date: Fri, 13 Oct 2023 18:42:55 +0200 Subject: [PATCH] feat: add frontend tests --- frontend/src/api/index.ts | 1 + frontend/tests/api/api.spec.ts | 148 +++++++++++++++++++++++++++++++++ frontend/tests/factories.ts | 14 ++++ 3 files changed, 163 insertions(+) diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 18d320a2..e40d33dd 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -1,5 +1,6 @@ export * from './applications-api'; export * from './fetcher'; +export * from './project-users-api'; export * from './projects-api'; export * from './prompt-config-api'; export * from './tokens-api'; diff --git a/frontend/tests/api/api.spec.ts b/frontend/tests/api/api.spec.ts index a67fad09..0ffa3d71 100644 --- a/frontend/tests/api/api.spec.ts +++ b/frontend/tests/api/api.spec.ts @@ -2,6 +2,7 @@ import { ApplicationFactory, ProjectFactory, + ProjectUserAccountFactory, PromptConfigFactory, TokenFactory, } from 'tests/factories'; @@ -25,6 +26,11 @@ import { handleUpdateProject, handleUpdatePromptConfig, } from '@/api'; +import { + handleAddUserToProject, + handleRemoveUserFromProject, + handleUpdateUserToPermission, +} from '@/api/project-users-api'; import { HttpMethod } from '@/constants'; describe('API tests', () => { @@ -570,5 +576,147 @@ describe('API tests', () => { }); }); }); + + describe('Project Users', () => { + describe('handleRetrieveProjectUsers', () => { + it('returns a list of project users', async () => { + const project = await ProjectFactory.build(); + const application = await ApplicationFactory.build(); + const userAccounts = + await ProjectUserAccountFactory.batch(2); + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(userAccounts), + }); + + const data = await handleRetrieveTokens({ + projectId: project.id, + applicationId: application.id, + }); + + expect(data).toEqual(userAccounts); + expect(mockFetch).toHaveBeenCalledWith( + new URL( + `http://www.example.com/v1/projects/${project.id}/users/`, + ), + { + headers: { + 'Authorization': 'Bearer test_token', + 'Content-Type': 'application/json', + 'X-Request-Id': expect.any(String), + }, + method: HttpMethod.Get, + }, + ); + }); + }); + describe('handleAddUserToProject', () => { + it('returns a project user', async () => { + const project = await ProjectFactory.build(); + const userAccount = await ProjectUserAccountFactory.build(); + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(userAccount), + }); + + const body = { + email: userAccount.email, + permission: userAccount.permission, + }; + + const data = await handleAddUserToProject({ + projectId: project.id, + data: body, + }); + + expect(data).toEqual(userAccount); + expect(mockFetch).toHaveBeenCalledWith( + new URL( + `http://www.example.com/v1/projects/${project.id}/users/`, + ), + { + headers: { + 'Authorization': 'Bearer test_token', + 'Content-Type': 'application/json', + 'X-Request-Id': expect.any(String), + }, + method: HttpMethod.Post, + body: JSON.stringify(body), + }, + ); + }); + }); + describe('handleUpdateUserToPermission', () => { + it('returns a project user', async () => { + const project = await ProjectFactory.build(); + const application = await ApplicationFactory.build(); + const userAccount = await ProjectUserAccountFactory.build(); + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(userAccount), + }); + + const body = { + userId: userAccount.id, + permission: userAccount.permission, + }; + + const data = await handleUpdateUserToPermission({ + projectId: project.id, + data: body, + }); + + expect(data).toEqual(userAccount); + expect(mockFetch).toHaveBeenCalledWith( + new URL( + `http://www.example.com/v1/projects/${project.id}/users/${userAccount.id}/`, + ), + { + headers: { + 'Authorization': 'Bearer test_token', + 'Content-Type': 'application/json', + 'X-Request-Id': expect.any(String), + }, + method: HttpMethod.Patch, + body: JSON.stringify(body), + }, + ); + }); + }); + describe('handleDeleteProjectUser', () => { + it('returns undefined', async () => { + const project = await ProjectFactory.build(); + const userAccount = await ProjectUserAccountFactory.build(); + + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(), + }); + + const data = await handleRemoveUserFromProject({ + projectId: project.id, + userId: userAccount.id, + }); + + expect(data).toBeUndefined(); + expect(mockFetch).toHaveBeenCalledWith( + new URL( + `http://www.example.com/v1/projects/${project.id}/users/${userAccount.id}/`, + ), + { + headers: { + 'Authorization': 'Bearer test_token', + 'Content-Type': 'application/json', + 'X-Request-Id': expect.any(String), + }, + method: HttpMethod.Delete, + }, + ); + }); + }); + }); }); }); diff --git a/frontend/tests/factories.ts b/frontend/tests/factories.ts index f65b12bf..d7628151 100644 --- a/frontend/tests/factories.ts +++ b/frontend/tests/factories.ts @@ -8,6 +8,7 @@ import { ModelVendor, OpenAIPromptMessage, Project, + ProjectUserAccount, PromptConfig, Token, } from '@/types'; @@ -67,3 +68,16 @@ export const TokenFactory = new TypeFactory(() => ({ name: faker.lorem.words(), createdAt: faker.date.past().toISOString(), })); + +export const ProjectUserAccountFactory = new TypeFactory( + () => ({ + id: faker.string.uuid(), + displayName: faker.person.fullName(), + email: faker.internet.email(), + firebaseId: faker.string.uuid(), + phoneNumber: faker.phone.number(), + photoUrl: faker.internet.url(), + createdAt: faker.date.past().toISOString(), + permission: AccessPermission.ADMIN, + }), +);