From 727370446f25a9e8215eaef465210b6a5ffd2a15 Mon Sep 17 00:00:00 2001 From: Phan An Date: Sun, 25 Feb 2024 16:38:55 +0700 Subject: [PATCH] feat(test): add tests for invitation service --- resources/assets/js/services/authService.ts | 2 +- .../js/services/downloadService.spec.ts | 4 +- .../js/services/invitationService.spec.ts | 57 +++++++++++++++++++ .../assets/js/services/invitationService.ts | 9 ++- resources/assets/js/stores/userStore.ts | 2 +- 5 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 resources/assets/js/services/invitationService.spec.ts diff --git a/resources/assets/js/services/authService.ts b/resources/assets/js/services/authService.ts index 743c2e1b..65826495 100644 --- a/resources/assets/js/services/authService.ts +++ b/resources/assets/js/services/authService.ts @@ -10,7 +10,7 @@ export interface UpdateCurrentProfileData { new_password?: string } -interface CompositeToken { +export interface CompositeToken { 'audio-token': string 'token': string } diff --git a/resources/assets/js/services/downloadService.spec.ts b/resources/assets/js/services/downloadService.spec.ts index ff4fed61..11aad8c9 100644 --- a/resources/assets/js/services/downloadService.spec.ts +++ b/resources/assets/js/services/downloadService.spec.ts @@ -29,11 +29,11 @@ new class extends UnitTestCase { it('downloads a playlist', () => { const mock = this.mock(downloadService, 'trigger') - const playlist = factory('playlist', { id: 42 }) + const playlist = factory('playlist') downloadService.fromPlaylist(playlist) - expect(mock).toHaveBeenCalledWith('playlist/42') + expect(mock).toHaveBeenCalledWith(`playlist/${playlist.id}`) }) it.each<[Song[], boolean]>([[[], false], [factory('song', 5), true]])( diff --git a/resources/assets/js/services/invitationService.spec.ts b/resources/assets/js/services/invitationService.spec.ts new file mode 100644 index 00000000..5e8b6a48 --- /dev/null +++ b/resources/assets/js/services/invitationService.spec.ts @@ -0,0 +1,57 @@ +import { expect, it } from 'vitest' +import UnitTestCase from '@/__tests__/UnitTestCase' +import factory from '@/__tests__/factory' +import { authService, http } from '@/services' +import { userStore } from '@/stores' +import { invitationService } from './invitationService' + +new class extends UnitTestCase { + protected test () { + it('accepts an invitation', async () => { + const postMock = this.mock(http, 'post').mockResolvedValue({ + 'audio-token': 'my-audio-token', + token: 'my-token', + }) + + const setAudioTokenMock = this.mock(authService, 'setAudioToken') + const setApiTokenMock = this.mock(authService, 'setApiToken') + + await invitationService.accept('invite-token', 'foo', 'bar') + + expect(postMock).toHaveBeenCalledWith('invitations/accept', { + token: 'invite-token', + name: 'foo', + password: 'bar', + }) + + expect(setAudioTokenMock).toHaveBeenCalledWith('my-audio-token') + expect(setApiTokenMock).toHaveBeenCalledWith('my-token') + }) + + it('invites users', async () => { + const prospects = factory.states('prospect')('user', 2) + const addMock = this.mock(userStore, 'add') + const postMock = this.mock(http, 'post').mockResolvedValue(prospects) + + await invitationService.invite([prospects[0].email, prospects[1].email], false) + + expect(postMock).toHaveBeenCalledWith('invitations', { + emails: [prospects[0].email, prospects[1].email], + is_admin: false, + }) + + expect(addMock).toHaveBeenCalledWith(prospects) + }) + + it('revokes an invitation', async () => { + const user = factory.states('prospect')('user') + const removeMock = this.mock(userStore, 'remove') + const deleteMock = this.mock(http, 'delete') + + await invitationService.revoke(user) + + expect(deleteMock).toHaveBeenCalledWith('invitations', { email: user.email }) + expect(removeMock).toHaveBeenCalledWith(user) + }) + } +} diff --git a/resources/assets/js/services/invitationService.ts b/resources/assets/js/services/invitationService.ts index 16d30c8f..533fdf32 100644 --- a/resources/assets/js/services/invitationService.ts +++ b/resources/assets/js/services/invitationService.ts @@ -1,16 +1,19 @@ -import { http } from '@/services' +import { authService, CompositeToken, http } from '@/services' import { userStore } from '@/stores' export const invitationService = { getUserProspect: async (token: string) => await http.get(`invitations?token=${token}`), async accept (token: string, name: string, password: string) { - await http.post('invitations/accept', { token, name, password }) + const compositeToken = await http.post('invitations/accept', { token, name, password }) + + authService.setAudioToken(compositeToken['audio-token']) + authService.setApiToken(compositeToken.token) }, invite: async (emails: string[], isAdmin: boolean) => { const users = await http.post('invitations', { emails, is_admin: isAdmin }) - users.forEach(user => userStore.add(user)) + userStore.add(users) }, revoke: async (user: User) => { diff --git a/resources/assets/js/stores/userStore.ts b/resources/assets/js/stores/userStore.ts index 78f1afd8..766e9c0e 100644 --- a/resources/assets/js/stores/userStore.ts +++ b/resources/assets/js/stores/userStore.ts @@ -58,7 +58,7 @@ export const userStore = { return this.byId(user.id) }, - add (user: User) { + add (user: User | User[]) { this.state.users.push(...this.syncWithVault(user)) },