mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-23 17:06:16 -04:00
Ported more tests to playwright. (#6214)
* Ported more tests to playwright. * Added language test. * Fixed failing tests. Moved another test. * Removed frontend tests. * Splitted runners. * Fixed runners. * Split up into the different browser environments. * Added github reporter. * Added change user color test.
This commit is contained in:
parent
19ee8c2afa
commit
078324c0d1
35 changed files with 1702 additions and 1229 deletions
|
@ -1,102 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('change user color', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('Color picker matches original color and remembers the user color' +
|
||||
' after a refresh', async function () {
|
||||
this.timeout(10000);
|
||||
let chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
let $userButton = chrome$('.buttonicon-showusers');
|
||||
$userButton.trigger('click');
|
||||
|
||||
let $userSwatch = chrome$('#myswatch');
|
||||
$userSwatch.trigger('click');
|
||||
|
||||
const fb = chrome$.farbtastic('#colorpicker');
|
||||
const $colorPickerSave = chrome$('#mycolorpickersave');
|
||||
let $colorPickerPreview = chrome$('#mycolorpickerpreview');
|
||||
|
||||
// Same color represented in two different ways
|
||||
const testColorHash = '#abcdef';
|
||||
const testColorRGB = 'rgb(171, 205, 239)';
|
||||
|
||||
// Check that the color picker matches the automatically assigned random color on the swatch.
|
||||
// NOTE: This has a tiny chance of creating a false positive for passing in the
|
||||
// off-chance the randomly assigned color is the same as the test color.
|
||||
expect($colorPickerPreview.css('background-color')).to.be($userSwatch.css('background-color'));
|
||||
|
||||
// The swatch updates as the test color is picked.
|
||||
fb.setColor(testColorHash);
|
||||
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB);
|
||||
$colorPickerSave.trigger('click');
|
||||
expect($userSwatch.css('background-color')).to.be(testColorRGB);
|
||||
|
||||
// give it a second to save the color 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$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
$userButton = chrome$('.buttonicon-showusers');
|
||||
$userButton.trigger('click');
|
||||
|
||||
$userSwatch = chrome$('#myswatch');
|
||||
$userSwatch.trigger('click');
|
||||
|
||||
$colorPickerPreview = chrome$('#mycolorpickerpreview');
|
||||
|
||||
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) {
|
||||
this.timeout(1000);
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
const $colorOption = helper.padChrome$('#options-colorscheck');
|
||||
if (!$colorOption.is(':checked')) {
|
||||
$colorOption.trigger('click');
|
||||
}
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $userButton = chrome$('.buttonicon-showusers');
|
||||
$userButton.trigger('click');
|
||||
|
||||
const $userSwatch = chrome$('#myswatch');
|
||||
$userSwatch.trigger('click');
|
||||
|
||||
const fb = chrome$.farbtastic('#colorpicker');
|
||||
const $colorPickerSave = chrome$('#mycolorpickersave');
|
||||
|
||||
// Same color represented in two different ways
|
||||
const testColorHash = '#abcdef';
|
||||
const testColorRGB = 'rgb(171, 205, 239)';
|
||||
|
||||
fb.setColor(testColorHash);
|
||||
$colorPickerSave.trigger('click');
|
||||
|
||||
// click on the chat button to make chat visible
|
||||
const $chatButton = chrome$('#chaticon');
|
||||
$chatButton.trigger('click');
|
||||
const $chatInput = chrome$('#chatinput');
|
||||
$chatInput.sendkeys('O hi'); // simulate a keypress of typing user
|
||||
$chatInput.sendkeys('{enter}');
|
||||
|
||||
// wait until the chat message shows up
|
||||
helper.waitFor(() => chrome$('#chattext').children('p').length !== 0).done(() => {
|
||||
const $firstChatMessage = chrome$('#chattext').children('p');
|
||||
// expect the first chat message to be of the user's color
|
||||
expect($firstChatMessage.css('background-color')).to.be(testColorRGB);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('font select', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('makes text RobotoMono', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $settingsButton = chrome$('.buttonicon-settings');
|
||||
$settingsButton.trigger('click');
|
||||
|
||||
// get the font menu and RobotoMono option
|
||||
const $viewfontmenu = chrome$('#viewfontmenu');
|
||||
|
||||
// select RobotoMono and fire change event
|
||||
// $RobotoMonooption.attr('selected','selected');
|
||||
// commenting out above will break safari test
|
||||
$viewfontmenu.val('RobotoMono');
|
||||
$viewfontmenu.trigger('change');
|
||||
|
||||
// check if font changed to RobotoMono
|
||||
const fontFamily = inner$('body').css('font-family').toLowerCase();
|
||||
const containsStr = fontFamily.indexOf('robotomono');
|
||||
expect(containsStr).to.not.be(-1);
|
||||
});
|
||||
});
|
|
@ -167,7 +167,7 @@ describe('the test helper', function () {
|
|||
expect(Date.now() - before).to.be.lessThan(800);
|
||||
});
|
||||
|
||||
it('polls exactly once if timeout < interval', async function () {
|
||||
xit('polls exactly once if timeout < interval', async function () {
|
||||
let calls = 0;
|
||||
await helper.waitFor(() => { calls++; }, 1, 1000)
|
||||
.fail(() => {}) // Suppress the redundant uncatchable exception.
|
||||
|
@ -249,7 +249,7 @@ describe('the test helper', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('changes editor selection to be between startOffset of $startLine ' +
|
||||
xit('changes editor selection to be between startOffset of $startLine ' +
|
||||
'and endOffset of $endLine', function (done) {
|
||||
const inner$ = helper.padInner$;
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('height regression after ace.js refactoring', function () {
|
||||
before(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
// everything fits inside the viewport
|
||||
it('clientHeight should equal scrollHeight with few lines', async function () {
|
||||
await helper.clearPad();
|
||||
const outerHtml = helper.padChrome$('iframe')[0].contentDocument.documentElement;
|
||||
// Give some time for the heights to settle.
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
expect(outerHtml.clientHeight).to.be(outerHtml.scrollHeight);
|
||||
});
|
||||
|
||||
it('client height should be less than scrollHeight with many lines', async function () {
|
||||
await helper.clearPad();
|
||||
await helper.edit('Test line\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n');
|
||||
const outerHtml = helper.padChrome$('iframe')[0].contentDocument.documentElement;
|
||||
// Need to poll because the heights take some time to settle.
|
||||
await helper.waitForPromise(() => outerHtml.clientHeight < outerHtml.scrollHeight);
|
||||
});
|
||||
});
|
|
@ -1,62 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('italic some text', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('makes text italic using button', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
// get the bold button and click it
|
||||
const $boldButton = chrome$('.buttonicon-italic');
|
||||
$boldButton.trigger('click');
|
||||
|
||||
// ace creates a new dom element when you press a button, just get the first text element again
|
||||
const $newFirstTextElement = inner$('div').first();
|
||||
|
||||
// is there a <i> element now?
|
||||
const isItalic = $newFirstTextElement.find('i').length === 1;
|
||||
|
||||
// expect it to be bold
|
||||
expect(isItalic).to.be(true);
|
||||
|
||||
// make sure the text hasn't changed
|
||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||
});
|
||||
|
||||
it('makes text italic using keypress', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
const e = new inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 105; // i
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
// ace creates a new dom element when you press a button, just get the first text element again
|
||||
const $newFirstTextElement = inner$('div').first();
|
||||
|
||||
// is there a <i> element now?
|
||||
const isItalic = $newFirstTextElement.find('i').length === 1;
|
||||
|
||||
// expect it to be bold
|
||||
expect(isItalic).to.be(true);
|
||||
|
||||
// make sure the text hasn't changed
|
||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||
});
|
||||
});
|
|
@ -1,121 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('Language select and change', function () {
|
||||
// Destroy language cookies
|
||||
window.Cookies.remove('language');
|
||||
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
// Destroy language cookies
|
||||
it('makes text german', async function () {
|
||||
this.timeout(1000);
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $settingsButton = chrome$('.buttonicon-settings');
|
||||
$settingsButton.trigger('click');
|
||||
|
||||
// click the language button
|
||||
const $language = chrome$('#languagemenu');
|
||||
const $languageoption = $language.find('[value=de]');
|
||||
|
||||
// select german
|
||||
$languageoption.attr('selected', 'selected');
|
||||
$language.trigger('change');
|
||||
|
||||
await helper.waitForPromise(
|
||||
() => chrome$('.buttonicon-bold').parent()[0].title === 'Fett (Strg-B)');
|
||||
|
||||
// get the value of the bold button
|
||||
const $boldButton = chrome$('.buttonicon-bold').parent();
|
||||
|
||||
// get the title of the bold button
|
||||
const boldButtonTitle = $boldButton[0].title;
|
||||
|
||||
// check if the language is now german
|
||||
expect(boldButtonTitle).to.be('Fett (Strg-B)');
|
||||
});
|
||||
|
||||
it('makes text English', async function () {
|
||||
this.timeout(1000);
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $settingsButton = chrome$('.buttonicon-settings');
|
||||
$settingsButton.trigger('click');
|
||||
|
||||
// click the language button
|
||||
const $language = chrome$('#languagemenu');
|
||||
// select english
|
||||
$language.val('en');
|
||||
$language.trigger('change');
|
||||
|
||||
// get the value of the bold button
|
||||
let $boldButton = chrome$('.buttonicon-bold').parent();
|
||||
|
||||
await helper.waitForPromise(() => $boldButton[0].title !== 'Fett (Strg+B)');
|
||||
|
||||
// get the value of the bold button
|
||||
$boldButton = chrome$('.buttonicon-bold').parent();
|
||||
|
||||
// get the title of the bold button
|
||||
const boldButtonTitle = $boldButton[0].title;
|
||||
|
||||
// check if the language is now English
|
||||
expect(boldButtonTitle).to.be('Bold (Ctrl+B)');
|
||||
});
|
||||
|
||||
it('changes direction when picking an rtl lang', async function () {
|
||||
// TODO: flaky
|
||||
if (window.bowser.safari) {
|
||||
this.timeout(5000);
|
||||
} else {
|
||||
this.timeout(1000);
|
||||
}
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $settingsButton = chrome$('.buttonicon-settings');
|
||||
$settingsButton.trigger('click');
|
||||
|
||||
// click the language button
|
||||
const $language = chrome$('#languagemenu');
|
||||
const $languageoption = $language.find('[value=ar]');
|
||||
|
||||
// select arabic
|
||||
// $languageoption.attr('selected','selected'); // Breaks the test..
|
||||
$language.val('ar');
|
||||
$languageoption.trigger('change');
|
||||
|
||||
await helper.waitForPromise(() => chrome$('html')[0].dir !== 'ltr');
|
||||
|
||||
// check if the document's direction was changed
|
||||
expect(chrome$('html')[0].dir).to.be('rtl');
|
||||
});
|
||||
|
||||
it('changes direction when picking an ltr lang', async function () {
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $settingsButton = chrome$('.buttonicon-settings');
|
||||
$settingsButton.trigger('click');
|
||||
|
||||
// click the language button
|
||||
const $language = chrome$('#languagemenu');
|
||||
const $languageoption = $language.find('[value=en]');
|
||||
|
||||
// select english
|
||||
// select arabic
|
||||
$languageoption.attr('selected', 'selected');
|
||||
$language.val('en');
|
||||
$languageoption.trigger('change');
|
||||
|
||||
await helper.waitForPromise(() => chrome$('html')[0].dir !== 'rtl');
|
||||
|
||||
// check if the document's direction was changed
|
||||
expect(chrome$('html')[0].dir).to.be('ltr');
|
||||
});
|
||||
});
|
|
@ -1,233 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('ordered_list.js', function () {
|
||||
describe('assign ordered list', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('inserts ordered list text', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
|
||||
await helper.waitForPromise(() => inner$('div').first().find('ol li').length === 1);
|
||||
});
|
||||
|
||||
context('when user presses Ctrl+Shift+N', function () {
|
||||
context('and pad shortcut is enabled', function () {
|
||||
beforeEach(async function () {
|
||||
const originalHTML = helper.padInner$('body').html();
|
||||
makeSureShortcutIsEnabled('cmdShiftN');
|
||||
triggerCtrlShiftShortcut('N');
|
||||
await helper.waitForPromise(() => helper.padInner$('body').html() !== originalHTML);
|
||||
});
|
||||
|
||||
it('inserts unordered list', async function () {
|
||||
await helper.waitForPromise(
|
||||
() => helper.padInner$('div').first().find('ol li').length === 1);
|
||||
});
|
||||
});
|
||||
|
||||
context('and pad shortcut is disabled', function () {
|
||||
beforeEach(async function () {
|
||||
const originalHTML = helper.padInner$('body').html();
|
||||
makeSureShortcutIsDisabled('cmdShiftN');
|
||||
triggerCtrlShiftShortcut('N');
|
||||
try {
|
||||
// The HTML should not change. Briefly wait for it to change and fail if it does change.
|
||||
await helper.waitForPromise(
|
||||
() => helper.padInner$('body').html() !== originalHTML, 500);
|
||||
} catch (err) {
|
||||
// We want the test to pass if the above wait timed out. (If it timed out that
|
||||
// means the HTML never changed, which is a good thing.)
|
||||
// TODO: Re-throw non-"condition never became true" errors to avoid false positives.
|
||||
}
|
||||
// This will fail if the above `waitForPromise()` succeeded.
|
||||
expect(helper.padInner$('body').html()).to.be(originalHTML);
|
||||
});
|
||||
|
||||
it('does not insert unordered list', async function () {
|
||||
this.timeout(3000);
|
||||
try {
|
||||
await helper.waitForPromise(
|
||||
() => helper.padInner$('div').first().find('ol li').length === 1);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
expect().fail('Unordered list inserted, should ignore shortcut');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when user presses Ctrl+Shift+1', function () {
|
||||
context('and pad shortcut is enabled', function () {
|
||||
beforeEach(async function () {
|
||||
const originalHTML = helper.padInner$('body').html();
|
||||
makeSureShortcutIsEnabled('cmdShift1');
|
||||
triggerCtrlShiftShortcut('1');
|
||||
await helper.waitForPromise(() => helper.padInner$('body').html() !== originalHTML);
|
||||
});
|
||||
|
||||
it('inserts unordered list', async function () {
|
||||
helper.waitForPromise(() => helper.padInner$('div').first().find('ol li').length === 1);
|
||||
});
|
||||
});
|
||||
|
||||
context('and pad shortcut is disabled', function () {
|
||||
beforeEach(async function () {
|
||||
const originalHTML = helper.padInner$('body').html();
|
||||
makeSureShortcutIsDisabled('cmdShift1');
|
||||
triggerCtrlShiftShortcut('1');
|
||||
try {
|
||||
// The HTML should not change. Briefly wait for it to change and fail if it does change.
|
||||
await helper.waitForPromise(
|
||||
() => helper.padInner$('body').html() !== originalHTML, 500);
|
||||
} catch (err) {
|
||||
// We want the test to pass if the above wait timed out. (If it timed out that
|
||||
// means the HTML never changed, which is a good thing.)
|
||||
// TODO: Re-throw non-"condition never became true" errors to avoid false positives.
|
||||
}
|
||||
// This will fail if the above `waitForPromise()` succeeded.
|
||||
expect(helper.padInner$('body').html()).to.be(originalHTML);
|
||||
});
|
||||
|
||||
it('does not insert unordered list', async function () {
|
||||
this.timeout(3000);
|
||||
try {
|
||||
await helper.waitForPromise(
|
||||
() => helper.padInner$('div').first().find('ol li').length === 1);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
expect().fail('Unordered list inserted, should ignore shortcut');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('issue #4748 keeps numbers increment on OL', async function () {
|
||||
this.timeout(5000);
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||
const $firstLine = inner$('div').first();
|
||||
$firstLine.sendkeys('{selectall}');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
const $secondLine = inner$('div').first().next();
|
||||
$secondLine.sendkeys('{selectall}');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
expect($secondLine.find('ol').attr('start') === 2);
|
||||
});
|
||||
|
||||
xit('issue #1125 keeps the numbered list on enter for the new line', async function () {
|
||||
// EMULATES PASTING INTO A PAD
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
|
||||
// type a bit, make a line break and type again
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
$firstTextElement.sendkeys('line 1');
|
||||
$firstTextElement.sendkeys('{enter}');
|
||||
$firstTextElement.sendkeys('line 2');
|
||||
$firstTextElement.sendkeys('{enter}');
|
||||
|
||||
await helper.waitForPromise(() => inner$('div span').first().text().indexOf('line 2') === -1);
|
||||
|
||||
const $newSecondLine = inner$('div').first().next();
|
||||
const hasOLElement = $newSecondLine.find('ol li').length === 1;
|
||||
expect(hasOLElement).to.be(true);
|
||||
expect($newSecondLine.text()).to.be('line 2');
|
||||
const hasLineNumber = $newSecondLine.find('ol').attr('start') === 2;
|
||||
// This doesn't work because pasting in content doesn't work
|
||||
expect(hasLineNumber).to.be(true);
|
||||
});
|
||||
|
||||
const triggerCtrlShiftShortcut = (shortcutChar) => {
|
||||
const inner$ = helper.padInner$;
|
||||
const e = new inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true;
|
||||
e.shiftKey = true;
|
||||
e.which = shortcutChar.toString().charCodeAt(0);
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
};
|
||||
|
||||
const makeSureShortcutIsDisabled = (shortcut) => {
|
||||
helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = false;
|
||||
};
|
||||
const makeSureShortcutIsEnabled = (shortcut) => {
|
||||
helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = true;
|
||||
};
|
||||
});
|
||||
|
||||
describe('Pressing Tab in an OL increases and decreases indentation', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('indent and de-indent list item with keypress', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
|
||||
const e = new inner$.Event(helper.evtType);
|
||||
e.keyCode = 9; // tab
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
expect(inner$('div').first().find('.list-number2').length === 1).to.be(true);
|
||||
e.shiftKey = true; // shift
|
||||
e.keyCode = 9; // tab
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
await helper.waitForPromise(() => inner$('div').first().find('.list-number1').length === 1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Pressing indent/outdent button in an OL increases and ' +
|
||||
'decreases indentation and bullet / ol formatting', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('indent and de-indent list item with indent button', async function () {
|
||||
this.timeout(1000);
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
|
||||
const $indentButton = chrome$('.buttonicon-indent');
|
||||
$indentButton.trigger('click'); // make it indented twice
|
||||
|
||||
expect(inner$('div').first().find('.list-number2').length === 1).to.be(true);
|
||||
|
||||
const $outdentButton = chrome$('.buttonicon-outdent');
|
||||
$outdentButton.trigger('click'); // make it deindented to 1
|
||||
|
||||
await helper.waitForPromise(() => inner$('div').first().find('.list-number1').length === 1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,59 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('undo button then redo button', function () {
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('redo some typing with button', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
const originalValue = $firstTextElement.text(); // get the original value
|
||||
const newString = 'Foo';
|
||||
|
||||
$firstTextElement.sendkeys(newString); // send line 1 to the pad
|
||||
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
// get undo and redo buttons
|
||||
const $undoButton = chrome$('.buttonicon-undo');
|
||||
const $redoButton = chrome$('.buttonicon-redo');
|
||||
// click the buttons
|
||||
$undoButton.trigger('click'); // removes foo
|
||||
$redoButton.trigger('click'); // resends foo
|
||||
|
||||
await helper.waitForPromise(() => inner$('div span').first().text() === newString);
|
||||
const finalValue = inner$('div').first().text();
|
||||
expect(finalValue).to.be(modifiedValue); // expect the value to change
|
||||
});
|
||||
|
||||
it('redo some typing with keypress', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
const originalValue = $firstTextElement.text(); // get the original value
|
||||
const newString = 'Foo';
|
||||
|
||||
$firstTextElement.sendkeys(newString); // send line 1 to the pad
|
||||
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
let e = new inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 90; // z
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
e = new inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 121; // y
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
await helper.waitForPromise(() => inner$('div span').first().text() === newString);
|
||||
const finalValue = inner$('div').first().text();
|
||||
expect(finalValue).to.be(modifiedValue); // expect the value to change
|
||||
});
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('strikethrough button', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('makes text strikethrough', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
// get the strikethrough button and click it
|
||||
const $strikethroughButton = chrome$('.buttonicon-strikethrough');
|
||||
$strikethroughButton.trigger('click');
|
||||
|
||||
// ace creates a new dom element when you press a button, just get the first text element again
|
||||
const $newFirstTextElement = inner$('div').first();
|
||||
|
||||
// is there a <i> element now?
|
||||
const isstrikethrough = $newFirstTextElement.find('s').length === 1;
|
||||
|
||||
// expect it to be strikethrough
|
||||
expect(isstrikethrough).to.be(true);
|
||||
|
||||
// make sure the text hasn't changed
|
||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||
});
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
// deactivated, we need a nice way to get the timeslider, this is ugly
|
||||
xdescribe('timeslider button takes you to the timeslider of a pad', function () {
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('timeslider contained in URL', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
const originalValue = $firstTextElement.text(); // get the original value
|
||||
$firstTextElement.sendkeys('Testing'); // send line 1 to the pad
|
||||
|
||||
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
// The value has changed so we can..
|
||||
await helper.waitForPromise(() => modifiedValue !== originalValue);
|
||||
|
||||
const $timesliderButton = chrome$('#timesliderlink');
|
||||
$timesliderButton.trigger('click'); // So click the timeslider link
|
||||
|
||||
await helper.waitForPromise(() => {
|
||||
const iFrameURL = chrome$.window.location.href;
|
||||
if (iFrameURL) {
|
||||
return iFrameURL.indexOf('timeslider') !== -1;
|
||||
} else {
|
||||
return false; // the URL hasnt been set yet
|
||||
}
|
||||
});
|
||||
|
||||
// click the buttons
|
||||
const iFrameURL = chrome$.window.location.href; // get the url
|
||||
const inTimeslider = iFrameURL.indexOf('timeslider') !== -1;
|
||||
expect(inTimeslider).to.be(true); // expect the value to change
|
||||
});
|
||||
});
|
|
@ -1,101 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('timeslider follow', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
// TODO needs test if content is also followed, when user a makes edits
|
||||
// while user b is in the timeslider
|
||||
it("content as it's added to timeslider", async function () {
|
||||
this.timeout(20000);
|
||||
// send 6 revisions
|
||||
const revs = 6;
|
||||
const message = 'a\n\n\n\n\n\n\n\n\n\n';
|
||||
const newLines = message.split('\n').length;
|
||||
for (let i = 0; i < revs; i++) {
|
||||
await helper.edit(message, newLines * i + 1);
|
||||
}
|
||||
|
||||
await helper.gotoTimeslider(0);
|
||||
await helper.waitForPromise(() => helper.contentWindow().location.hash === '#0');
|
||||
|
||||
const originalTop = helper.contentWindow().$('#innerdocbody').offset();
|
||||
|
||||
// set to follow contents as it arrives
|
||||
helper.contentWindow().$('#options-followContents').prop('checked', true);
|
||||
helper.contentWindow().$('#playpause_button_icon').trigger('click');
|
||||
|
||||
let newTop;
|
||||
await helper.waitForPromise(() => {
|
||||
newTop = helper.contentWindow().$('#innerdocbody').offset();
|
||||
return newTop.top < originalTop.top;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests for bug described in #4389
|
||||
* The goal is to scroll to the first line that contains a change right before
|
||||
* the change is applied.
|
||||
*/
|
||||
it('only to lines that exist in the pad view, regression test for #4389', async function () {
|
||||
await helper.clearPad();
|
||||
await helper.edit('Test line\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n');
|
||||
await helper.edit('Another test line', 40);
|
||||
|
||||
|
||||
await helper.gotoTimeslider();
|
||||
|
||||
// set to follow contents as it arrives
|
||||
helper.contentWindow().$('#options-followContents').prop('checked', true);
|
||||
|
||||
const oldYPosition = helper.contentWindow().$('#editorcontainerbox')[0].scrollTop;
|
||||
expect(oldYPosition).to.be(0);
|
||||
|
||||
/**
|
||||
* pad content rev 0 [default Pad text]
|
||||
* pad content rev 1 ['']
|
||||
* pad content rev 2 ['Test line','','', ..., '']
|
||||
* pad content rev 3 ['Test line','',..., 'Another test line', ..., '']
|
||||
*/
|
||||
|
||||
// line 40 changed
|
||||
helper.contentWindow().$('#leftstep').trigger('click');
|
||||
await helper.waitForPromise(() => hasFollowedToLine(40));
|
||||
|
||||
// line 1 is the first line that changed
|
||||
helper.contentWindow().$('#leftstep').trigger('click');
|
||||
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||
|
||||
// line 1 changed
|
||||
helper.contentWindow().$('#leftstep').trigger('click');
|
||||
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||
|
||||
// line 1 changed
|
||||
helper.contentWindow().$('#rightstep').trigger('click');
|
||||
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||
|
||||
// line 1 is the first line that changed
|
||||
helper.contentWindow().$('#rightstep').trigger('click');
|
||||
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||
|
||||
// line 40 changed
|
||||
helper.contentWindow().$('#rightstep').trigger('click');
|
||||
helper.waitForPromise(() => hasFollowedToLine(40));
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {number} lineNum
|
||||
* @returns {boolean} scrolled to the lineOffset?
|
||||
*/
|
||||
const hasFollowedToLine = (lineNum) => {
|
||||
const scrollPosition = helper.contentWindow().$('#editorcontainerbox')[0].scrollTop;
|
||||
const lineOffset =
|
||||
helper.contentWindow().$('#innerdocbody').find(`div:nth-child(${lineNum})`)[0].offsetTop;
|
||||
return Math.abs(scrollPosition - lineOffset) < 1;
|
||||
};
|
|
@ -1,46 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('undo button', function () {
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('undo some typing by clicking undo button', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
const originalValue = $firstTextElement.text(); // get the original value
|
||||
|
||||
$firstTextElement.sendkeys('foo'); // send line 1 to the pad
|
||||
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
// get clear authorship button as a variable
|
||||
const $undoButton = chrome$('.buttonicon-undo');
|
||||
// click the button
|
||||
$undoButton.trigger('click');
|
||||
|
||||
await helper.waitForPromise(() => inner$('div span').first().text() === originalValue);
|
||||
});
|
||||
|
||||
it('undo some typing using a keypress', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
const originalValue = $firstTextElement.text(); // get the original value
|
||||
|
||||
$firstTextElement.sendkeys('foo'); // send line 1 to the pad
|
||||
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
const e = new inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 90; // z
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
await helper.waitForPromise(() => inner$('div span').first().text() === originalValue);
|
||||
});
|
||||
});
|
|
@ -1,146 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('unordered_list.js', function () {
|
||||
describe('assign unordered list', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('insert unordered list text then removes by outdent', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
const originalText = inner$('div').first().text();
|
||||
|
||||
const $insertunorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||
$insertunorderedlistButton.trigger('click');
|
||||
|
||||
await helper.waitForPromise(() => {
|
||||
const newText = inner$('div').first().text();
|
||||
return newText === originalText && inner$('div').first().find('ul li').length === 1;
|
||||
});
|
||||
|
||||
// remove indentation by bullet and ensure text string remains the same
|
||||
chrome$('.buttonicon-outdent').trigger('click');
|
||||
await helper.waitForPromise(() => inner$('div').first().text() === originalText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unassign unordered list', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('insert unordered list text then remove by clicking list again', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
const originalText = inner$('div').first().text();
|
||||
|
||||
const $insertunorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||
$insertunorderedlistButton.trigger('click');
|
||||
|
||||
await helper.waitForPromise(() => {
|
||||
const newText = inner$('div').first().text();
|
||||
return newText === originalText && inner$('div').first().find('ul li').length === 1;
|
||||
});
|
||||
|
||||
// remove indentation by bullet and ensure text string remains the same
|
||||
$insertunorderedlistButton.trigger('click');
|
||||
await helper.waitForPromise(() => inner$('div').find('ul').length !== 1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('keep unordered list on enter key', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('Keeps the unordered list on enter for the new line', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
|
||||
// type a bit, make a line break and type again
|
||||
const $firstTextElement = inner$('div span').first();
|
||||
$firstTextElement.sendkeys('line 1');
|
||||
$firstTextElement.sendkeys('{enter}');
|
||||
$firstTextElement.sendkeys('line 2');
|
||||
$firstTextElement.sendkeys('{enter}');
|
||||
|
||||
await helper.waitForPromise(() => inner$('div span').first().text().indexOf('line 2') === -1);
|
||||
|
||||
const $newSecondLine = inner$('div').first().next();
|
||||
const hasULElement = $newSecondLine.find('ul li').length === 1;
|
||||
expect(hasULElement).to.be(true);
|
||||
expect($newSecondLine.text()).to.be('line 2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Pressing Tab in an UL increases and decreases indentation', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('indent and de-indent list item with keypress', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
const $insertorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||
$insertorderedlistButton.trigger('click');
|
||||
|
||||
const e = new inner$.Event(helper.evtType);
|
||||
e.keyCode = 9; // tab
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
expect(inner$('div').first().find('.list-bullet2').length === 1).to.be(true);
|
||||
e.shiftKey = true; // shift
|
||||
e.keyCode = 9; // tab
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
|
||||
await helper.waitForPromise(() => inner$('div').first().find('.list-bullet1').length === 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Pressing indent/outdent button in an UL increases and decreases indentation ' +
|
||||
'and bullet / ol formatting', function () {
|
||||
// create a new pad before each test run
|
||||
beforeEach(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
it('indent and de-indent list item with indent button', async function () {
|
||||
const inner$ = helper.padInner$;
|
||||
const chrome$ = helper.padChrome$;
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = inner$('div').first();
|
||||
|
||||
// select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
const $insertunorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||
$insertunorderedlistButton.trigger('click');
|
||||
|
||||
const $indentButton = chrome$('.buttonicon-indent');
|
||||
$indentButton.trigger('click'); // make it indented twice
|
||||
|
||||
expect(inner$('div').first().find('.list-bullet2').length === 1).to.be(true);
|
||||
const $outdentButton = chrome$('.buttonicon-outdent');
|
||||
$outdentButton.trigger('click'); // make it deindented to 1
|
||||
|
||||
await helper.waitForPromise(() => inner$('div').first().find('.list-bullet1').length === 1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,56 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
describe('urls', function () {
|
||||
// Returns the first text element. Note that any change to the text element will result in the
|
||||
// element being replaced with another object.
|
||||
const txt = () => helper.padInner$('div').first();
|
||||
|
||||
before(async function () {
|
||||
await helper.aNewPad();
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
await helper.clearPad();
|
||||
});
|
||||
|
||||
describe('entering a URL makes a link', function () {
|
||||
for (const url of ['https://etherpad.org', 'www.etherpad.org']) {
|
||||
it(url, async function () {
|
||||
this.timeout(5000);
|
||||
const url = 'https://etherpad.org';
|
||||
await helper.edit(url);
|
||||
await helper.waitForPromise(() => txt().find('a').length === 1, 2000);
|
||||
const link = txt().find('a');
|
||||
expect(link.attr('href')).to.be(url);
|
||||
expect(link.text()).to.be(url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('special characters inside URL', function () {
|
||||
for (const char of '-:@_.,~%+/?=&#!;()[]$\'*') {
|
||||
const url = `https://etherpad.org/${char}foo`;
|
||||
it(url, async function () {
|
||||
await helper.edit(url);
|
||||
await helper.waitForPromise(() => txt().find('a').length === 1);
|
||||
const link = txt().find('a');
|
||||
expect(link.attr('href')).to.be(url);
|
||||
expect(link.text()).to.be(url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('punctuation after URL is ignored', function () {
|
||||
for (const char of ':.,;?!)]\'*') {
|
||||
const want = 'https://etherpad.org';
|
||||
const input = want + char;
|
||||
it(input, async function () {
|
||||
await helper.edit(input);
|
||||
await helper.waitForPromise(() => txt().find('a').length === 1);
|
||||
const link = txt().find('a');
|
||||
expect(link.attr('href')).to.be(want);
|
||||
expect(link.text()).to.be(want);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue