Skip to content
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

test: read receipts #30637

Merged
merged 17 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ninety-carrots-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

test: read receipts
323 changes: 321 additions & 2 deletions apps/meteor/tests/end-to-end/api/24-methods.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { expect } from 'chai';
import { after, before, beforeEach, describe, it } from 'mocha';

import { getCredentials, request, methodCall, api, credentials } from '../../data/api-data.js';
import { api, credentials, getCredentials, methodCall, request } from '../../data/api-data.js';
import { sendSimpleMessage } from '../../data/chat.helper.js';
import { CI_MAX_ROOMS_PER_GUEST as maxRoomsPerGuest } from '../../data/constants';
import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { createRoom } from '../../data/rooms.helper';
import { createRoom, deleteRoom } from '../../data/rooms.helper';
import { password } from '../../data/user';
import { createUser, deleteUser, login } from '../../data/users.helper.js';
import { IS_EE } from '../../e2e/config/constants';

describe('Meteor.methods', function () {
this.retries(0);
Expand Down Expand Up @@ -123,6 +126,322 @@ describe('Meteor.methods', function () {
});
});

describe('[@getReadReceipts]', () => {
it('should fail if not logged in', async () => {
heitortanoue marked this conversation as resolved.
Show resolved Hide resolved
await request
.post(methodCall('getReadReceipts'))
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: 'test' }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(401)
.expect((res) => {
expect(res.body).to.have.property('status', 'error');
expect(res.body).to.have.property('message', 'You must be logged in to do this.');
});
});

(!IS_EE ? describe : describe.skip)('[@getReadReceipts] CE', () => {
it('should fail if there is no enterprise license', async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: 'test' }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
const data = JSON.parse(res.body.message);
expect(data).to.have.property('error').that.is.an('object');
expect(data.error).to.have.property('error', 'error-action-not-allowed');
expect(data.error).to.have.property('message', 'This is an enterprise feature [error-action-not-allowed]');
});
});
});

(IS_EE ? describe : describe.skip)('[@getReadReceipts] EE', () => {
let user = null;
let userCredentials = null;
let room = null;
let firstMessage = null;
let firstThreadMessage = null;

const roomName = `methods-test-channel-${Date.now()}`;
before(async () => {
await updateSetting('Message_Read_Receipt_Enabled', true);
await updateSetting('Message_Read_Receipt_Store_Users', true);

user = await createUser();
userCredentials = await login(user.username, password);
room = (await createRoom({ type: 'p', name: roomName, members: [user.username] })).body.group;
firstMessage = (await sendSimpleMessage({ roomId: room._id })).body.message;
firstThreadMessage = (await sendSimpleMessage({ roomId: room._id, tmid: firstMessage._id })).body.message;
});

after(async () => {
await deleteRoom({ type: 'p', roomId: room._id });
await deleteUser(user);
});

describe('simple message and thread that nobody has read yet', () => {
it("should return only the sender's read receipt for a message sent in the main room", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: firstMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(1);
expect(data.result[0]).to.have.property('userId', credentials['X-User-Id']);
});
});

it("should return only the sender's read receipt for a message sent in a thread", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: firstThreadMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(1);
expect(data.result[0]).to.have.property('userId', credentials['X-User-Id']);
});
});
});

describe('simple message and thread where the room message was read by the invited user but the thread message was not', () => {
before("should read all main room's messages with the invited user", async () => {
await request
.post(methodCall('readMessages'))
.set(userCredentials)
.send({
message: JSON.stringify({
id: 'id',
msg: 'method',
method: 'readMessages',
params: [room._id, true],
}),
});
});

it("should return both the sender's and the invited user's read receipt for a message sent in the main room", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: firstMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(2);

const receiptsUserIds = [data.result[0].userId, data.result[1].userId];
expect(receiptsUserIds).to.have.members([credentials['X-User-Id'], user._id]);
});
});

it("should return only the sender's read receipt for a message sent in a thread", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: firstThreadMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(1);
expect(data.result[0]).to.have.property('userId', credentials['X-User-Id']);
});
});
});

describe('simple message and thread where both was read by the invited user', () => {
before('should read thread messages with the invited user', async () => {
await request
.post(methodCall('getThreadMessages'))
.set(userCredentials)
.send({
message: JSON.stringify({
id: 'id',
msg: 'method',
method: 'getThreadMessages',
params: [
{
tmid: firstMessage._id,
},
],
}),
});
});

it("should return both the sender's and invited user's read receipt for a message sent in a thread", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: firstThreadMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(2);

const receiptsUserIds = [data.result[0].userId, data.result[1].userId];
expect(receiptsUserIds).to.have.members([credentials['X-User-Id'], user._id]);
});
});
});

describe('simple message and thread marked as read by the invited user', () => {
let otherMessage = null;
let otherThreadMessage = null;

before('should send another message and create a thread', async () => {
otherMessage = (await sendSimpleMessage({ roomId: room._id })).body.message;
otherThreadMessage = (await sendSimpleMessage({ roomId: room._id, tmid: otherMessage._id })).body.message;
});

before('should mark the thread as read by the invited user', async () => {
await request
.post(methodCall('readThreads'))
.set(userCredentials)
.send({
message: JSON.stringify({
method: 'readThreads',
params: [otherMessage._id],
id: 'id',
msg: 'method',
}),
});
});

it("should return both the sender's and invited user's read receipt for a message sent in the main room", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: otherThreadMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(2);

const receiptsUserIds = [data.result[0].userId, data.result[1].userId];
expect(receiptsUserIds).to.have.members([credentials['X-User-Id'], user._id]);
});
});

it("should return both the sender's and invited user's read receipt for a message sent in a thread", async () => {
await request
.post(methodCall('getReadReceipts'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'getReadReceipts',
params: [{ messageId: otherThreadMessage._id }],
id: 'id',
msg: 'method',
}),
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.a.property('success', true);
expect(res.body).to.have.a.property('message').that.is.a('string');

const data = JSON.parse(res.body.message);
expect(data).to.have.a.property('result').that.is.an('array');
expect(data.result.length).to.equal(2);

const receiptsUserIds = [data.result[0].userId, data.result[1].userId];
expect(receiptsUserIds).to.have.members([credentials['X-User-Id'], user._id]);
});
});
});
});
});

describe('[@getMessages]', () => {
let rid = false;
let firstMessage = false;
Expand Down
Loading