mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-05-05 14:47:12 -04:00
Added language test.
This commit is contained in:
parent
0d7bca27c1
commit
129c25073c
8 changed files with 224 additions and 263 deletions
|
@ -128,6 +128,8 @@ export const goToPad = async (page: Page, padId: string) => {
|
||||||
|
|
||||||
|
|
||||||
export const clearPadContent = async (page: Page) => {
|
export const clearPadContent = async (page: Page) => {
|
||||||
|
const body = await getPadBody(page);
|
||||||
|
await body.click();
|
||||||
await page.keyboard.down('Control');
|
await page.keyboard.down('Control');
|
||||||
await page.keyboard.press('A');
|
await page.keyboard.press('A');
|
||||||
await page.keyboard.up('Control');
|
await page.keyboard.up('Control');
|
||||||
|
|
20
src/tests/frontend-new/helper/timeslider.ts
Normal file
20
src/tests/frontend-new/helper/timeslider.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import {Page} from "@playwright/test";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the src-attribute of the main iframe to the timeslider
|
||||||
|
* In case a revision is given, sets the timeslider to this specific revision.
|
||||||
|
* Defaults to going to the last revision.
|
||||||
|
* It waits until the timer is filled with date and time, because it's one of the
|
||||||
|
* last things that happen during timeslider load
|
||||||
|
*
|
||||||
|
* @param page
|
||||||
|
* @param {number} [revision] the optional revision
|
||||||
|
* @returns {Promise}
|
||||||
|
* @todo for some reason this does only work the first time, you cannot
|
||||||
|
* goto rev 0 and then via the same method to rev 5. Use buttons instead
|
||||||
|
*/
|
||||||
|
export const gotoTimeslider = async (page: Page, revision: number): Promise<any> => {
|
||||||
|
let revisionString = Number.isInteger(revision) ? `#${revision}` : '';
|
||||||
|
await page.goto(`${page.url()}/timeslider${revisionString}`);
|
||||||
|
await page.waitForSelector('#timer')
|
||||||
|
};
|
85
src/tests/frontend-new/specs/language.spec.ts
Normal file
85
src/tests/frontend-new/specs/language.spec.ts
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
import {expect, test} from "@playwright/test";
|
||||||
|
import {getPadBody, goToNewPad} from "../helper/padHelper";
|
||||||
|
import {showSettings} from "../helper/settingsHelper";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page, browser })=>{
|
||||||
|
const context = await browser.newContext()
|
||||||
|
await context.clearCookies()
|
||||||
|
await goToNewPad(page);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test.describe('Language select and change', function () {
|
||||||
|
|
||||||
|
// Destroy language cookies
|
||||||
|
test('makes text german', async function ({page}) {
|
||||||
|
// click on the settings button to make settings visible
|
||||||
|
await showSettings(page)
|
||||||
|
|
||||||
|
// click the language button
|
||||||
|
await page.locator('.nice-select').nth(1).locator('.current').click()
|
||||||
|
await page.locator('.nice-select').locator('[data-value=de]').click()
|
||||||
|
//const $language = chrome$('#languagemenu');
|
||||||
|
//const $languageoption = $language.find('[value=de]');
|
||||||
|
|
||||||
|
// select german
|
||||||
|
await page.locator('.buttonicon-bold').evaluate((el) => el.parentElement!.title === 'Fett (Strg-B)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('makes text English', async function ({page}) {
|
||||||
|
|
||||||
|
await showSettings(page)
|
||||||
|
|
||||||
|
// click the language button
|
||||||
|
await page.locator('.nice-select').nth(1).locator('.current').click()
|
||||||
|
await page.locator('.nice-select').locator('[data-value=de]').click()
|
||||||
|
|
||||||
|
// select german
|
||||||
|
await page.locator('.buttonicon-bold').evaluate((el) => el.parentElement!.title === 'Fett (Strg-B)');
|
||||||
|
|
||||||
|
|
||||||
|
// change to english
|
||||||
|
await page.locator('.nice-select').nth(1).locator('.current').click()
|
||||||
|
await page.locator('.nice-select').locator('[data-value=en]').click()
|
||||||
|
|
||||||
|
// check if the language is now English
|
||||||
|
await page.locator('.buttonicon-bold').evaluate((el) => el.parentElement!.title !== 'Fett (Strg-B)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('changes direction when picking an rtl lang', async function ({page}) {
|
||||||
|
|
||||||
|
await showSettings(page)
|
||||||
|
|
||||||
|
// click the language button
|
||||||
|
await page.locator('.nice-select').nth(1).locator('.current').click()
|
||||||
|
await page.locator('.nice-select').locator('[data-value=de]').click()
|
||||||
|
|
||||||
|
// select german
|
||||||
|
await page.locator('.buttonicon-bold').evaluate((el) => el.parentElement!.title === 'Fett (Strg-B)');
|
||||||
|
|
||||||
|
// click the language button
|
||||||
|
await page.locator('.nice-select').nth(1).locator('.current').click()
|
||||||
|
// select arabic
|
||||||
|
// $languageoption.attr('selected','selected'); // Breaks the test..
|
||||||
|
await page.locator('.nice-select').locator('[data-value=ar]').click()
|
||||||
|
|
||||||
|
await page.waitForSelector('html[dir="rtl"]')
|
||||||
|
});
|
||||||
|
|
||||||
|
test('changes direction when picking an ltr lang', async function ({page}) {
|
||||||
|
await showSettings(page)
|
||||||
|
|
||||||
|
|
||||||
|
// change to english
|
||||||
|
await page.locator('.nice-select').nth(1).locator('.current').click()
|
||||||
|
await page.locator('.nice-select').locator('[data-value=en]').click()
|
||||||
|
|
||||||
|
// check if the language is now English
|
||||||
|
await page.locator('.buttonicon-bold').evaluate((el) => el.parentElement!.title !== 'Fett (Strg-B)');
|
||||||
|
|
||||||
|
|
||||||
|
await page.waitForSelector('html[dir="ltr"]')
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
37
src/tests/frontend-new/specs/timeslider.spec.ts
Normal file
37
src/tests/frontend-new/specs/timeslider.spec.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import {expect, test} from "@playwright/test";
|
||||||
|
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page })=>{
|
||||||
|
// create a new pad before each test run
|
||||||
|
await goToNewPad(page);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// deactivated, we need a nice way to get the timeslider, this is ugly
|
||||||
|
test.describe('timeslider button takes you to the timeslider of a pad', function () {
|
||||||
|
|
||||||
|
test('timeslider contained in URL', async function ({page}) {
|
||||||
|
const padBody = await getPadBody(page);
|
||||||
|
await clearPadContent(page)
|
||||||
|
await writeToPad(page, 'Foo'); // send line 1 to the pad
|
||||||
|
|
||||||
|
// get the first text element inside the editable space
|
||||||
|
const $firstTextElement = padBody.locator('div span').first();
|
||||||
|
const originalValue = await $firstTextElement.textContent(); // get the original value
|
||||||
|
await $firstTextElement.click()
|
||||||
|
await writeToPad(page, 'Testing'); // send line 1 to the pad
|
||||||
|
|
||||||
|
const modifiedValue = await $firstTextElement.textContent(); // get the modified value
|
||||||
|
expect(modifiedValue).not.toBe(originalValue); // expect the value to change
|
||||||
|
|
||||||
|
const $timesliderButton = page.locator('.buttonicon-history');
|
||||||
|
await $timesliderButton.click(); // So click the timeslider link
|
||||||
|
|
||||||
|
await page.waitForSelector('#timeslider-wrapper')
|
||||||
|
|
||||||
|
const iFrameURL = page.url(); // get the url
|
||||||
|
const inTimeslider = iFrameURL.indexOf('timeslider') !== -1;
|
||||||
|
|
||||||
|
expect(inTimeslider).toBe(true); // expect the value to change
|
||||||
|
});
|
||||||
|
});
|
80
src/tests/frontend-new/specs/timeslider_follow.spec.ts
Normal file
80
src/tests/frontend-new/specs/timeslider_follow.spec.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
'use strict';
|
||||||
|
import {expect, Page, test} from "@playwright/test";
|
||||||
|
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||||
|
import {gotoTimeslider} from "../helper/timeslider";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page })=>{
|
||||||
|
await goToNewPad(page);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test.describe('timeslider follow', function () {
|
||||||
|
|
||||||
|
// TODO needs test if content is also followed, when user a makes edits
|
||||||
|
// while user b is in the timeslider
|
||||||
|
test("content as it's added to timeslider", async function ({page}) {
|
||||||
|
// 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 writeToPad(page, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
await gotoTimeslider(page,0);
|
||||||
|
expect(page.url()).toContain('#0');
|
||||||
|
|
||||||
|
const originalTop = await page.evaluate(() => {
|
||||||
|
return window.document.querySelector('#innerdocbody')!.getBoundingClientRect().top;
|
||||||
|
});
|
||||||
|
|
||||||
|
// set to follow contents as it arrives
|
||||||
|
await page.check('#options-followContents');
|
||||||
|
await page.click('#playpause_button_icon');
|
||||||
|
|
||||||
|
// wait for the scroll
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
|
||||||
|
const currentOffset = await page.evaluate(() => {
|
||||||
|
return window.document.querySelector('#innerdocbody')!.getBoundingClientRect().top;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
console.log('originalTop', originalTop);
|
||||||
|
console.log('currentOffset', currentOffset);
|
||||||
|
|
||||||
|
expect(currentOffset).toBeLessThan(originalTop);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
test('only to lines that exist in the pad view, regression test for #4389', async function ({page}) {
|
||||||
|
const padBody = await getPadBody(page)
|
||||||
|
await padBody.click()
|
||||||
|
|
||||||
|
await clearPadContent(page)
|
||||||
|
|
||||||
|
await writeToPad(page,'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 padBody.locator('div').nth(40).click();
|
||||||
|
await writeToPad(page, 'Another test line');
|
||||||
|
|
||||||
|
|
||||||
|
await gotoTimeslider(page, 200);
|
||||||
|
|
||||||
|
// set to follow contents as it arrives
|
||||||
|
await page.check('#options-followContents');
|
||||||
|
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
|
||||||
|
const oldYPosition = await page.locator('#editorcontainerbox').evaluate((el) => {
|
||||||
|
return el.scrollTop;
|
||||||
|
})
|
||||||
|
expect(oldYPosition).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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,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;
|
|
||||||
};
|
|
Loading…
Add table
Add a link
Reference in a new issue