mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-25 09:56:15 -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
103
src/tests/frontend-new/specs/change_user_color.spec.ts
Normal file
103
src/tests/frontend-new/specs/change_user_color.spec.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {goToNewPad, sendChatMessage, showChat} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({page}) => {
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
test.describe('change user color', function () {
|
||||
|
||||
test('Color picker matches original color and remembers the user color after a refresh',
|
||||
async function ({page}) {
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
let $userButton = page.locator('.buttonicon-showusers');
|
||||
await $userButton.click()
|
||||
|
||||
let $userSwatch = page.locator('#myswatch');
|
||||
await $userSwatch.click()
|
||||
// Change the color value of the Farbtastic color picker
|
||||
|
||||
const $colorPickerSave = page.locator('#mycolorpickersave');
|
||||
let $colorPickerPreview = page.locator('#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(await $colorPickerPreview.getAttribute('style')).toContain(await $userSwatch.getAttribute('style'));
|
||||
|
||||
// The swatch updates as the test color is picked.
|
||||
await page.evaluate((testRGBColor) => {
|
||||
document.getElementById('mycolorpickerpreview')!.style.backgroundColor = testRGBColor;
|
||||
}, testColorRGB
|
||||
)
|
||||
|
||||
await $colorPickerSave.click();
|
||||
|
||||
// give it a second to save the color on the server side
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
|
||||
// get a new pad, but don't clear the cookies
|
||||
await goToNewPad(page)
|
||||
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
await $userButton.click()
|
||||
|
||||
await $userSwatch.click()
|
||||
|
||||
|
||||
|
||||
expect(await $colorPickerPreview.getAttribute('style')).toContain(await $userSwatch.getAttribute('style'));
|
||||
});
|
||||
|
||||
test('Own user color is shown when you enter a chat', async function ({page}) {
|
||||
|
||||
const colorOption = page.locator('#options-colorscheck');
|
||||
if (!(await colorOption.isChecked())) {
|
||||
await colorOption.check();
|
||||
}
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
const $userButton = page.locator('.buttonicon-showusers');
|
||||
await $userButton.click()
|
||||
|
||||
const $userSwatch = page.locator('#myswatch');
|
||||
await $userSwatch.click()
|
||||
|
||||
const $colorPickerSave = page.locator('#mycolorpickersave');
|
||||
|
||||
// Same color represented in two different ways
|
||||
const testColorHash = '#abcdef';
|
||||
const testColorRGB = 'rgb(171, 205, 239)';
|
||||
|
||||
// The swatch updates as the test color is picked.
|
||||
await page.evaluate((testRGBColor) => {
|
||||
document.getElementById('mycolorpickerpreview')!.style.backgroundColor = testRGBColor;
|
||||
}, testColorRGB
|
||||
)
|
||||
|
||||
|
||||
await $colorPickerSave.click();
|
||||
// click on the chat button to make chat visible
|
||||
await showChat(page)
|
||||
await sendChatMessage(page, 'O hi');
|
||||
|
||||
// wait until the chat message shows up
|
||||
const chatP = page.locator('#chattext').locator('p')
|
||||
const chatText = await chatP.innerText();
|
||||
|
||||
expect(chatText).toContain('O hi');
|
||||
|
||||
const color = await chatP.evaluate((el) => {
|
||||
return window.getComputedStyle(el).getPropertyValue('background-color');
|
||||
}, chatText);
|
||||
|
||||
expect(color).toBe(testColorRGB);
|
||||
});
|
||||
});
|
|
@ -63,8 +63,7 @@ test.describe('embed links', function () {
|
|||
// create a new pad before each test run
|
||||
await goToNewPad(page);
|
||||
})
|
||||
test.describe('the share link', function () {
|
||||
test('is the actual pad url', async function ({page}) {
|
||||
test('the share link is the actual pad url', async function ({page}) {
|
||||
|
||||
const shareButton = page.locator('.buttonicon-embed')
|
||||
// open share dropdown
|
||||
|
@ -75,10 +74,8 @@ test.describe('embed links', function () {
|
|||
const padURL = page.url();
|
||||
expect(shareLink).toBe(padURL);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('the embed as iframe code', function () {
|
||||
test('is an iframe with the the correct url parameters and correct size', async function ({page}) {
|
||||
test('is an iframe with the the correct url parameters and correct size', async function ({page}) {
|
||||
|
||||
const shareButton = page.locator('.buttonicon-embed')
|
||||
await shareButton.click()
|
||||
|
@ -89,7 +86,6 @@ test.describe('embed links', function () {
|
|||
|
||||
await checkiFrameCode(embedCode, false, page);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('when read only option is set', function () {
|
||||
|
@ -98,8 +94,7 @@ test.describe('embed links', function () {
|
|||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
test.describe('the share link', function () {
|
||||
test('shows a read only url', async function ({page}) {
|
||||
test('the share link shows a read only url', async function ({page}) {
|
||||
|
||||
// open share dropdown
|
||||
const shareButton = page.locator('.buttonicon-embed')
|
||||
|
@ -115,10 +110,8 @@ test.describe('embed links', function () {
|
|||
const containsReadOnlyLink = shareLink.indexOf('r.') > 0;
|
||||
expect(containsReadOnlyLink).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('the embed as iframe code', function () {
|
||||
test('is an iframe with the the correct url parameters and correct size', async function ({page}) {
|
||||
test('the embed as iframe code is an iframe with the the correct url parameters and correct size', async function ({page}) {
|
||||
|
||||
|
||||
// open share dropdown
|
||||
|
@ -139,8 +132,5 @@ test.describe('embed links', function () {
|
|||
|
||||
await checkiFrameCode(embedCode, true, page);
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
|
39
src/tests/frontend-new/specs/font_type.spec.ts
Normal file
39
src/tests/frontend-new/specs/font_type.spec.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {getPadBody, goToNewPad} from "../helper/padHelper";
|
||||
import {showSettings} from "../helper/settingsHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
// create a new pad before each test run
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
|
||||
test.describe('font select', function () {
|
||||
// create a new pad before each test run
|
||||
|
||||
test('makes text RobotoMono', async function ({page}) {
|
||||
// click on the settings button to make settings visible
|
||||
await showSettings(page);
|
||||
|
||||
// get the font menu and RobotoMono option
|
||||
const viewFontMenu = page.locator('#viewfontmenu');
|
||||
|
||||
// select RobotoMono and fire change event
|
||||
// $RobotoMonooption.attr('selected','selected');
|
||||
// commenting out above will break safari test
|
||||
const dropdown = page.locator('.dropdowns-container .dropdown-line .current').nth(0)
|
||||
await dropdown.click()
|
||||
await page.locator('li:text("RobotoMono")').click()
|
||||
|
||||
await viewFontMenu.dispatchEvent('change');
|
||||
const padBody = await getPadBody(page)
|
||||
const color = await padBody.evaluate((e) => {
|
||||
return window.getComputedStyle(e).getPropertyValue("font-family")
|
||||
})
|
||||
|
||||
|
||||
// check if font changed to RobotoMono
|
||||
const containsStr = color.toLowerCase().indexOf('robotomono');
|
||||
expect(containsStr).not.toBe(-1);
|
||||
});
|
||||
});
|
|
@ -25,7 +25,7 @@ test.describe('indentation button', function () {
|
|||
const padBody = await getPadBody(page);
|
||||
await page.locator('.buttonicon-indent').click()
|
||||
|
||||
const uls = padBody.locator('div').first().locator('ul li')
|
||||
const uls = padBody.locator('div').first().locator('ul')
|
||||
await expect(uls).toHaveCount(1);
|
||||
});
|
||||
|
||||
|
|
56
src/tests/frontend-new/specs/inner_height.spec.ts
Normal file
56
src/tests/frontend-new/specs/inner_height.spec.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
test.describe('height regression after ace.js refactoring', function () {
|
||||
|
||||
test('clientHeight should equal scrollHeight with few lines', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
|
||||
const iframe = page.locator('iframe').first()
|
||||
const scrollHeight = await iframe.evaluate((element) => {
|
||||
return element.scrollHeight;
|
||||
})
|
||||
|
||||
const clientHeight = await iframe.evaluate((element) => {
|
||||
return element.clientHeight;
|
||||
})
|
||||
|
||||
|
||||
expect(clientHeight).toEqual(scrollHeight);
|
||||
});
|
||||
|
||||
test('client height should be less than scrollHeight with many lines', 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' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' +
|
||||
'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\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 iframe = page.locator('iframe').first()
|
||||
const scrollHeight = await iframe.evaluate((element) => {
|
||||
return element.scrollHeight;
|
||||
})
|
||||
|
||||
const clientHeight = await iframe.evaluate((element) => {
|
||||
return element.clientHeight;
|
||||
})
|
||||
|
||||
// Need to poll because the heights take some time to settle.
|
||||
expect(clientHeight).toBeLessThanOrEqual(scrollHeight);
|
||||
});
|
||||
});
|
65
src/tests/frontend-new/specs/italic.spec.ts
Normal file
65
src/tests/frontend-new/specs/italic.spec.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
test.describe('italic some text', function () {
|
||||
|
||||
test('makes text italic using button', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
await $firstTextElement.click()
|
||||
await writeToPad(page, 'Foo')
|
||||
|
||||
// select this text element
|
||||
await padBody.click()
|
||||
await page.keyboard.press('Control+A');
|
||||
|
||||
// get the bold button and click it
|
||||
const $boldButton = page.locator('.buttonicon-italic');
|
||||
await $boldButton.click();
|
||||
|
||||
// ace creates a new dom element when you press a button, just get the first text element again
|
||||
const $newFirstTextElement = padBody.locator('div').first();
|
||||
|
||||
// is there a <i> element now?
|
||||
// expect it to be italic
|
||||
await expect($newFirstTextElement.locator('i')).toHaveCount(1);
|
||||
|
||||
|
||||
// make sure the text hasn't changed
|
||||
expect(await $newFirstTextElement.textContent()).toEqual(await $firstTextElement.textContent());
|
||||
});
|
||||
|
||||
test('makes text italic using keypress', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
|
||||
// select this text element
|
||||
await writeToPad(page, 'Foo')
|
||||
|
||||
await page.keyboard.press('Control+A');
|
||||
|
||||
await page.keyboard.press('Control+I');
|
||||
|
||||
// ace creates a new dom element when you press a button, just get the first text element again
|
||||
const $newFirstTextElement = padBody.locator('div').first();
|
||||
|
||||
// is there a <i> element now?
|
||||
// expect it to be italic
|
||||
await expect($newFirstTextElement.locator('i')).toHaveCount(1);
|
||||
|
||||
// make sure the text hasn't changed
|
||||
expect(await $newFirstTextElement.textContent()).toBe(await $firstTextElement.textContent());
|
||||
});
|
||||
});
|
88
src/tests/frontend-new/specs/language.spec.ts
Normal file
88
src/tests/frontend-new/specs/language.spec.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
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
|
||||
const languageDropDown = page.locator('.nice-select').nth(1)
|
||||
|
||||
await languageDropDown.click()
|
||||
await page.locator('.nice-select').locator('[data-value=de]').click()
|
||||
await expect(languageDropDown.locator('.current')).toHaveText('Deutsch')
|
||||
|
||||
// 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
|
||||
const languageDropDown = page.locator('.nice-select').nth(1)
|
||||
await languageDropDown.locator('.current').click()
|
||||
await languageDropDown.locator('[data-value=en]').click()
|
||||
|
||||
await expect(languageDropDown.locator('.current')).toHaveText('English')
|
||||
|
||||
// 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"]')
|
||||
|
||||
});
|
||||
});
|
109
src/tests/frontend-new/specs/ordered_list.spec.ts
Normal file
109
src/tests/frontend-new/specs/ordered_list.spec.ts
Normal file
|
@ -0,0 +1,109 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
|
||||
test.describe('ordered_list.js', function () {
|
||||
|
||||
test('issue #4748 keeps numbers increment on OL', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
await writeToPad(page, 'Line 1')
|
||||
await page.keyboard.press('Enter')
|
||||
await writeToPad(page, 'Line 2')
|
||||
|
||||
const $insertorderedlistButton = page.locator('.buttonicon-insertorderedlist')
|
||||
await padBody.locator('div').first().selectText()
|
||||
await $insertorderedlistButton.first().click();
|
||||
|
||||
const secondLine = padBody.locator('div').nth(1)
|
||||
|
||||
await secondLine.selectText()
|
||||
await $insertorderedlistButton.click();
|
||||
|
||||
expect(await secondLine.locator('ol').getAttribute('start')).toEqual('2');
|
||||
});
|
||||
|
||||
test('issue #1125 keeps the numbered list on enter for the new line', async function ({page}) {
|
||||
// EMULATES PASTING INTO A PAD
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
await expect(padBody.locator('div')).toHaveCount(1)
|
||||
const $insertorderedlistButton = page.locator('.buttonicon-insertorderedlist')
|
||||
await $insertorderedlistButton.click();
|
||||
|
||||
// type a bit, make a line break and type again
|
||||
const firstTextElement = padBody.locator('div').first()
|
||||
await firstTextElement.click()
|
||||
await writeToPad(page, 'line 1')
|
||||
await page.keyboard.press('Enter')
|
||||
await writeToPad(page, 'line 2')
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
await expect(padBody.locator('div span').nth(1)).toHaveText('line 2');
|
||||
|
||||
const $newSecondLine = padBody.locator('div').nth(1)
|
||||
expect(await $newSecondLine.locator('ol li').count()).toEqual(1);
|
||||
await expect($newSecondLine.locator('ol li').nth(0)).toHaveText('line 2');
|
||||
const hasLineNumber = await $newSecondLine.locator('ol').getAttribute('start');
|
||||
// This doesn't work because pasting in content doesn't work
|
||||
expect(Number(hasLineNumber)).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Pressing Tab in an OL increases and decreases indentation', function () {
|
||||
|
||||
test('indent and de-indent list item with keypress', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
|
||||
// select this text element
|
||||
await $firstTextElement.selectText()
|
||||
|
||||
const $insertorderedlistButton = page.locator('.buttonicon-insertorderedlist')
|
||||
await $insertorderedlistButton.click()
|
||||
|
||||
await page.keyboard.press('Tab')
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-number2')).toHaveCount(1)
|
||||
|
||||
await page.keyboard.press('Shift+Tab')
|
||||
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-number1')).toHaveCount(1)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test.describe('Pressing indent/outdent button in an OL increases and ' +
|
||||
'decreases indentation and bullet / ol formatting', function () {
|
||||
|
||||
test('indent and de-indent list item with indent button', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
|
||||
// select this text element
|
||||
await $firstTextElement.selectText()
|
||||
|
||||
const $insertorderedlistButton = page.locator('.buttonicon-insertorderedlist')
|
||||
await $insertorderedlistButton.click()
|
||||
|
||||
const $indentButton = page.locator('.buttonicon-indent')
|
||||
await $indentButton.dblclick() // make it indented twice
|
||||
|
||||
const outdentButton = page.locator('.buttonicon-outdent')
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-number3')).toHaveCount(1)
|
||||
|
||||
await outdentButton.click(); // make it deindented to 1
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-number2')).toHaveCount(1)
|
||||
});
|
||||
});
|
65
src/tests/frontend-new/specs/redo.spec.ts
Normal file
65
src/tests/frontend-new/specs/redo.spec.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
|
||||
test.describe('undo button then redo button', function () {
|
||||
|
||||
|
||||
test('redo some typing with button', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
|
||||
// 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
|
||||
const newString = 'Foo';
|
||||
|
||||
await $firstTextElement.focus()
|
||||
expect(await $firstTextElement.textContent()).toContain(originalValue);
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
await writeToPad(page, newString); // 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
|
||||
|
||||
// get undo and redo buttons // click the buttons
|
||||
await page.locator('.buttonicon-undo').click() // removes foo
|
||||
await page.locator('.buttonicon-redo').click() // resends foo
|
||||
|
||||
await expect($firstTextElement).toHaveText(newString);
|
||||
|
||||
const finalValue = await padBody.locator('div').first().textContent();
|
||||
expect(finalValue).toBe(modifiedValue); // expect the value to change
|
||||
});
|
||||
|
||||
test('redo some typing with keypress', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
|
||||
// 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
|
||||
const newString = 'Foo';
|
||||
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
await writeToPad(page, newString); // 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
|
||||
|
||||
// undo the change
|
||||
await padBody.click()
|
||||
await page.keyboard.press('Control+Z');
|
||||
|
||||
await page.keyboard.press('Control+Y'); // redo the change
|
||||
|
||||
|
||||
await expect($firstTextElement).toHaveText(newString);
|
||||
|
||||
const finalValue = await padBody.locator('div').first().textContent();
|
||||
expect(finalValue).toBe(modifiedValue); // expect the value to change
|
||||
});
|
||||
});
|
30
src/tests/frontend-new/specs/strikethrough.spec.ts
Normal file
30
src/tests/frontend-new/specs/strikethrough.spec.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
test.describe('strikethrough button', function () {
|
||||
|
||||
test('makes text strikethrough', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
|
||||
// select this text element
|
||||
await $firstTextElement.selectText()
|
||||
|
||||
// get the strikethrough button and click it
|
||||
await page.locator('.buttonicon-strikethrough').click();
|
||||
|
||||
// ace creates a new dom element when you press a button, just get the first text element again
|
||||
|
||||
// is there a <i> element now?
|
||||
await expect($firstTextElement.locator('s')).toHaveCount(1);
|
||||
|
||||
// make sure the text hasn't changed
|
||||
expect(await $firstTextElement.textContent()).toEqual(await $firstTextElement.textContent());
|
||||
});
|
||||
});
|
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
|
||||
});
|
||||
});
|
76
src/tests/frontend-new/specs/timeslider_follow.spec.ts
Normal file
76
src/tests/frontend-new/specs/timeslider_follow.spec.ts
Normal file
|
@ -0,0 +1,76 @@
|
|||
'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;
|
||||
});
|
||||
|
||||
expect(currentOffset).toBeLessThanOrEqual(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);
|
||||
});
|
||||
});
|
56
src/tests/frontend-new/specs/undo.spec.ts
Normal file
56
src/tests/frontend-new/specs/undo.spec.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
|
||||
test.describe('undo button', function () {
|
||||
|
||||
test('undo some typing by clicking undo button', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const firstTextElement = padBody.locator('div').first()
|
||||
const originalValue = await firstTextElement.textContent(); // get the original value
|
||||
await firstTextElement.focus()
|
||||
|
||||
await writeToPad(page, 'foo'); // 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
|
||||
|
||||
// get clear authorship button as a variable
|
||||
const undoButton = page.locator('.buttonicon-undo')
|
||||
await undoButton.click() // click the button
|
||||
|
||||
await expect(firstTextElement).toHaveText(originalValue!);
|
||||
});
|
||||
|
||||
test('undo some typing using a keypress', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
|
||||
// get the first text element inside the editable space
|
||||
const firstTextElement = padBody.locator('div').first()
|
||||
const originalValue = await firstTextElement.textContent(); // get the original value
|
||||
|
||||
await firstTextElement.focus()
|
||||
await writeToPad(page, 'foo'); // 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
|
||||
|
||||
// undo the change
|
||||
await page.keyboard.press('Control+Z');
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
await expect(firstTextElement).toHaveText(originalValue!);
|
||||
});
|
||||
});
|
127
src/tests/frontend-new/specs/unordered_list.spec.ts
Normal file
127
src/tests/frontend-new/specs/unordered_list.spec.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
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);
|
||||
})
|
||||
|
||||
test.describe('unordered_list.js', function () {
|
||||
test.describe('assign unordered list', function () {
|
||||
test('insert unordered list text then removes by outdent', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
const originalText = await padBody.locator('div').first().textContent();
|
||||
|
||||
const $insertunorderedlistButton = page.locator('.buttonicon-insertunorderedlist');
|
||||
await $insertunorderedlistButton.click();
|
||||
|
||||
await expect(padBody.locator('div').first()).toHaveText(originalText!);
|
||||
await expect(padBody.locator('div ul li')).toHaveCount(1);
|
||||
|
||||
// remove indentation by bullet and ensure text string remains the same
|
||||
const $outdentButton = page.locator('.buttonicon-outdent');
|
||||
await $outdentButton.click();
|
||||
await expect(padBody.locator('div').first()).toHaveText(originalText!);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('unassign unordered list', function () {
|
||||
// create a new pad before each test run
|
||||
|
||||
|
||||
test('insert unordered list text then remove by clicking list again', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
const originalText = await padBody.locator('div').first().textContent();
|
||||
|
||||
await padBody.locator('div').first().selectText()
|
||||
const $insertunorderedlistButton = page.locator('.buttonicon-insertunorderedlist');
|
||||
await $insertunorderedlistButton.click();
|
||||
|
||||
await expect(padBody.locator('div').first()).toHaveText(originalText!);
|
||||
await expect(padBody.locator('div ul li')).toHaveCount(1);
|
||||
|
||||
// remove indentation by bullet and ensure text string remains the same
|
||||
await $insertunorderedlistButton.click();
|
||||
await expect(padBody.locator('div').locator('ul')).toHaveCount(0)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test.describe('keep unordered list on enter key', function () {
|
||||
|
||||
test('Keeps the unordered list on enter for the new line', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
await expect(padBody.locator('div')).toHaveCount(1)
|
||||
|
||||
const $insertorderedlistButton = page.locator('.buttonicon-insertunorderedlist')
|
||||
await $insertorderedlistButton.click();
|
||||
|
||||
// type a bit, make a line break and type again
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
await $firstTextElement.click()
|
||||
await page.keyboard.type('line 1');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.type('line 2');
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await expect(padBody.locator('div span')).toHaveCount(2);
|
||||
|
||||
|
||||
const $newSecondLine = padBody.locator('div').nth(1)
|
||||
await expect($newSecondLine.locator('ul')).toHaveCount(1);
|
||||
await expect($newSecondLine).toHaveText('line 2');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Pressing Tab in an UL increases and decreases indentation', function () {
|
||||
|
||||
test('indent and de-indent list item with keypress', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
|
||||
// select this text element
|
||||
await $firstTextElement.selectText();
|
||||
|
||||
const $insertunorderedlistButton = page.locator('.buttonicon-insertunorderedlist');
|
||||
await $insertunorderedlistButton.click();
|
||||
|
||||
await padBody.locator('div').first().click();
|
||||
await page.keyboard.press('Home');
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(padBody.locator('div').first().locator('.list-bullet2')).toHaveCount(1);
|
||||
|
||||
await page.keyboard.press('Shift+Tab');
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-bullet1')).toHaveCount(1);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Pressing indent/outdent button in an UL increases and decreases indentation ' +
|
||||
'and bullet / ol formatting', function () {
|
||||
|
||||
test('indent and de-indent list item with indent button', async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
|
||||
// get the first text element out of the inner iframe
|
||||
const $firstTextElement = padBody.locator('div').first();
|
||||
|
||||
// select this text element
|
||||
await $firstTextElement.selectText();
|
||||
|
||||
const $insertunorderedlistButton = page.locator('.buttonicon-insertunorderedlist');
|
||||
await $insertunorderedlistButton.click();
|
||||
|
||||
await page.locator('.buttonicon-indent').click();
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-bullet2')).toHaveCount(1);
|
||||
const outdentButton = page.locator('.buttonicon-outdent');
|
||||
await outdentButton.click();
|
||||
|
||||
await expect(padBody.locator('div').first().locator('.list-bullet1')).toHaveCount(1);
|
||||
});
|
||||
});
|
||||
});
|
51
src/tests/frontend-new/specs/urls_become_clickable.spec.ts
Normal file
51
src/tests/frontend-new/specs/urls_become_clickable.spec.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import {expect, test} from "@playwright/test";
|
||||
import {clearPadContent, getPadBody, goToNewPad, writeToPad} from "../helper/padHelper";
|
||||
|
||||
test.beforeEach(async ({ page })=>{
|
||||
await goToNewPad(page);
|
||||
})
|
||||
|
||||
test.describe('entering a URL makes a link', function () {
|
||||
for (const url of ['https://etherpad.org', 'www.etherpad.org', 'https://www.etherpad.org']) {
|
||||
test(url, async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
const url = 'https://etherpad.org';
|
||||
await writeToPad(page, url);
|
||||
await expect(padBody.locator('div').first()).toHaveText(url);
|
||||
await expect(padBody.locator('a')).toHaveText(url);
|
||||
await expect(padBody.locator('a')).toHaveAttribute('href', url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test.describe('special characters inside URL', async function () {
|
||||
for (const char of '-:@_.,~%+/?=&#!;()[]$\'*') {
|
||||
const url = `https://etherpad.org/${char}foo`;
|
||||
test(url, async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
await padBody.click()
|
||||
await clearPadContent(page)
|
||||
await writeToPad(page, url);
|
||||
await expect(padBody.locator('div').first()).toHaveText(url);
|
||||
await expect(padBody.locator('a')).toHaveText(url);
|
||||
await expect(padBody.locator('a')).toHaveAttribute('href', url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('punctuation after URL is ignored', ()=> {
|
||||
for (const char of ':.,;?!)]\'*') {
|
||||
const want = 'https://etherpad.org';
|
||||
const input = want + char;
|
||||
test(input, async function ({page}) {
|
||||
const padBody = await getPadBody(page);
|
||||
await clearPadContent(page)
|
||||
await writeToPad(page, input);
|
||||
await expect(padBody.locator('a')).toHaveCount(1);
|
||||
await expect(padBody.locator('a')).toHaveAttribute('href', want);
|
||||
});
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue