-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
319 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,27 @@ describe('RoomsRepository', () => { | |
}); | ||
}); | ||
|
||
test.each(testCases)('[$name] finds users by email', async ({ name }) => { | ||
const repo = repos[name]; | ||
|
||
const params: SaveUserParams = { | ||
sub: 'google_123', | ||
email: '[email protected]', | ||
name: 'Some User', | ||
}; | ||
|
||
await repo.saveUser(params); | ||
const found = await repo.findUser('[email protected]'); | ||
|
||
expect(found).toMatchObject({ | ||
id: 'user:google_123', | ||
email: '[email protected]', | ||
name: 'Some User', | ||
}); | ||
|
||
expect(await repo.findUser('[email protected]')).toBeNull(); | ||
}); | ||
|
||
test.each(testCases)('[$name] updates users', async ({ name }) => { | ||
const repo = repos[name]; | ||
const params: SaveUserParams = { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import { Command } from '@entities/command.entity'; | |
import { BadRequestException } from '@nestjs/common'; | ||
import { ParseCommandUseCase } from '.'; | ||
import { ParsedCommand } from './command.parser'; | ||
import { JoinPolicy } from '@entities/room.entity'; | ||
|
||
describe('ParseCommandUseCase', () => { | ||
let parse: ParseCommandUseCase; | ||
|
@@ -118,6 +119,76 @@ describe('ParseCommandUseCase', () => { | |
}); | ||
}); | ||
|
||
describe('/rename user', () => { | ||
it('parses valid commands', () => { | ||
withMessage('/rename user My User').expectCommand({ | ||
tag: 'renameUser', | ||
params: { | ||
newName: 'My User', | ||
}, | ||
}); | ||
}); | ||
|
||
it('validates the number of arguments', () => { | ||
withMessage('/rename user').expectError( | ||
'Error in command `/rename user`:', | ||
`* Received too few arguments. Expected: \`/rename user {name}\``, | ||
); | ||
}); | ||
}); | ||
|
||
describe('/leave', () => { | ||
it('parses valid commands', () => { | ||
withMessage('/leave').expectCommand({ | ||
tag: 'leave', | ||
params: null, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('/set room join policy', () => { | ||
it('parses valid commands', () => { | ||
withMessage('/set room join policy anyone').expectCommand({ | ||
tag: 'changeRoomJoinPolicy', | ||
params: { | ||
newJoinPolicy: JoinPolicy.Anyone, | ||
}, | ||
}); | ||
}); | ||
|
||
it('validates the number of arguments', () => { | ||
withMessage('/set room join policy').expectError( | ||
'Error in command `/set room join policy`:', | ||
`* Received too few arguments. Expected: \`/set room join policy {'anyone', 'invite'}\``, | ||
); | ||
}); | ||
}); | ||
|
||
describe('/invite', () => { | ||
it('parses valid commands', () => { | ||
withMessage('/invite [email protected]').expectCommand({ | ||
tag: 'inviteUser', | ||
params: { | ||
email: '[email protected]', | ||
}, | ||
}); | ||
}); | ||
|
||
it('validates the number of arguments', () => { | ||
withMessage('/invite').expectError( | ||
'Error in command `/invite`:', | ||
`* Received too few arguments. Expected: \`/invite {email}\``, | ||
); | ||
}); | ||
|
||
it('validates the email', () => { | ||
withMessage('/invite not-an-email').expectError( | ||
'Error in command `/invite not-an-email`:', | ||
`* Argument 1 (\`not-an-email\`): Invalid email`, | ||
); | ||
}); | ||
}); | ||
|
||
it('responds if the command is unrecognised', () => { | ||
const command: Command = { | ||
roomId: 'my-room', | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { JoinPolicy } from '@entities/room.entity'; | ||
import { TestAuthService } from '@fixtures/auth/test-auth-service'; | ||
import { TestMembershipsRepository } from '@fixtures/data/test.memberships.repository'; | ||
import { TestRoomsRepository } from '@fixtures/data/test.rooms.repository'; | ||
import { RoomFactory } from '@fixtures/messages/room.factory'; | ||
import { UserFactory } from '@fixtures/messages/user.factory'; | ||
import { UnauthorizedException } from '@nestjs/common'; | ||
import { AppLogger } from '@app/app.logger'; | ||
import { Role } from '@usecases/auth.service'; | ||
import mock, { MockProxy } from 'jest-mock-extended/lib/Mock'; | ||
import { Dispatcher } from '@entities/messages/message'; | ||
import { InviteUseCase } from './invite'; | ||
import { TestUsersRepository } from '@fixtures/data/test.users.repository'; | ||
import { MembershipStatus } from '@entities/membership.entity'; | ||
|
||
describe('InviteUseCase', () => { | ||
let invite: InviteUseCase; | ||
let rooms: TestRoomsRepository; | ||
let users: TestUsersRepository; | ||
let memberships: TestMembershipsRepository; | ||
let auth: TestAuthService; | ||
let dispatcher: MockProxy<Dispatcher>; | ||
|
||
const owner = UserFactory.build({ name: 'Alice' }); | ||
const otherUser = UserFactory.build({ name: 'Bob' }); | ||
const room = RoomFactory.build({ joinPolicy: JoinPolicy.Invite }); | ||
|
||
const now = new Date(1000); | ||
|
||
beforeEach(() => { | ||
rooms = new TestRoomsRepository(); | ||
rooms.setData([room]); | ||
|
||
users = new TestUsersRepository(); | ||
users.setData([owner, otherUser]); | ||
|
||
memberships = new TestMembershipsRepository(); | ||
|
||
auth = new TestAuthService(mock<AppLogger>()); | ||
auth.stubPermission({ user: owner, subject: room, action: Role.Manage }); | ||
|
||
dispatcher = mock<Dispatcher>(); | ||
|
||
invite = new InviteUseCase(rooms, users, memberships, auth, dispatcher); | ||
|
||
jest.useFakeTimers({ now }); | ||
}); | ||
|
||
it('invites a user to the room', async () => { | ||
await invite.exec({ | ||
authenticatedUser: owner, | ||
roomId: room.id, | ||
email: otherUser.email, | ||
}); | ||
|
||
expect(memberships.getData()).toEqual([ | ||
{ | ||
userId: otherUser.id, | ||
roomId: room.id, | ||
status: MembershipStatus.PendingInvite, | ||
from: now.getTime(), | ||
}, | ||
]); | ||
|
||
expect(dispatcher.send).toHaveBeenCalledWith({ | ||
content: 'Alice invited Bob to join the room', | ||
authorId: 'system', | ||
roomId: room.id, | ||
}); | ||
}); | ||
|
||
it('authorizes the user', async () => { | ||
await expect( | ||
invite.exec({ | ||
authenticatedUser: otherUser, | ||
roomId: room.id, | ||
email: otherUser.email, | ||
}), | ||
).rejects.toEqual( | ||
new UnauthorizedException( | ||
'You do not have permission to perform this action.', | ||
), | ||
); | ||
}); | ||
|
||
it('checks the user exists', async () => { | ||
await invite.exec({ | ||
authenticatedUser: owner, | ||
roomId: room.id, | ||
email: '[email protected]', | ||
}); | ||
|
||
expect(dispatcher.send).toHaveBeenCalledWith({ | ||
content: 'No user exists with email [email protected]', | ||
authorId: 'system', | ||
roomId: room.id, | ||
recipientId: owner.id, | ||
}); | ||
}); | ||
|
||
it('checks the user is not already a member', async () => { | ||
await memberships.setData([ | ||
{ | ||
from: 0, | ||
roomId: room.id, | ||
userId: otherUser.id, | ||
status: MembershipStatus.Joined, | ||
}, | ||
]); | ||
|
||
await invite.exec({ | ||
authenticatedUser: owner, | ||
roomId: room.id, | ||
email: otherUser.email, | ||
}); | ||
|
||
expect(dispatcher.send).toHaveBeenCalledWith({ | ||
content: 'Bob is already a member of this room', | ||
authorId: 'system', | ||
roomId: room.id, | ||
recipientId: owner.id, | ||
}); | ||
}); | ||
|
||
it('checks the user doesn not already have an invite', async () => { | ||
await memberships.setData([ | ||
{ | ||
from: 0, | ||
roomId: room.id, | ||
userId: otherUser.id, | ||
status: MembershipStatus.PendingInvite, | ||
}, | ||
]); | ||
|
||
await invite.exec({ | ||
authenticatedUser: owner, | ||
roomId: room.id, | ||
email: otherUser.email, | ||
}); | ||
|
||
expect(dispatcher.send).toHaveBeenCalledWith({ | ||
content: 'Bob already has an invite to this room', | ||
authorId: 'system', | ||
roomId: room.id, | ||
recipientId: owner.id, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { JoinPolicy } from '@entities/room.entity'; | ||
import { TestAuthService } from '@fixtures/auth/test-auth-service'; | ||
import { TestMembershipsRepository } from '@fixtures/data/test.memberships.repository'; | ||
import { TestRoomsRepository } from '@fixtures/data/test.rooms.repository'; | ||
import { RoomFactory } from '@fixtures/messages/room.factory'; | ||
import { UserFactory } from '@fixtures/messages/user.factory'; | ||
import { UnauthorizedException } from '@nestjs/common'; | ||
import { JoinRoomUseCase } from './join'; | ||
import { AppLogger } from '@app/app.logger'; | ||
import { Role } from '@usecases/auth.service'; | ||
import mock, { MockProxy } from 'jest-mock-extended/lib/Mock'; | ||
import { Dispatcher, UpdatedEntity } from '@entities/messages/message'; | ||
import { LeaveRoomUseCase } from './leave'; | ||
import { MembershipStatus } from '@entities/membership.entity'; | ||
|
||
describe(':eaveRoomUseCase', () => { | ||
let leave: LeaveRoomUseCase; | ||
let rooms: TestRoomsRepository; | ||
let memberships: TestMembershipsRepository; | ||
let auth: TestAuthService; | ||
let dispatcher: MockProxy<Dispatcher>; | ||
|
||
const user = UserFactory.build({ name: 'Joe Bloggs' }); | ||
|
||
const now = new Date(1000); | ||
|
||
beforeEach(() => { | ||
rooms = new TestRoomsRepository(); | ||
memberships = new TestMembershipsRepository(); | ||
auth = new TestAuthService(mock<AppLogger>()); | ||
dispatcher = mock<Dispatcher>(); | ||
leave = new LeaveRoomUseCase(rooms, memberships, dispatcher); | ||
jest.useFakeTimers({ now }); | ||
}); | ||
|
||
it('assigns a membership to the user', async () => { | ||
const room = RoomFactory.build({ | ||
joinPolicy: JoinPolicy.Anyone, | ||
}); | ||
rooms.setData([room]); | ||
auth.stubPermission({ user, subject: room, action: Role.Read }); | ||
|
||
await leave.exec({ authenticatedUser: user, roomId: room.id }); | ||
|
||
expect(memberships.getData()).toEqual([ | ||
{ | ||
userId: user.id, | ||
roomId: room.id, | ||
status: MembershipStatus.Revoked, | ||
from: now.getTime(), | ||
}, | ||
]); | ||
|
||
expect(dispatcher.send).toHaveBeenCalledWith({ | ||
content: 'Joe Bloggs left the room.', | ||
authorId: 'system', | ||
roomId: room.id, | ||
updatedEntities: [UpdatedEntity.Room, UpdatedEntity.Users], | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters