tests: Add regression tests for character composition race

See: https://github.com/ether/etherpad-lite/issues/4978
This commit is contained in:
Guilherme Goncalves 2021-03-24 17:17:43 -03:00 committed by Richard Hansen
parent 1fdaf95c3b
commit f2034ad368
3 changed files with 250 additions and 0 deletions

View file

@ -0,0 +1,102 @@
'use strict';
describe('Messages in the COLLABROOM', function () {
const user1Text = 'text created by user 1';
const user2Text = 'text created by user 2';
const triggerEvent = (eventName) => {
const event = new helper.padInner$.Event(eventName);
helper.padInner$('#innerdocbody').trigger(event);
};
const replaceLineText = async (lineNumber, newText) => {
const inner$ = helper.padInner$;
// get the line element
const $line = inner$('div').eq(lineNumber);
// simulate key presses to delete content
$line.sendkeys('{selectall}'); // select all
$line.sendkeys('{del}'); // clear the first line
$line.sendkeys(newText); // insert the string
await helper.waitForPromise(() => inner$('div').eq(lineNumber).text() === newText);
};
before(async function () {
this.timeout(10000);
await helper.aNewPad();
await helper.multipleUsers.init();
});
it('bug #4978 regression test', async function () {
// The bug was triggered by receiving a change from another user while simultaneously composing
// a character and waiting for an acknowledgement of a previously sent change.
// User 1 starts sending a change to the server.
let sendStarted;
const finishSend = (() => {
const socketJsonObj = helper.padChrome$.window.pad.socket.json;
const sendBackup = socketJsonObj.send;
let startSend;
sendStarted = new Promise((resolve) => { startSend = resolve; });
let finishSend;
const sendP = new Promise((resolve) => { finishSend = resolve; });
socketJsonObj.send = (...args) => {
startSend();
sendP.then(() => {
socketJsonObj.send = sendBackup;
socketJsonObj.send(...args);
});
};
return finishSend;
})();
await replaceLineText(0, user1Text);
await sendStarted;
// User 1 starts a character composition.
triggerEvent('compositionstart');
// User 1 receives a change from user 2. (User 1 will not incorporate the change until the
// composition is completed.)
const user2ChangeArrivedAtUser1 = new Promise((resolve) => {
const cc = helper.padChrome$.window.pad.collabClient;
const origHM = cc.handleMessageFromServer;
cc.handleMessageFromServer = (evt) => {
if (evt.type === 'COLLABROOM' && evt.data.type === 'NEW_CHANGES') {
cc.handleMessageFromServer = origHM;
resolve();
}
return origHM.call(cc, evt);
};
});
await helper.multipleUsers.performAsOtherUser(async () => await replaceLineText(1, user2Text));
await user2ChangeArrivedAtUser1;
// User 1 finishes sending the change to the server. User 2 should see the changes right away.
finishSend();
await helper.multipleUsers.performAsOtherUser(async () => await helper.waitForPromise(
() => helper.padInner$('div').eq(0).text() === user1Text));
// User 1 finishes the character composition. User 2's change should then become visible.
triggerEvent('compositionend');
await helper.waitForPromise(() => helper.padInner$('div').eq(1).text() === user2Text);
// Users 1 and 2 make some more changes.
await helper.multipleUsers.performAsOtherUser(async () => await replaceLineText(3, user2Text));
await replaceLineText(2, user1Text);
// All changes should appear in both views.
const assertContent = async () => await helper.waitForPromise(() => {
const expectedLines = [
user1Text,
user2Text,
user1Text,
user2Text,
];
return expectedLines.every((txt, i) => helper.padInner$('div').eq(i).text() === txt);
});
await assertContent();
await helper.multipleUsers.performAsOtherUser(assertContent);
});
});