').css('color', 'red').text(' FAILED'));
+ appendToLog($('').text(`${err.stack || err}`));
+ throw err;
+ }
+ $msg.append(' done');
+ await incrementBar();
+ }));
+ require.setGlobalKeyPath('require');
+ delete window.testRunnerRequire;
+ for (const spec of specs) {
+ const desc = makeDesc(spec);
+ const $msg = appendToLog(`Executing ${desc}...`);
+ try {
+ describe(desc, function () {
+ for (const [fn, args] of mochaCalls.get(spec)) window[fn](...args);
+ });
+ } catch (err) {
+ $msg.append($('').css('color', 'red').text(' FAILED'));
+ appendToLog($('').text(`${err.stack || err}`));
+ throw err;
+ }
+ $msg.append(' done');
+ await incrementBar();
+ }
+ $progressArea.remove();
+
+ await helper.init();
+ const grep = getURLParameter('grep');
+ if (grep != null) {
+ mocha.grep(grep);
+ }
+ const runner = mocha.run();
+ customRunner(runner);
+})());
diff --git a/src/tests/frontend/specs/alphabet.js b/src/tests/frontend/specs/alphabet.js
index 158bc734cb8..999cfdf3a24 100644
--- a/src/tests/frontend/specs/alphabet.js
+++ b/src/tests/frontend/specs/alphabet.js
@@ -4,13 +4,11 @@ describe('All the alphabet works n stuff', function () {
const expectedString = 'abcdefghijklmnopqrstuvwxyz';
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
it('when you enter any char it appears right', function (done) {
- this.timeout(250);
const inner$ = helper.padInner$;
// get the first text element out of the inner iframe
diff --git a/src/tests/frontend/specs/authorship_of_editions.js b/src/tests/frontend/specs/authorship_of_editions.js
index f6f29d49140..9fd90ffb7a5 100644
--- a/src/tests/frontend/specs/authorship_of_editions.js
+++ b/src/tests/frontend/specs/authorship_of_editions.js
@@ -6,71 +6,61 @@ describe('author of pad edition', function () {
const LINE_WITH_UNORDERED_LIST = 2;
// author 1 creates a new pad with some content (regular lines and lists)
- before(function (done) {
- const padId = helper.newPad(() => {
- // make sure pad has at least 3 lines
- const $firstLine = helper.padInner$('div').first();
- const threeLines = ['regular line', 'line with ordered list', 'line with unordered list']
- .join('
');
- $firstLine.html(threeLines);
-
- // wait for lines to be processed by Etherpad
- helper.waitFor(() => {
- const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
- return $lineWithUnorderedList.text() === 'line with unordered list';
- }).done(() => {
- // create the unordered list
- const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
- $lineWithUnorderedList.sendkeys('{selectall}');
-
- const $insertUnorderedListButton = helper.padChrome$('.buttonicon-insertunorderedlist');
- $insertUnorderedListButton.click();
-
- helper.waitFor(() => {
- const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
- return $lineWithUnorderedList.find('ul li').length === 1;
- }).done(() => {
- // create the ordered list
- const $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
- $lineWithOrderedList.sendkeys('{selectall}');
-
- const $insertOrderedListButton = helper.padChrome$('.buttonicon-insertorderedlist');
- $insertOrderedListButton.click();
-
- helper.waitFor(() => {
- const $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
- return $lineWithOrderedList.find('ol li').length === 1;
- }).done(() => {
- // Reload pad, to make changes as a second user. Need a timeout here to make sure
- // all changes were saved before reloading
- setTimeout(() => {
- // Expire cookie, so author is changed after reloading the pad.
- // See https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_4_Reset_the_previous_cookie
- helper.padChrome$.document.cookie =
- 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
-
- helper.newPad(done, padId);
- }, 1000);
- });
- });
- });
- });
- this.timeout(60000);
+ before(async function () {
+ const padId = await helper.aNewPad();
+
+ // make sure pad has at least 3 lines
+ const $firstLine = helper.padInner$('div').first();
+ const threeLines = ['regular line', 'line with ordered list', 'line with unordered list']
+ .join('
');
+ $firstLine.html(threeLines);
+
+ // wait for lines to be processed by Etherpad
+ await helper.waitForPromise(() => (
+ getLine(LINE_WITH_UNORDERED_LIST).text() === 'line with unordered list' &&
+ helper.commits.length === 1));
+
+ // create the unordered list
+ const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
+ $lineWithUnorderedList.sendkeys('{selectall}');
+
+ const $insertUnorderedListButton = helper.padChrome$('.buttonicon-insertunorderedlist');
+ $insertUnorderedListButton.click();
+
+ await helper.waitForPromise(() => (
+ getLine(LINE_WITH_UNORDERED_LIST).find('ul li').length === 1 &&
+ helper.commits.length === 2));
+
+ // create the ordered list
+ const $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
+ $lineWithOrderedList.sendkeys('{selectall}');
+
+ const $insertOrderedListButton = helper.padChrome$('.buttonicon-insertorderedlist');
+ $insertOrderedListButton.click();
+
+ await helper.waitForPromise(() => (
+ getLine(LINE_WITH_ORDERED_LIST).find('ol li').length === 1 &&
+ helper.commits.length === 3));
+
+ // Expire cookie, so author is changed after reloading the pad.
+ const {Cookies} = helper.padChrome$.window.require('ep_etherpad-lite/static/js/pad_utils');
+ Cookies.remove('token');
+
+ // Reload pad, to make changes as a second user.
+ await helper.aNewPad({id: padId});
});
// author 2 makes some changes on the pad
- it('marks only the new content as changes of the second user on a regular line', function (done) {
- changeLineAndCheckOnlyThatChangeIsFromThisAuthor(REGULAR_LINE, 'x', done);
+ it('regular line', async function () {
+ await changeLineAndCheckOnlyThatChangeIsFromThisAuthor(REGULAR_LINE, 'x');
});
- it('marks only the new content as changes of the second user on a ' +
- 'line with ordered list', function (done) {
- changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_ORDERED_LIST, 'y', done);
+ it('line with ordered list', async function () {
+ await changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_ORDERED_LIST, 'y');
});
- it('marks only the new content as changes of the second user on ' +
- 'a line with unordered list', function (done) {
- changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_UNORDERED_LIST, 'z', done);
+ it('line with unordered list', async function () {
+ await changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_UNORDERED_LIST, 'z');
});
/* ********************** Helper functions ************************ */
@@ -78,7 +68,7 @@ describe('author of pad edition', function () {
const getAuthorFromClassList = (classes) => classes.find((cls) => cls.startsWith('author'));
- const changeLineAndCheckOnlyThatChangeIsFromThisAuthor = (lineNumber, textChange, done) => {
+ const changeLineAndCheckOnlyThatChangeIsFromThisAuthor = async (lineNumber, textChange) => {
// get original author class
const classes = getLine(lineNumber).find('span').first().attr('class').split(' ');
const originalAuthor = getAuthorFromClassList(classes);
@@ -90,18 +80,16 @@ describe('author of pad edition', function () {
// wait for change to be processed by Etherpad
let otherAuthorsOfLine;
- helper.waitFor(() => {
+ await helper.waitForPromise(() => {
const authorsOfLine = getLine(lineNumber).find('span').map(function () {
return getAuthorFromClassList($(this).attr('class').split(' '));
}).get();
otherAuthorsOfLine = authorsOfLine.filter((author) => author !== originalAuthor);
const lineHasChangeOfThisAuthor = otherAuthorsOfLine.length > 0;
return lineHasChangeOfThisAuthor;
- }).done(() => {
- const thisAuthor = otherAuthorsOfLine[0];
- const $changeOfThisAuthor = getLine(lineNumber).find(`span.${thisAuthor}`);
- expect($changeOfThisAuthor.text()).to.be(textChange);
- done();
});
+ const thisAuthor = otherAuthorsOfLine[0];
+ const $changeOfThisAuthor = getLine(lineNumber).find(`span.${thisAuthor}`);
+ expect($changeOfThisAuthor.text()).to.be(textChange);
};
});
diff --git a/src/tests/frontend/specs/bold.js b/src/tests/frontend/specs/bold.js
index 7aac2e36e4b..51655588df7 100644
--- a/src/tests/frontend/specs/bold.js
+++ b/src/tests/frontend/specs/bold.js
@@ -2,13 +2,11 @@
describe('bold button', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
it('makes text bold on click', function (done) {
- this.timeout(200);
const inner$ = helper.padInner$;
const chrome$ = helper.padChrome$;
@@ -37,7 +35,6 @@ describe('bold button', function () {
});
it('makes text bold on keypress', function (done) {
- this.timeout(200);
const inner$ = helper.padInner$;
// get the first text element out of the inner iframe
diff --git a/src/tests/frontend/specs/change_user_color.js b/src/tests/frontend/specs/change_user_color.js
index 1f41dcce239..d8fd976434b 100644
--- a/src/tests/frontend/specs/change_user_color.js
+++ b/src/tests/frontend/specs/change_user_color.js
@@ -2,26 +2,25 @@
describe('change user color', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
it('Color picker matches original color and remembers the user color' +
- ' after a refresh', function (done) {
+ ' after a refresh', async function () {
this.timeout(10000);
- const chrome$ = helper.padChrome$;
+ let chrome$ = helper.padChrome$;
// click on the settings button to make settings visible
- const $userButton = chrome$('.buttonicon-showusers');
+ let $userButton = chrome$('.buttonicon-showusers');
$userButton.click();
- const $userSwatch = chrome$('#myswatch');
+ let $userSwatch = chrome$('#myswatch');
$userSwatch.click();
const fb = chrome$.farbtastic('#colorpicker');
const $colorPickerSave = chrome$('#mycolorpickersave');
- const $colorPickerPreview = chrome$('#mycolorpickerpreview');
+ let $colorPickerPreview = chrome$('#mycolorpickerpreview');
// Same color represented in two different ways
const testColorHash = '#abcdef';
@@ -38,28 +37,25 @@ describe('change user color', function () {
$colorPickerSave.click();
expect($userSwatch.css('background-color')).to.be(testColorRGB);
- setTimeout(() => { // give it a second to save the color on the server side
- helper.newPad({ // get a new pad, but don't clear the cookies
- clearCookies: false,
- cb() {
- const chrome$ = helper.padChrome$;
+ // give it a second to save the color on the server side
+ await new Promise((resolve) => setTimeout(resolve, 1000));
- // click on the settings button to make settings visible
- const $userButton = chrome$('.buttonicon-showusers');
- $userButton.click();
+ // get a new pad, but don't clear the cookies
+ await helper.aNewPad({clearCookies: false});
- const $userSwatch = chrome$('#myswatch');
- $userSwatch.click();
+ chrome$ = helper.padChrome$;
- const $colorPickerPreview = chrome$('#mycolorpickerpreview');
+ // click on the settings button to make settings visible
+ $userButton = chrome$('.buttonicon-showusers');
+ $userButton.click();
- expect($colorPickerPreview.css('background-color')).to.be(testColorRGB);
- expect($userSwatch.css('background-color')).to.be(testColorRGB);
+ $userSwatch = chrome$('#myswatch');
+ $userSwatch.click();
+
+ $colorPickerPreview = chrome$('#mycolorpickerpreview');
- done();
- },
- });
- }, 1000);
+ expect($colorPickerPreview.css('background-color')).to.be(testColorRGB);
+ expect($userSwatch.css('background-color')).to.be(testColorRGB);
});
it('Own user color is shown when you enter a chat', function (done) {
diff --git a/src/tests/frontend/specs/change_user_name.js b/src/tests/frontend/specs/change_user_name.js
index 8ba5e637abb..b146a128146 100644
--- a/src/tests/frontend/specs/change_user_name.js
+++ b/src/tests/frontend/specs/change_user_name.js
@@ -2,32 +2,29 @@
describe('change username value', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
it('Remembers the user name after a refresh', async function () {
- this.timeout(1500);
- helper.toggleUserList();
- helper.setUserName('😃');
-
- helper.newPad({ // get a new pad, but don't clear the cookies
- clearCookies: false,
- cb() {
- helper.toggleUserList();
-
- expect(helper.usernameField().val()).to.be('😃');
- },
- });
+ this.timeout(10000);
+ await helper.toggleUserList();
+ await helper.setUserName('😃');
+ // Give the server an opportunity to write the new name.
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ // get a new pad, but don't clear the cookies
+ await helper.aNewPad({clearCookies: false});
+ await helper.toggleUserList();
+ await helper.waitForPromise(() => helper.usernameField().val() === '😃');
});
it('Own user name is shown when you enter a chat', async function () {
- this.timeout(1500);
- helper.toggleUserList();
- helper.setUserName('😃');
+ this.timeout(10000);
+ await helper.toggleUserList();
+ await helper.setUserName('😃');
- helper.showChat();
- helper.sendChatMessage('O hi{enter}');
+ await helper.showChat();
+ await helper.sendChatMessage('O hi{enter}');
await helper.waitForPromise(() => {
// username:hours:minutes text
diff --git a/src/tests/frontend/specs/chat.js b/src/tests/frontend/specs/chat.js
index be080755ab3..3b1eaebf360 100644
--- a/src/tests/frontend/specs/chat.js
+++ b/src/tests/frontend/specs/chat.js
@@ -2,8 +2,8 @@
describe('Chat messages and UI', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
it('opens chat, sends a message, makes sure it exists ' +
@@ -86,34 +86,27 @@ describe('Chat messages and UI', function () {
});
xit('Checks showChat=false URL Parameter hides chat then' +
- ' when removed it shows chat', function (done) {
- this.timeout(60000);
-
- setTimeout(() => { // give it a second to save the username on the server side
- helper.newPad({ // get a new pad, but don't clear the cookies
- clearCookies: false,
- params: {
- showChat: 'false',
- }, cb() {
- const chrome$ = helper.padChrome$;
- const chaticon = chrome$('#chaticon');
- // chat should be hidden.
- expect(chaticon.is(':visible')).to.be(false);
-
- setTimeout(() => { // give it a second to save the username on the server side
- helper.newPad({ // get a new pad, but don't clear the cookies
- clearCookies: false,
- cb() {
- const chrome$ = helper.padChrome$;
- const chaticon = chrome$('#chaticon');
- // chat should be visible.
- expect(chaticon.is(':visible')).to.be(true);
- done();
- },
- });
- }, 1000);
- },
- });
- }, 3000);
+ ' when removed it shows chat', async function () {
+ // give it a second to save the username on the server side
+ await new Promise((resolve) => setTimeout(resolve, 3000));
+
+ // get a new pad, but don't clear the cookies
+ await helper.aNewPad({clearCookies: false, params: {showChat: 'false'}});
+
+ let chrome$ = helper.padChrome$;
+ let chaticon = chrome$('#chaticon');
+ // chat should be hidden.
+ expect(chaticon.is(':visible')).to.be(false);
+
+ // give it a second to save the username on the server side
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+
+ // get a new pad, but don't clear the cookies
+ await helper.aNewPad({clearCookies: false});
+
+ chrome$ = helper.padChrome$;
+ chaticon = chrome$('#chaticon');
+ // chat should be visible.
+ expect(chaticon.is(':visible')).to.be(true);
});
});
diff --git a/src/tests/frontend/specs/chat_load_messages.js b/src/tests/frontend/specs/chat_load_messages.js
index 6b34e614bd7..d720fbba187 100644
--- a/src/tests/frontend/specs/chat_load_messages.js
+++ b/src/tests/frontend/specs/chat_load_messages.js
@@ -3,9 +3,8 @@
describe('chat-load-messages', function () {
let padName;
- it('creates a pad', function (done) {
- padName = helper.newPad(done);
- this.timeout(60000);
+ it('creates a pad', async function () {
+ padName = await helper.aNewPad();
});
it('adds a lot of messages', async function () {
@@ -15,8 +14,6 @@ describe('chat-load-messages', function () {
const chatInput = chrome$('#chatinput');
const chatText = chrome$('#chattext');
- this.timeout(60000);
-
const messages = 140;
for (let i = 1; i <= messages; i++) {
let num = `${i}`;
@@ -26,7 +23,7 @@ describe('chat-load-messages', function () {
chatInput.sendkeys('{enter}');
await helper.waitForPromise(() => chatText.children('p').length === i);
}
- await new Promise((resolve) => helper.newPad(() => resolve(), padName));
+ await helper.aNewPad({id: padName});
});
it('checks initial message count', function (done) {
diff --git a/src/tests/frontend/specs/clear_authorship_colors.js b/src/tests/frontend/specs/clear_authorship_colors.js
index ae5603949ce..58ce937044a 100644
--- a/src/tests/frontend/specs/clear_authorship_colors.js
+++ b/src/tests/frontend/specs/clear_authorship_colors.js
@@ -2,20 +2,17 @@
describe('clear authorship colors button', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
- it('makes text clear authorship colors', function (done) {
+ it('makes text clear authorship colors', async function () {
this.timeout(2500);
const inner$ = helper.padInner$;
const chrome$ = helper.padChrome$;
// override the confirm dialogue functioon
- helper.padChrome$.window.confirm = function () {
- return true;
- };
+ helper.padChrome$.window.confirm = () => true;
// get the first text element out of the inner iframe
const $firstTextElement = inner$('div').first();
@@ -29,41 +26,31 @@ describe('clear authorship colors button', function () {
$firstTextElement.sendkeys('{rightarrow}');
// wait until we have the full value available
- helper.waitFor(() => inner$('div span').first().attr('class').indexOf('author') !== -1
- ).done(() => {
- // IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
- inner$('div').first().focus();
-
- // get the clear authorship colors button and click it
- const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
- $clearauthorshipcolorsButton.click();
-
- // does the first div include an author class?
- const hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
- expect(hasAuthorClass).to.be(false);
-
- helper.waitFor(() => {
- const disconnectVisible =
- chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
- return (disconnectVisible === true);
- });
-
- const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
- expect(disconnectVisible).to.be(true);
-
- done();
- });
+ await helper.waitForPromise(
+ () => inner$('div span').first().attr('class').indexOf('author') !== -1);
+
+ // IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
+ inner$('div').first().focus();
+
+ // get the clear authorship colors button and click it
+ const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
+ $clearauthorshipcolorsButton.click();
+
+ // does the first div include an author class?
+ const hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
+ expect(hasAuthorClass).to.be(false);
+
+ await helper.waitForPromise(
+ () => chrome$('div.disconnected').attr('class').indexOf('visible') === -1);
});
- it("makes text clear authorship colors and checks it can't be undone", function (done) {
+ it("makes text clear authorship colors and checks it can't be undone", async function () {
this.timeout(1500);
const inner$ = helper.padInner$;
const chrome$ = helper.padChrome$;
// override the confirm dialogue functioon
- helper.padChrome$.window.confirm = function () {
- return true;
- };
+ helper.padChrome$.window.confirm = () => true;
// get the first text element out of the inner iframe
const $firstTextElement = inner$('div').first();
@@ -77,47 +64,38 @@ describe('clear authorship colors button', function () {
$firstTextElement.sendkeys('{rightarrow}');
// wait until we have the full value available
- helper.waitFor(
- () => inner$('div span').first().attr('class').indexOf('author') !== -1
- ).done(() => {
- // IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
- inner$('div').first().focus();
-
- // get the clear authorship colors button and click it
- const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
- $clearauthorshipcolorsButton.click();
-
- // does the first div include an author class?
- let hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
- expect(hasAuthorClass).to.be(false);
-
- const e = new inner$.Event(helper.evtType);
- e.ctrlKey = true; // Control key
- e.which = 90; // z
- inner$('#innerdocbody').trigger(e); // shouldn't od anything
-
- // does the first div include an author class?
- hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
- expect(hasAuthorClass).to.be(false);
-
- // get undo and redo buttons
- const $undoButton = chrome$('.buttonicon-undo');
-
- // click the button
- $undoButton.click(); // shouldn't do anything
- hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
- expect(hasAuthorClass).to.be(false);
-
- helper.waitFor(() => {
- const disconnectVisible =
- chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
- return (disconnectVisible === true);
- });
-
- const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
- expect(disconnectVisible).to.be(true);
-
- done();
- });
+ await helper.waitForPromise(
+ () => inner$('div span').first().attr('class').indexOf('author') !== -1);
+
+ // IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
+ inner$('div').first().focus();
+
+ // get the clear authorship colors button and click it
+ const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
+ $clearauthorshipcolorsButton.click();
+
+ // does the first div include an author class?
+ let hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
+ expect(hasAuthorClass).to.be(false);
+
+ const e = new inner$.Event(helper.evtType);
+ e.ctrlKey = true; // Control key
+ e.which = 90; // z
+ inner$('#innerdocbody').trigger(e); // shouldn't od anything
+
+ // does the first div include an author class?
+ hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
+ expect(hasAuthorClass).to.be(false);
+
+ // get undo and redo buttons
+ const $undoButton = chrome$('.buttonicon-undo');
+
+ // click the button
+ $undoButton.click(); // shouldn't do anything
+ hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
+ expect(hasAuthorClass).to.be(false);
+
+ await helper.waitForPromise(
+ () => chrome$('div.disconnected').attr('class').indexOf('visible') === -1);
});
});
diff --git a/src/tests/frontend/specs/collab_client.js b/src/tests/frontend/specs/collab_client.js
new file mode 100644
index 00000000000..307e379082d
--- /dev/null
+++ b/src/tests/frontend/specs/collab_client.js
@@ -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);
+ });
+});
diff --git a/src/tests/frontend/specs/delete.js b/src/tests/frontend/specs/delete.js
index 1ffbbd51c0d..05164280b4c 100644
--- a/src/tests/frontend/specs/delete.js
+++ b/src/tests/frontend/specs/delete.js
@@ -2,13 +2,11 @@
describe('delete keystroke', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
- it('makes text delete', function (done) {
- this.timeout(50);
+ it('makes text delete', async function () {
const inner$ = helper.padInner$;
// get the first text element out of the inner iframe
@@ -28,7 +26,5 @@ describe('delete keystroke', function () {
// expect it to be one char less in length
expect(newElementLength).to.be((elementLength - 1));
-
- done();
});
});
diff --git a/src/tests/frontend/specs/drag_and_drop.js b/src/tests/frontend/specs/drag_and_drop.js
index 8937b375e63..6d3f5a363b0 100644
--- a/src/tests/frontend/specs/drag_and_drop.js
+++ b/src/tests/frontend/specs/drag_and_drop.js
@@ -2,24 +2,22 @@
// WARNING: drag and drop is only simulated on these tests, manual testing might also be necessary
describe('drag and drop', function () {
- before(function (done) {
- helper.newPad(() => {
- createScriptWithSeveralLines(done);
- });
- this.timeout(60000);
+ before(async function () {
+ await helper.aNewPad();
+ await createScriptWithSeveralLines();
});
context('when user drags part of one line and drops it far form its original place', function () {
- before(function (done) {
+ before(async function () {
selectPartOfSourceLine();
dragSelectedTextAndDropItIntoMiddleOfLine(TARGET_LINE);
// make sure DnD was correctly simulated
- helper.waitFor(() => {
+ await helper.waitForPromise(() => {
const $targetLine = getLine(TARGET_LINE);
const sourceWasMovedToTarget = $targetLine.text() === 'Target line [line 1]';
return sourceWasMovedToTarget;
- }).done(done);
+ });
});
context('and user triggers UNDO', function () {
@@ -30,8 +28,7 @@ describe('drag and drop', function () {
await helper.waitForPromise(() => helper.padInner$('body').html() !== originalHTML);
});
- it('moves text back to its original place', function (done) {
- this.timeout(50);
+ it('moves text back to its original place', async function () {
// test text was removed from drop target
const $targetLine = getLine(TARGET_LINE);
expect($targetLine.text()).to.be('Target line []');
@@ -41,23 +38,21 @@ describe('drag and drop', function () {
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
expect($firstSourceLine.text()).to.be('Source line 1.');
expect($lastSourceLine.text()).to.be('Source line 2.');
-
- done();
});
});
});
context('when user drags some lines far form its original place', function () {
- before(function (done) {
+ before(async function () {
selectMultipleSourceLines();
dragSelectedTextAndDropItIntoMiddleOfLine(TARGET_LINE);
// make sure DnD was correctly simulated
- helper.waitFor(() => {
+ await helper.waitForPromise(() => {
const $lineAfterTarget = getLine(TARGET_LINE + 1);
const sourceWasMovedToTarget = $lineAfterTarget.text() !== '...';
return sourceWasMovedToTarget;
- }).done(done);
+ });
});
context('and user triggers UNDO', function () {
@@ -68,8 +63,7 @@ describe('drag and drop', function () {
await helper.waitForPromise(() => helper.padInner$('body').html() !== originalHTML);
});
- it('moves text back to its original place', function (done) {
- this.timeout(50);
+ it('moves text back to its original place', async function () {
// test text was removed from drop target
const $targetLine = getLine(TARGET_LINE);
expect($targetLine.text()).to.be('Target line []');
@@ -79,8 +73,6 @@ describe('drag and drop', function () {
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
expect($firstSourceLine.text()).to.be('Source line 1.');
expect($lastSourceLine.text()).to.be('Source line 2.');
-
- done();
});
});
});
@@ -94,17 +86,17 @@ describe('drag and drop', function () {
return $lines.slice(lineNumber, lineNumber + 1);
};
- const createScriptWithSeveralLines = (done) => {
+ const createScriptWithSeveralLines = async () => {
// create some lines to be used on the tests
const $firstLine = helper.padInner$('div').first();
$firstLine.html('...
...
Target line []
...
...
' +
'Source line 1.
Source line 2.
');
// wait for lines to be split
- helper.waitFor(() => {
+ await helper.waitForPromise(() => {
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
return $lastSourceLine.text() === 'Source line 2.';
- }).done(done);
+ });
};
const selectPartOfSourceLine = () => {
diff --git a/src/tests/frontend/specs/embed_value.js b/src/tests/frontend/specs/embed_value.js
index 74c8d5ddca1..e92d070a740 100644
--- a/src/tests/frontend/specs/embed_value.js
+++ b/src/tests/frontend/specs/embed_value.js
@@ -50,14 +50,12 @@ describe('embed links', function () {
describe('read and write', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
describe('the share link', function () {
- it('is the actual pad url', function (done) {
- this.timeout(100);
+ it('is the actual pad url', async function () {
const chrome$ = helper.padChrome$;
// open share dropdown
@@ -67,14 +65,11 @@ describe('embed links', function () {
const shareLink = chrome$('#linkinput').val();
const padURL = chrome$.window.location.href;
expect(shareLink).to.be(padURL);
-
- done();
});
});
describe('the embed as iframe code', function () {
- it('is an iframe with the the correct url parameters and correct size', function (done) {
- this.timeout(50);
+ it('is an iframe with the the correct url parameters and correct size', async function () {
const chrome$ = helper.padChrome$;
// open share dropdown
@@ -84,21 +79,17 @@ describe('embed links', function () {
const embedCode = chrome$('#embedinput').val();
checkiFrameCode(embedCode, false);
-
- done();
});
});
});
describe('when read only option is set', function () {
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
describe('the share link', function () {
- it('shows a read only url', function (done) {
- this.timeout(50);
+ it('shows a read only url', async function () {
const chrome$ = helper.padChrome$;
// open share dropdown
@@ -110,14 +101,11 @@ describe('embed links', function () {
const shareLink = chrome$('#linkinput').val();
const containsReadOnlyLink = shareLink.indexOf('r.') > 0;
expect(containsReadOnlyLink).to.be(true);
-
- done();
});
});
describe('the embed as iframe code', function () {
- it('is an iframe with the the correct url parameters and correct size', function (done) {
- this.timeout(50);
+ it('is an iframe with the the correct url parameters and correct size', async function () {
const chrome$ = helper.padChrome$;
// open share dropdown
@@ -131,8 +119,6 @@ describe('embed links', function () {
const embedCode = chrome$('#embedinput').val();
checkiFrameCode(embedCode, true);
-
- done();
});
});
});
diff --git a/src/tests/frontend/specs/enter.js b/src/tests/frontend/specs/enter.js
index 69cd9d48ad6..a32a90c6ea2 100644
--- a/src/tests/frontend/specs/enter.js
+++ b/src/tests/frontend/specs/enter.js
@@ -2,11 +2,11 @@
describe('enter keystroke', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
- it('creates a new line & puts cursor onto a new line', function (done) {
+
+ it('creates a new line & puts cursor onto a new line', async function () {
this.timeout(2000);
const inner$ = helper.padInner$;
@@ -19,14 +19,13 @@ describe('enter keystroke', function () {
// simulate key presses to enter content
$firstTextElement.sendkeys('{enter}');
- helper.waitFor(() => inner$('div').first().text() === '').done(() => {
- const $newSecondLine = inner$('div').first().next();
- const newFirstTextElementValue = inner$('div').first().text();
- expect(newFirstTextElementValue).to.be(''); // expect the first line to be blank
- // expect the second line to be the same as the original first line.
- expect($newSecondLine.text()).to.be(originalTextValue);
- done();
- });
+ await helper.waitForPromise(() => inner$('div').first().text() === '');
+
+ const $newSecondLine = inner$('div').first().next();
+ const newFirstTextElementValue = inner$('div').first().text();
+ expect(newFirstTextElementValue).to.be(''); // expect the first line to be blank
+ // expect the second line to be the same as the original first line.
+ expect($newSecondLine.text()).to.be(originalTextValue);
});
it('enter is always visible after event', async function () {
diff --git a/src/tests/frontend/specs/font_type.js b/src/tests/frontend/specs/font_type.js
index 9790873b374..fbebcdfd742 100644
--- a/src/tests/frontend/specs/font_type.js
+++ b/src/tests/frontend/specs/font_type.js
@@ -2,13 +2,11 @@
describe('font select', function () {
// create a new pad before each test run
- beforeEach(function (cb) {
- helper.newPad(cb);
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
- it('makes text RobotoMono', function (done) {
- this.timeout(100);
+ it('makes text RobotoMono', async function () {
const inner$ = helper.padInner$;
const chrome$ = helper.padChrome$;
@@ -29,7 +27,5 @@ describe('font select', function () {
const fontFamily = inner$('body').css('font-family').toLowerCase();
const containsStr = fontFamily.indexOf('robotomono');
expect(containsStr).to.not.be(-1);
-
- done();
});
});
diff --git a/src/tests/frontend/specs/helper.js b/src/tests/frontend/specs/helper.js
index fdd896ea95c..0d876b33659 100644
--- a/src/tests/frontend/specs/helper.js
+++ b/src/tests/frontend/specs/helper.js
@@ -2,42 +2,24 @@
describe('the test helper', function () {
describe('the newPad method', function () {
- xit("doesn't leak memory if you creates iframes over and over again", function (done) {
+ xit("doesn't leak memory if you creates iframes over and over again", async function () {
this.timeout(100000);
-
- let times = 10;
-
- const loadPad = () => {
- helper.newPad(() => {
- times--;
- if (times > 0) {
- loadPad();
- } else {
- done();
- }
- });
- };
-
- loadPad();
+ for (let i = 0; i < 10; ++i) await helper.aNewPad();
});
- it('gives me 3 jquery instances of chrome, outer and inner', function (done) {
+ it('gives me 3 jquery instances of chrome, outer and inner', async function () {
this.timeout(10000);
-
- helper.newPad(() => {
- // check if the jquery selectors have the desired elements
- expect(helper.padChrome$('#editbar').length).to.be(1);
- expect(helper.padOuter$('#outerdocbody').length).to.be(1);
- expect(helper.padInner$('#innerdocbody').length).to.be(1);
-
- // check if the document object was set correctly
- expect(helper.padChrome$.window.document).to.be(helper.padChrome$.document);
- expect(helper.padOuter$.window.document).to.be(helper.padOuter$.document);
- expect(helper.padInner$.window.document).to.be(helper.padInner$.document);
-
- done();
- });
+ await helper.aNewPad();
+ // check if the jquery selectors have the desired elements
+ expect(helper.padChrome$('#editbar').length).to.be(1);
+ expect(helper.padOuter$('#outerdocbody').length).to.be(1);
+ expect(helper.padInner$('#innerdocbody').length).to.be(1);
+ // check if the document object was set correctly
+ expect(helper.padChrome$.window.document).to.be(helper.padChrome$.document);
+ expect(helper.padOuter$.window.document).to.be(helper.padOuter$.document);
+ expect(helper.padInner$.window.document).to.be(helper.padInner$.document);
});
+
// Make sure the cookies are cleared, and make sure that the cookie
// clearing has taken effect at this point in the code. It has been
// observed that the former can happen without the latter if there
@@ -45,88 +27,75 @@ describe('the test helper', function () {
// However this doesn't seem to always be easily replicated, so this
// timeout may or may end up in the code. None the less, we test here
// to catch it if the bug comes up again.
- it('clears cookies', function (done) {
- this.timeout(60000);
-
+ it('clears cookies', async function () {
// set cookies far into the future to make sure they're not expired yet
- window.document.cookie = 'token=foo;expires=Thu, 01 Jan 3030 00:00:00 GMT; path=/';
- window.document.cookie = 'language=bar;expires=Thu, 01 Jan 3030 00:00:00 GMT; path=/';
+ window.Cookies.set('token', 'foo', {expires: 7 /* days */});
+ window.Cookies.set('language', 'bar', {expires: 7 /* days */});
expect(window.document.cookie).to.contain('token=foo');
expect(window.document.cookie).to.contain('language=bar');
- helper.newPad(() => {
- // helper function seems to have cleared cookies
- // NOTE: this doesn't yet mean it's proven to have taken effect by this point in execution
- const firstCookie = window.document.cookie;
- expect(firstCookie).to.not.contain('token=foo');
- expect(firstCookie).to.not.contain('language=bar');
+ await helper.aNewPad();
- const chrome$ = helper.padChrome$;
+ // helper function seems to have cleared cookies
+ // NOTE: this doesn't yet mean it's proven to have taken effect by this point in execution
+ const firstCookie = window.document.cookie;
+ expect(window.Cookies.get('token')).to.not.be('foo');
+ expect(window.Cookies.get('language') == null).to.be(true);
- // click on the settings button to make settings visible
- const $userButton = chrome$('.buttonicon-showusers');
- $userButton.click();
+ let chrome$ = helper.padChrome$;
- const $usernameInput = chrome$('#myusernameedit');
- $usernameInput.click();
+ // click on the settings button to make settings visible
+ let $userButton = chrome$('.buttonicon-showusers');
+ $userButton.click();
- $usernameInput.val('John McLear');
- $usernameInput.blur();
+ let $usernameInput = chrome$('#myusernameedit');
+ $usernameInput.click();
- // Before refreshing, make sure the name is there
- expect($usernameInput.val()).to.be('John McLear');
+ $usernameInput.val('John McLear');
+ $usernameInput.blur();
- // Now that we have a chrome, we can set a pad cookie
- // so we can confirm it gets wiped as well
- chrome$.document.cookie = 'prefsHtml=baz;expires=Thu, 01 Jan 3030 00:00:00 GMT';
- expect(chrome$.document.cookie).to.contain('prefsHtml=baz');
+ // Before refreshing, make sure the name is there
+ expect($usernameInput.val()).to.be('John McLear');
- // Cookies are weird. Because it's attached to chrome$ (as helper.setPadCookies does)
- // AND we didn't put path=/, we shouldn't expect it to be visible on
- // window.document.cookie. Let's just be sure.
- expect(window.document.cookie).to.not.contain('prefsHtml=baz');
+ // Now that we have a chrome, we can set a pad cookie
+ // so we can confirm it gets wiped as well
+ const getPadcookie =
+ () => helper.padChrome$.window.require('ep_etherpad-lite/static/js/pad_cookie').padcookie;
+ let padcookie = getPadcookie();
+ padcookie.clear();
+ padcookie.setPref('foo', 'bar');
+ expect(padcookie.getPref('foo')).to.be('bar');
- setTimeout(() => { // give it a second to save the username on the server side
- helper.newPad(() => { // get a new pad, let it clear the cookies
- const chrome$ = helper.padChrome$;
+ // give it a second to save the username on the server side
+ await new Promise((resolve) => setTimeout(resolve, 1000));
- // helper function seems to have cleared cookies
- // NOTE: this doesn't yet mean cookies were cleared effectively.
- // We still need to test below that we're in a new session
- expect(window.document.cookie).to.not.contain('token=foo');
- expect(window.document.cookie).to.not.contain('language=bar');
- expect(chrome$.document.cookie).to.contain('prefsHtml=baz');
- expect(window.document.cookie).to.not.contain('prefsHtml=baz');
+ await helper.aNewPad(); // get a new pad, let it clear the cookies
+ chrome$ = helper.padChrome$;
+ padcookie = getPadcookie();
- expect(window.document.cookie).to.not.be(firstCookie);
+ // helper function seems to have cleared cookies
+ // NOTE: this doesn't yet mean cookies were cleared effectively.
+ // We still need to test below that we're in a new session
+ expect(window.Cookies.get('token')).to.not.be('foo');
+ expect(window.Cookies.get('language') == null).to.be(true);
+ expect(padcookie.getPref('foo') == null).to.be(true);
- // click on the settings button to make settings visible
- const $userButton = chrome$('.buttonicon-showusers');
- $userButton.click();
+ expect(window.document.cookie).to.not.be(firstCookie);
- // confirm that the session was actually cleared
- const $usernameInput = chrome$('#myusernameedit');
- expect($usernameInput.val()).to.be('');
+ // click on the settings button to make settings visible
+ $userButton = chrome$('.buttonicon-showusers');
+ $userButton.click();
- done();
- });
- }, 1000);
- });
+ // confirm that the session was actually cleared
+ $usernameInput = chrome$('#myusernameedit');
+ expect($usernameInput.val()).to.be('');
});
- it('sets pad prefs cookie', function (done) {
- this.timeout(60000);
-
- helper.newPad({
- padPrefs: {foo: 'bar'},
- cb() {
- const chrome$ = helper.padChrome$;
- expect(chrome$.document.cookie).to.contain('prefsHttp=%7B%22');
- expect(chrome$.document.cookie).to.contain('foo%22%3A%22bar');
- done();
- },
- });
+ it('sets pad prefs cookie', async function () {
+ await helper.aNewPad({padPrefs: {foo: 'padPrefs test'}});
+ const {padcookie} = helper.padChrome$.window.require('ep_etherpad-lite/static/js/pad_cookie');
+ expect(padcookie.getPref('foo')).to.be('padPrefs test');
});
});
@@ -266,20 +235,18 @@ describe('the test helper', function () {
.replace(/\s/gi, ' ');
};
- before(function (done) {
- helper.newPad(() => {
- // create some lines to be used on the tests
- const $firstLine = helper.padInner$('div').first();
- $firstLine.sendkeys('{selectall}some{enter}short{enter}lines{enter}to test{enter}{enter}');
-
- // wait for lines to be split
- helper.waitFor(() => {
- const $fourthLine = helper.padInner$('div').eq(3);
- return $fourthLine.text() === 'to test';
- }).done(done);
- });
+ before(async function () {
+ await helper.aNewPad();
+
+ // create some lines to be used on the tests
+ const $firstLine = helper.padInner$('div').first();
+ $firstLine.sendkeys('{selectall}some{enter}short{enter}lines{enter}to test{enter}{enter}');
- this.timeout(60000);
+ // wait for lines to be split
+ await helper.waitForPromise(() => {
+ const $fourthLine = helper.padInner$('div').eq(3);
+ return $fourthLine.text() === 'to test';
+ });
});
it('changes editor selection to be between startOffset of $startLine ' +
@@ -336,7 +303,7 @@ describe('the test helper', function () {
done();
});
- it('ends selection at beginning of $endLine when its offset is zero', function (done) {
+ it('ends selection at beginning of $endLine when its offset is zero', async function () {
const inner$ = helper.padInner$;
const startOffset = 2;
@@ -358,8 +325,6 @@ describe('the test helper', function () {
* how I'm covering it in this test.
*/
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines ');
-
- done();
});
it('selects full line when offset is longer than line content', function (done) {
@@ -390,7 +355,7 @@ describe('the test helper', function () {
});
it('selects all text between beginning of $startLine and end of $endLine ' +
- 'when no offset is provided', function (done) {
+ 'when no offset is provided', async function () {
const inner$ = helper.padInner$;
const $lines = inner$('div');
@@ -410,16 +375,12 @@ describe('the test helper', function () {
*/
expect(cleanText(
selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('short lines to test');
-
- done();
});
});
describe('helper', function () {
- before(function (cb) {
- helper.newPad(() => {
- cb();
- });
+ before(async function () {
+ await helper.aNewPad();
});
it('.textLines() returns the text of the pad as strings', async function () {
diff --git a/src/tests/frontend/specs/importexport.js b/src/tests/frontend/specs/importexport.js
index 73798eca99c..46254bedd34 100644
--- a/src/tests/frontend/specs/importexport.js
+++ b/src/tests/frontend/specs/importexport.js
@@ -499,9 +499,7 @@ describe('importexport.js', function () {
let confirm;
before(async function () {
- this.timeout(60000);
- await new Promise(
- (resolve, reject) => helper.newPad((err) => err != null ? reject(err) : resolve()));
+ await helper.aNewPad();
confirm = helper.padChrome$.window.confirm;
helper.padChrome$.window.confirm = () => true;
// As of 2021-02-22 a mutable FileList cannot be directly created so DataTransfer is used as a
diff --git a/src/tests/frontend/specs/importindents.js b/src/tests/frontend/specs/importindents.js
index eecbbce59aa..0d04d16d449 100644
--- a/src/tests/frontend/specs/importindents.js
+++ b/src/tests/frontend/specs/importindents.js
@@ -1,20 +1,20 @@
'use strict';
describe('import indents functionality', function () {
- beforeEach(function (cb) {
- helper.newPad(cb); // creates a new pad
- this.timeout(60000);
+ beforeEach(async function () {
+ await helper.aNewPad();
});
- function getinnertext() {
+ const getinnertext = () => {
const inner = helper.padInner$;
let newtext = '';
inner('div').each((line, el) => {
newtext += `${el.innerHTML}\n`;
});
return newtext;
- }
- function importrequest(data, importurl, type) {
+ };
+
+ const importrequest = (data, importurl, type) => {
let error;
const result = $.ajax({
url: importurl,
@@ -42,8 +42,9 @@ describe('import indents functionality', function () {
});
expect(error).to.be(undefined);
return result;
- }
- function exportfunc(link) {
+ };
+
+ const exportfunc = (link) => {
const exportresults = [];
$.ajaxSetup({
async: false,
@@ -58,51 +59,72 @@ describe('import indents functionality', function () {
exportresults.push(['txt', data]);
});
return exportresults;
- }
+ };
- xit('import a pad with indents from html', function (done) {
+ xit('import a pad with indents from html', async function () {
const importurl = `${helper.padChrome$.window.location.href}/import`;
- /* eslint-disable-next-line max-len */
- const htmlWithIndents = '
- indent line 1
- indent line 2
- indent2 line 1
- indent2 line 2
';
+ const htmlWithIndents =
+ '- indent line 1
- indent line 2
' +
+ '- indent2 line 1
- indent2 line 2
' +
+ '';
importrequest(htmlWithIndents, importurl, 'html');
- helper.waitFor(() => expect(getinnertext()).to.be(
+ await helper.waitForPromise(() => getinnertext() ===
'\n' +
'\n' +
'\n' +
'\n' +
- '
\n'));
+ '
\n');
const results = exportfunc(helper.padChrome$.window.location.href);
- /* eslint-disable-next-line max-len */
- expect(results[0][1]).to.be('- indent line 1
- indent line 2
- indent2 line 1
- indent2 line 2
');
+ expect(results[0][1]).to.be(
+ '- indent line 1
- indent line 2
' +
+ '- indent2 line 1
- indent2 line 2
');
expect(results[1][1])
.to.be('\tindent line 1\n\tindent line 2\n\t\tindent2 line 1\n\t\tindent2 line 2\n\n');
- done();
});
- xit('import a pad with indented lists and newlines from html', function (done) {
+ xit('import a pad with indented lists and newlines from html', async function () {
const importurl = `${helper.padChrome$.window.location.href}/import`;
- /* eslint-disable-next-line max-len */
- const htmlWithIndents = '
';
+ const htmlWithIndents =
+ '
' +
+ '
' +
+ '- indent 2 times line 2
' +
+ '
';
importrequest(htmlWithIndents, importurl, 'html');
- helper.waitFor(() => expect(getinnertext()).to.be(
+ await helper.waitForPromise(() => getinnertext() ===
'\n' +
'
\n' +
'\n' +
'\n' +
'
\n' +
'\n' +
- '
\n'));
+ '
\n');
const results = exportfunc(helper.padChrome$.window.location.href);
- /* eslint-disable-next-line max-len */
- expect(results[0][1]).to.be('
');
- /* eslint-disable-next-line max-len */
- expect(results[1][1]).to.be('\tindent line 1\n\n\tindent 1 line 2\n\t\tindent 2 times line 1\n\n\t\tindent 2 times line 2\n\n');
- done();
+ expect(results[0][1]).to.be(
+ '
' +
+ '
' +
+ '
');
+ expect(results[1][1]).to.be(
+ '\tindent line 1\n\n\tindent 1 line 2\n\t\tindent 2 times line 1\n\n' +
+ '\t\tindent 2 times line 2\n\n');
});
- xit('import with 8 levels of indents and newlines and attributes from html', function (done) {
+
+ xit('import with 8 levels of indents and newlines and attributes from html', async function () {
const importurl = `${helper.padChrome$.window.location.href}/import`;
- /* eslint-disable-next-line max-len */
- const htmlWithIndents = '
indent4 line 2 bisuindent4 line 2 bs- indent4 line 2 u
uis
';
+ const htmlWithIndents =
+ '
' +
+ '
' +
+ '