The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/apps/meteor/tests/end-to-end/api/direct-message.ts

1312 lines
41 KiB

import type { Credentials } from '@rocket.chat/api-client';
import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings';
import { Random } from '@rocket.chat/random';
import { expect } from 'chai';
import { after, before, describe, it } from 'mocha';
import { getCredentials, api, request, credentials, apiUsername, apiEmail, methodCall } from '../../data/api-data';
import { pinMessage, sendMessage, starMessage, updateMessage } from '../../data/chat.helper';
import { updateSetting, updatePermission } from '../../data/permissions.helper';
import { deleteRoom } from '../../data/rooms.helper';
import { testFileUploads } from '../../data/uploads.helper';
import { password, adminUsername } from '../../data/user';
import type { TestUser } from '../../data/users.helper';
import { createUser, deleteUser, login, setUserStatus } from '../../data/users.helper';
describe('[Direct Messages]', () => {
let testDM: IRoom & { rid: IRoom['_id'] };
let user: TestUser<IUser>;
let directMessage: { _id: IRoom['_id'] };
before((done) => getCredentials(done));
before(async () => {
user = await createUser();
const cred = await login(user.username, password);
await setUserStatus(cred);
await request
.post(api('im.create'))
.set(credentials)
.send({
username: user.username,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
testDM = res.body.room;
});
});
before('/chat.postMessage', (done) => {
void request
.post(api('chat.postMessage'))
.set(credentials)
.send({
roomId: testDM.rid,
text: 'This message was sent using the API',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.nested.property('message.msg', 'This message was sent using the API');
expect(res.body).to.have.nested.property('message.rid');
directMessage = { _id: res.body.message.rid };
})
.end(done);
});
after(() => deleteUser(user));
describe('/im.setTopic', () => {
it('should set the topic of the DM with a string', (done) => {
void request
.post(api('im.setTopic'))
.set(credentials)
.send({
roomId: directMessage._id,
topic: `a direct message with ${user.username}`,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.nested.property('topic', `a direct message with ${user.username}`);
})
.end(done);
});
it('should set the topic of DM with an empty string(remove the topic)', (done) => {
void request
.post(api('im.setTopic'))
.set(credentials)
.send({
roomId: directMessage._id,
topic: '',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.nested.property('topic', '');
})
.end(done);
});
});
describe('Testing DM info', () => {
let dmMessage: IMessage;
it('sending a message...', (done) => {
void request
.post(api('chat.sendMessage'))
.set(credentials)
.send({
message: {
text: 'Sample message',
rid: testDM._id,
},
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
dmMessage = res.body.message;
})
.end(done);
});
it('REACTing with last message', (done) => {
void request
.post(api('chat.react'))
.set(credentials)
.send({
emoji: ':squid:',
messageId: dmMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
it('STARring last message', (done) => {
void request
.post(api('chat.starMessage'))
.set(credentials)
.send({
messageId: dmMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
it('PINning last message', (done) => {
void request
.post(api('chat.pinMessage'))
.set(credentials)
.send({
messageId: dmMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
it('should return all DM messages where the last message of array should have the "star" array with USERS star ONLY', (done) => {
void request
.get(api('im.messages'))
.set(credentials)
.query({
roomId: testDM._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages').and.to.be.an('array');
const messages = res.body.messages as IMessage[];
const lastMessage = messages.filter((message) => message._id === dmMessage._id)[0];
expect(lastMessage).to.have.property('starred').and.to.be.an('array');
expect(lastMessage.starred?.[0]._id).to.be.equal(adminUsername);
})
.end(done);
});
});
it('/im.history', (done) => {
void request
.get(api('im.history'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages');
})
.end(done);
});
it('/im.list', (done) => {
void request
.get(api('im.list'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count');
expect(res.body).to.have.property('total');
expect(res.body).to.have.property('ims').and.to.be.an('array');
const im = (res.body.ims as IRoom[]).find((dm) => dm._id === testDM._id);
expect(im).to.have.property('_id');
expect(im).to.have.property('t').and.to.be.eq('d');
expect(im).to.have.property('msgs').and.to.be.a('number');
expect(im).to.have.property('usernames').and.to.be.an('array');
expect(im).to.have.property('lm');
expect(im).to.have.property('_updatedAt');
expect(im).to.have.property('ts');
expect(im).to.have.property('lastMessage');
})
.end(done);
});
describe('/im.list.everyone', () => {
before(async () => {
return updatePermission('view-room-administration', ['admin']);
});
after(async () => {
return updatePermission('view-room-administration', ['admin']);
});
it('should succesfully return a list of direct messages', async () => {
await request
.get(api('im.list.everyone'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count', 1);
expect(res.body).to.have.property('total', 1);
expect(res.body).to.have.property('ims').and.to.be.an('array');
const im = res.body.ims[0];
expect(im).to.have.property('_id');
expect(im).to.have.property('t').and.to.be.eq('d');
expect(im).to.have.property('msgs').and.to.be.a('number');
expect(im).to.have.property('usernames').and.to.be.an('array');
expect(im).to.have.property('ro');
expect(im).to.have.property('sysMes');
expect(im).to.have.property('_updatedAt');
expect(im).to.have.property('ts');
expect(im).to.have.property('lastMessage');
});
});
it('should fail if user does NOT have the view-room-administration permission', async () => {
await updatePermission('view-room-administration', []);
await request
.get(api('im.list.everyone'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(403)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
});
});
});
describe("Setting: 'Use Real Name': true", () => {
before(async () => updateSetting('UI_Use_Real_Name', true));
after(async () => updateSetting('UI_Use_Real_Name', false));
it('/im.list', (done) => {
void request
.get(api('im.list'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count');
expect(res.body).to.have.property('total');
expect(res.body).to.have.property('ims').and.to.be.an('array');
const im = (res.body.ims as IRoom[]).find((dm) => dm._id === testDM._id) as IRoom;
expect(im).to.have.property('_id');
expect(im).to.have.property('t').and.to.be.eq('d');
expect(im).to.have.property('msgs').and.to.be.a('number');
expect(im).to.have.property('usernames').and.to.be.an('array');
expect(im).to.have.property('lm');
expect(im).to.have.property('_updatedAt');
expect(im).to.have.property('ts');
expect(im).to.have.property('lastMessage');
const { lastMessage } = im;
expect(lastMessage).to.have.nested.property('u.name', 'RocketChat Internal Admin Test');
})
.end(done);
});
it('/im.list.everyone', (done) => {
void request
.get(api('im.list.everyone'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count');
expect(res.body).to.have.property('total');
expect(res.body).to.have.property('ims').and.to.be.an('array');
const im = (res.body.ims as IRoom[]).find((dm) => dm._id === testDM._id) as IRoom;
expect(im).to.have.property('_id');
expect(im).to.have.property('t').and.to.be.eq('d');
expect(im).to.have.property('msgs').and.to.be.a('number');
expect(im).to.have.property('usernames').and.to.be.an('array');
expect(im).to.have.property('ro');
expect(im).to.have.property('sysMes');
expect(im).to.have.property('_updatedAt');
expect(im).to.have.property('ts');
expect(im).to.have.property('lastMessage');
const { lastMessage } = im;
expect(lastMessage).to.have.nested.property('u.name', 'RocketChat Internal Admin Test');
})
.end(done);
});
});
it('/im.open', (done) => {
void request
.post(api('im.open'))
.set(credentials)
.send({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
describe('/im.counters', () => {
it('should require auth', async () => {
await request
.get(api('im.counters'))
.expect('Content-Type', 'application/json')
.expect(401)
.expect((res) => {
expect(res.body).to.have.property('status', 'error');
});
});
it('should require a roomId', async () => {
await request
.get(api('im.counters'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
});
});
it('should work with all params right', (done) => {
void request
.get(api('im.counters'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('joined', true);
expect(res.body).to.have.property('members');
expect(res.body).to.have.property('unreads');
expect(res.body).to.have.property('unreadsFrom');
expect(res.body).to.have.property('msgs');
expect(res.body).to.have.property('latest');
expect(res.body).to.have.property('userMentions');
})
.end(done);
});
describe('with valid room id', () => {
let testDM: IRoom & { rid: IRoom['_id'] };
let user2: TestUser<IUser>;
let userCreds: Credentials;
before(async () => {
user2 = await createUser();
userCreds = await login(user2.username, password);
await request
.post(api('im.create'))
.set(credentials)
.send({
username: user2.username,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
testDM = res.body.room;
});
await request
.post(api('chat.sendMessage'))
.set(credentials)
.send({
message: {
text: 'Sample message',
rid: testDM._id,
},
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
});
after(async () => {
await request
.post(api('im.delete'))
.set(credentials)
.send({
roomId: testDM._id,
})
.expect(200);
await deleteUser(user2);
});
it('should properly return counters before opening the dm', async () => {
await request
.get(api('im.counters'))
.set(userCreds)
.query({
roomId: testDM._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('joined', true);
expect(res.body).to.have.property('members').and.to.be.a('number').and.to.be.eq(2);
expect(res.body).to.have.property('unreads').and.to.be.a('number').and.to.be.eq(1);
expect(res.body).to.have.property('unreadsFrom');
expect(res.body).to.have.property('msgs').and.to.be.a('number').and.to.be.eq(1);
expect(res.body).to.have.property('latest');
expect(res.body).to.have.property('userMentions').and.to.be.a('number').and.to.be.eq(0);
});
});
});
describe('with deactived users', async () => {
before(() => request.post(api('users.setActiveStatus')).set(credentials).send({ userId: user._id, activeStatus: false }));
after(() => request.post(api('users.setActiveStatus')).set(credentials).send({ userId: user._id, activeStatus: true }));
it('should not include deactivated users in members count', async () => {
// Deactivate the second user
const res = await request.get(api('im.counters')).set(credentials).query({ roomId: directMessage._id });
expect(res.status).to.equal(200);
expect(res.body.success).to.be.true;
// Only admin remain active
expect(res.body.members).to.equal(1);
});
});
});
describe('[/im.files]', async () => {
await testFileUploads('im.files', 'd', 'invalid-channel');
});
describe('/im.messages', () => {
let testUser: IUser;
let testUser2: IUser;
let testUserDMRoom: IRoom;
let testUserCredentials: Credentials;
let testUser2Credentials: Credentials;
let pinnedMessageId: IMessage['_id'];
let messages: Pick<IMessage, 'rid' | 'msg' | 'mentions'>[] = [];
before(async () => {
[testUser, testUser2] = await Promise.all([
createUser({ joinDefaultChannels: false, roles: ['admin'], username: `a_${Random.id()}` }),
createUser({ joinDefaultChannels: false, username: `b_${Random.id()}` }),
]);
[testUserCredentials, testUser2Credentials] = await Promise.all([
login(testUser.username, password),
login(testUser2.username, password),
]);
await setUserStatus(testUserCredentials);
testUserDMRoom = (
await request
.post(api('im.create'))
.set(testUserCredentials)
.send({ username: `${testUser2.username}` })
).body.room;
messages = [
{
rid: testUserDMRoom._id,
msg: `@${adminUsername} youre being mentioned`,
mentions: [{ username: adminUsername, _id: adminUsername, name: adminUsername }],
},
{
rid: testUserDMRoom._id,
msg: `@${testUser.username} youre being mentioned`,
mentions: [{ username: testUser.username, _id: testUser._id, name: testUser.name }],
},
{
rid: testUserDMRoom._id,
msg: `A simple message`,
},
{
rid: testUserDMRoom._id,
msg: `A pinned simple message`,
},
];
/**
* We are not using `Promise.all` here because we want to ensure that each message is sent sequentially.
* This approach helps in maintaining the order of messages by ts.
*/
const starredMessage = await sendMessage({ message: messages[0], requestCredentials: testUserCredentials });
const pinnedMessage = await sendMessage({ message: messages[1], requestCredentials: testUser2Credentials });
await sendMessage({ message: messages[2], requestCredentials: testUserCredentials });
await sendMessage({ message: messages[3], requestCredentials: testUser2Credentials });
await Promise.all([
starMessage({ messageId: starredMessage.body.message._id, requestCredentials: testUserCredentials }),
pinMessage({ messageId: pinnedMessage.body.message._id, requestCredentials: testUserCredentials }),
]);
pinnedMessageId = pinnedMessage.body.message._id;
});
after(async () => Promise.all([deleteUser(testUser), deleteUser(testUser2)]));
it('should return all DM messages that were sent to yourself using your username', (done) => {
void request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
username: testUser.username,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages').and.to.be.an('array');
})
.end(done);
});
it('should sort by ts by default', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages.map((m: IMessage) => m.u.username)).to.deep.equal(
res.body.messages
.sort((a: IMessage, b: IMessage) => new Date(b.ts).getTime() - new Date(a.ts).getTime())
.map((m: IMessage) => m.u.username),
);
});
});
it('should allow custom sorting', async () => {
const { messages } = (
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
).body;
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
sort: '{"u.username":-1}',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages.map((m: IMessage) => m.u.username)).to.deep.equal(
messages.map((m: IMessage) => m.u.username).sort((a: string, b: string) => b.localeCompare(a)),
);
});
});
it('should return an error when trying to access a DM that does not belong to the current user', async () => {
await request
.get(api('im.messages'))
.set(credentials)
.query({ roomId: testUserDMRoom._id })
.expect('Content-Type', 'application/json')
.expect(403)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'unauthorized');
});
});
it('should return messages that mention a single user', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
mentionIds: adminUsername,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages).to.have.lengthOf(1);
expect(res.body.messages[0]).to.have.nested.property('mentions').that.is.an('array').and.to.have.lengthOf(1);
expect(res.body.messages[0].mentions[0]).to.have.property('_id', adminUsername);
expect(res.body).to.have.property('count', 1);
expect(res.body).to.have.property('total', 1);
});
});
it('should return messages that mention multiple users', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
mentionIds: `${adminUsername},${testUser._id}`,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages).to.have.lengthOf(2);
expect(res.body).to.have.property('count', 2);
expect(res.body).to.have.property('total', 2);
const mentionIds = res.body.messages.map((message: any) => message.mentions[0]._id);
expect(mentionIds).to.include.members([adminUsername, testUser._id]);
});
});
it('should return messages that are starred by a specific user', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
starredIds: testUser._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages).to.have.lengthOf(1);
expect(res.body.messages[0]).to.have.nested.property('starred').that.is.an('array').and.to.have.lengthOf(1);
expect(res.body).to.have.property('count', 1);
expect(res.body).to.have.property('total', 1);
});
});
it('should return messages that are pinned', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
pinned: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages).to.have.lengthOf(1);
expect(res.body.messages[0]).to.have.nested.property('pinned').that.is.an('boolean').and.to.be.true;
expect(res.body.messages[0]).to.have.nested.property('pinnedBy').that.is.an('object');
expect(res.body.messages[0].pinnedBy).to.have.property('_id', testUser._id);
expect(res.body).to.have.property('count', 1);
expect(res.body).to.have.property('total', 1);
});
});
describe('_hidden messages behavior when Message_KeepHistory is enabled', async () => {
before(async () => {
await updateSetting('Message_KeepHistory', true);
await pinMessage({ messageId: pinnedMessageId, unpin: true, requestCredentials: testUserCredentials });
});
after(async () => {
await updateSetting('Message_KeepHistory', false);
});
it('should return all messages, without any pinned messages', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({ roomId: testUserDMRoom._id })
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages').and.to.be.an('array');
expect(res.body.messages).to.have.lengthOf(5);
res.body.messages.forEach((msg: IMessage) => {
expect(msg).to.not.have.property('pinned', true);
expect(msg).to.not.have.property('_hidden');
});
});
});
it('should return no pinned messages', async () => {
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({
roomId: testUserDMRoom._id,
pinned: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages).to.have.lengthOf(0);
expect(res.body).to.have.property('count', 0);
expect(res.body).to.have.property('total', 0);
});
});
it('should not return old message when updating a message', async () => {
await updateMessage({
msgId: pinnedMessageId,
updatedMessage: 'message was unpinned',
roomId: testUserDMRoom._id,
requestCredentials: testUser2Credentials,
});
await request
.get(api('im.messages'))
.set(testUserCredentials)
.query({ roomId: testUserDMRoom._id })
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages').and.to.be.an('array');
expect(res.body.messages).to.have.lengthOf(5);
const updatedMessage = res.body.messages.find((msg: IMessage) => msg._id === pinnedMessageId);
expect(updatedMessage).to.have.property('msg', 'message was unpinned');
expect(updatedMessage).to.have.property('editedAt');
res.body.messages.forEach((msg: IMessage) => {
expect(msg).to.not.have.property('_hidden');
});
});
});
});
});
describe('/im.messages.others', () => {
it('should fail when the endpoint is disabled and the user has permissions', async () => {
await updateSetting('API_Enable_Direct_Message_History_EndPoint', false);
await request
.get(api('im.messages.others'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('errorType', 'error-endpoint-disabled');
});
});
it('should fail when the endpoint is disabled and the user doesnt have permission', async () => {
await updateSetting('API_Enable_Direct_Message_History_EndPoint', false);
await updatePermission('view-room-administration', []);
await request
.get(api('im.messages.others'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(403)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
});
});
it('should fail when the endpoint is enabled but the user doesnt have permission', async () => {
await updateSetting('API_Enable_Direct_Message_History_EndPoint', true);
await updatePermission('view-room-administration', []);
await request
.get(api('im.messages.others'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(403)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
});
});
it('should succeed when the endpoint is enabled and user has permission', async () => {
await updateSetting('API_Enable_Direct_Message_History_EndPoint', true);
await updatePermission('view-room-administration', ['admin']);
await request
.get(api('im.messages.others'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('messages').and.to.be.an('array');
expect(res.body).to.have.property('offset');
expect(res.body).to.have.property('count');
expect(res.body).to.have.property('total');
});
});
});
it('/im.close', (done) => {
void request
.post(api('im.close'))
.set(credentials)
.send({
roomId: directMessage._id,
userId: user._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
describe('fname property', () => {
const username = `fname_${apiUsername}`;
const name = `Name fname_${apiUsername}`;
const updatedName = `Updated Name fname_${apiUsername}`;
const email = `fname_${apiEmail}`;
let userId: IUser['_id'];
let directMessageId: IMessage['_id'];
let user: TestUser<IUser>;
before((done) => {
void request
.post(api('users.create'))
.set(credentials)
.send({
email,
name,
username,
password,
active: true,
roles: ['user'],
joinDefaultChannels: true,
verified: true,
})
.expect((res) => {
user = res.body.user;
userId = res.body.user._id;
})
.end(done);
});
before((done) => {
void request
.post(api('chat.postMessage'))
.set(credentials)
.send({
channel: `@${username}`,
text: 'This message was sent using the API',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.nested.property('message.msg', 'This message was sent using the API');
expect(res.body).to.have.nested.property('message.rid');
directMessageId = res.body.message.rid;
})
.end(done);
});
after(async () => deleteUser(user));
it('should have fname property', (done) => {
void request
.get(api('subscriptions.getOne'))
.set(credentials)
.query({
roomId: directMessageId,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.subscription).to.have.property('name', username);
expect(res.body.subscription).to.have.property('fname', name);
})
.end(done);
});
it("should update user's name", (done) => {
void request
.post(api('users.update'))
.set(credentials)
.send({
userId,
data: {
name: updatedName,
},
})
.expect((res) => {
expect(res.body.user).to.have.property('name', updatedName);
})
.end(done);
});
it('should have fname property updated', (done) => {
void request
.get(api('subscriptions.getOne'))
.set(credentials)
.query({
roomId: directMessageId,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.subscription).to.have.property('name', username);
expect(res.body.subscription).to.have.property('fname', updatedName);
})
.end(done);
});
});
describe('/im.members', () => {
it('should return and array with two members', (done) => {
void request
.get(api('im.members'))
.set(credentials)
.query({
roomId: directMessage._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count').and.to.be.equal(2);
expect(res.body).to.have.property('offset').and.to.be.equal(0);
expect(res.body).to.have.property('total').and.to.be.equal(2);
expect(res.body).to.have.property('members').and.to.have.lengthOf(2);
})
.end(done);
});
it('should return and array with one member', (done) => {
void request
.get(api('im.members'))
.set(credentials)
.query({
username: user.username,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count').and.to.be.equal(2);
expect(res.body).to.have.property('offset').and.to.be.equal(0);
expect(res.body).to.have.property('total').and.to.be.equal(2);
expect(res.body).to.have.property('members').and.to.have.lengthOf(2);
})
.end(done);
});
it('should return and array with one member queried by status', (done) => {
void request
.get(api('im.members'))
.set(credentials)
.query({
'roomId': directMessage._id,
'status[]': ['online'],
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('count').and.to.be.equal(1);
expect(res.body).to.have.property('offset').and.to.be.equal(0);
expect(res.body).to.have.property('total').and.to.be.equal(1);
expect(res.body).to.have.property('members').and.to.have.lengthOf(1);
})
.end(done);
});
});
describe('/im.create', () => {
let user: TestUser<IUser>;
let userCredentials: Credentials;
let otherUser: TestUser<IUser>;
let otherUserCredentials: Credentials;
let thirdUser: TestUser<IUser>;
let thirdUserCredentials: Credentials;
let roomIds: Record<string, IRoom['_id']> = {};
// Names have to be in alfabetical order so we can test the room's fullname
const userFullName = 'User A';
const otherUserFullName = 'User B';
const thirdUserFullName = 'User C';
before(async () => {
user = await createUser({ name: userFullName });
otherUser = await createUser({ name: otherUserFullName });
thirdUser = await createUser({ name: thirdUserFullName });
userCredentials = await login(user.username, password);
otherUserCredentials = await login(otherUser.username, password);
thirdUserCredentials = await login(thirdUser.username, password);
});
after(async () => {
await Promise.all(Object.values(roomIds).map((roomId) => deleteRoom({ type: 'd', roomId })));
await deleteUser(user);
await deleteUser(otherUser);
await deleteUser(thirdUser);
});
it('creates a DM between two other parties (including self)', (done) => {
void request
.post(api('im.create'))
.set(userCredentials)
.send({
usernames: [otherUser.username, thirdUser.username].join(','),
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room').and.to.be.an('object');
expect(res.body.room).to.have.property('usernames').and.to.have.members([thirdUser.username, user.username, otherUser.username]);
roomIds = { ...roomIds, multipleDm: res.body.room._id };
})
.end(done);
});
it('creates a DM between two other parties (excluding self)', (done) => {
void request
.post(api('im.create'))
.set(credentials)
.send({
usernames: [user.username, otherUser.username].join(','),
excludeSelf: true,
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room').and.to.be.an('object');
expect(res.body.room).to.have.property('usernames').and.to.have.members([user.username, otherUser.username]);
roomIds = { ...roomIds, dm: res.body.room._id };
})
.end(done);
});
it('should create a self-DM', (done) => {
void request
.post(api('im.create'))
.set(userCredentials)
.send({
username: user.username,
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room').and.to.be.an('object');
expect(res.body.room).to.have.property('usernames').and.to.have.members([user.username]);
roomIds = { ...roomIds, self: res.body.room._id };
})
.end(done);
});
describe('should create dm with correct notification preferences', () => {
let user: TestUser<IUser>;
let userCredentials: Credentials;
let userPrefRoomId: IRoom['_id'];
before(async () => {
user = await createUser();
userCredentials = await login(user.username, password);
});
after(async () => {
if (userPrefRoomId) {
await deleteRoom({ type: 'd', roomId: userPrefRoomId });
}
await deleteUser(user);
});
it('should save user preferences', async () => {
await request
.post(methodCall('saveUserPreferences'))
.set(userCredentials)
.send({
message: JSON.stringify({
id: 'id',
msg: 'method',
method: 'saveUserPreferences',
params: [{ emailNotificationMode: 'nothing' }],
}),
})
.expect(200);
});
it('should create a DM', (done) => {
void request
.post(api('im.create'))
.set(userCredentials)
.send({
usernames: [user.username, otherUser.username].join(','),
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room').and.to.be.an('object');
expect(res.body.room).to.have.property('usernames').and.to.have.members([user.username, otherUser.username]);
userPrefRoomId = res.body.room._id;
})
.end(done);
});
it('should return the right user notification preferences in the dm', (done) => {
void request
.get(api('subscriptions.getOne'))
.set(userCredentials)
.query({
roomId: userPrefRoomId,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('subscription').and.to.be.an('object');
expect(res.body).to.have.nested.property('subscription.emailNotifications').and.to.be.equal('nothing');
})
.end(done);
});
});
async function testRoomFNameForUser(testCredentials: Credentials, roomId: IRoom['_id'], fullName: string) {
return request
.get(api('subscriptions.getOne'))
.set(testCredentials)
.query({ roomId })
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('subscription').and.to.be.an('object');
expect(res.body.subscription).to.have.property('fname', fullName);
});
}
describe('Rooms fullName', () => {
it("should be own user's name for self DM", async () => {
await testRoomFNameForUser(userCredentials, roomIds.self, userFullName);
});
it("should be other user's name concatenated for multiple users's DM for every user", async () => {
await testRoomFNameForUser(userCredentials, roomIds.multipleDm, [otherUserFullName, thirdUserFullName].join(', '));
await testRoomFNameForUser(otherUserCredentials, roomIds.multipleDm, [userFullName, thirdUserFullName].join(', '));
await testRoomFNameForUser(thirdUserCredentials, roomIds.multipleDm, [userFullName, otherUserFullName].join(', '));
});
it("should be other user's name for DM for both users", async () => {
await testRoomFNameForUser(userCredentials, roomIds.dm, otherUserFullName);
await testRoomFNameForUser(otherUserCredentials, roomIds.dm, userFullName);
});
});
});
describe('/im.delete', () => {
let testDM: IRoom;
it('/im.create', (done) => {
void request
.post(api('im.create'))
.set(credentials)
.send({
username: user.username,
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
testDM = res.body.room;
})
.end(done);
});
it('/im.delete', (done) => {
void request
.post(api('im.delete'))
.set(credentials)
.send({
username: user.username,
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
it('/im.open', (done) => {
void request
.post(api('im.open'))
.set(credentials)
.send({
roomId: testDM._id,
})
.expect(403)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'unauthorized');
})
.end(done);
});
describe('when authenticated as a non-admin user', () => {
let otherUser: TestUser<IUser>;
let otherCredentials: Credentials;
before(async () => {
otherUser = await createUser();
otherCredentials = await login(otherUser.username, password);
});
after(async () => {
await deleteUser(otherUser);
});
it('/im.create', (done) => {
void request
.post(api('im.create'))
.set(credentials)
.send({
username: otherUser.username,
})
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
testDM = res.body.room;
})
.end(done);
});
it('/im.delete', (done) => {
void request
.post(api('im.delete'))
.set(otherCredentials)
.send({
roomId: testDM._id,
})
.expect(400)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', false);
})
.end(done);
});
});
});
});