403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/ilovecveti.ru/bitrix/js/ui/text-editor/test/e2e/tests/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/ilovecveti.ru/bitrix/js/ui/text-editor/test/e2e/tests/utils.js
import { test as base, expect } from '@playwright/test';
import { defaultTheme } from '../../../src/themes/default-theme';
import { selectAll } from './keyboard';

export const E2E_BROWSER = process.env.E2E_BROWSER;
export const IS_MAC = process.platform === 'darwin';
export const IS_WINDOWS = process.platform === 'win32';
export const IS_LINUX = !IS_MAC && !IS_WINDOWS;

export const test = base.extend({
	isPlainText: false,
	isRichText: true,
});

export { expect } from '@playwright/test';

export async function initializeTest({
	page,
	editorOptions = {},
	demoContent = false,
	lang = 'en',
})
{
	const options = encodeURI(JSON.stringify(editorOptions));
	let url = 'http://localhost/dev/ui/text-editor/e2e/full-featured.php';

	url += `?lang=${lang}`;

	if (demoContent)
	{
		url += '&demoContent=true';
	}

	url += `&editorOptions=${options}`;

	const response = await page.goto(url);
	if (response.status() === 500)
	{
		// eslint-disable-next-line no-param-reassign
		page.__retryCount = typeof(page.__retryCount) === 'undefined' ? 1 : page.__retryCount + 1;

		if (page.__retryCount > 5)
		{
			throw new Error('Too many retries!');
		}
		else
		{
			await initializeTest({ page, editorOptions, demoContent, lang });
		}
	}
}

export async function focusEditor(page)
{
	const editor = await page.locator('[data-lexical-editor="true"]');
	await editor.first().focus();

	return editor;
}

export function stripIndent(source)
{
	return source.replaceAll(/[\t\n]+/gm, '');
}

function wrapAndSlowDown(method, delay)
{
	return async function() {
		await new Promise((resolve) => setTimeout(resolve, delay));

		return method.apply(this, arguments);
	};
}

export async function repeat(times, cb)
{
	for (let i = 0; i < times; i++)
	{
		await cb();
	}
}

export async function clickSelectors(page, selectors)
{
	for (let i = 0; i < selectors.length; i++)
	{
		await click(page, selectors[i]);
	}
}

export async function assertHTML(
	page,
	expectedHtml,
	{ ignoreClasses = false, ignoreInlineStyles = false, preserveTab = false } = {},
	actualHtmlModificationsCallback = (actualHtml) => actualHtml,
)
{
	const expected = prettifyHTML(
		preserveTab ? expectedHtml.replaceAll(/\n+/gm, '') : expectedHtml.replaceAll(/[\t\n]+/gm, ''),
		{
			ignoreClasses,
			ignoreInlineStyles,
		},
	);

	await expect(async () => {
		const actualHtml = await page
			.locator('[data-lexical-editor="true"]')
			.first()
			.innerHTML()
		;

		let actual = prettifyHTML(actualHtml.replaceAll(/\n/gm, ''), { ignoreClasses, ignoreInlineStyles });
		actual = actualHtmlModificationsCallback(actual);

		expect(actual, 'innerHTML of contenteditable in page did not match').toEqual(expected);
	}).toPass({ intervals: [100, 250, 500], timeout: 2000 });
}

export async function assertSelection(page, expected)
{
	// Assert the selection of the editor matches the snapshot
	const selection = await page.evaluate(() => {
		const rootElement = document.querySelector('[data-lexical-editor="true"]');

		const getPathFromNode = (node) => {
			const path = [];
			if (node === rootElement)
			{
				return [];
			}

			while (node !== null)
			{
				const parent = node.parentNode;
				if (parent === null || node === rootElement)
				{
					break;
				}
				path.push([...parent.childNodes].indexOf(node));
				node = parent;
			}

			return path.reverse();
		};

		const { anchorNode, anchorOffset, focusNode, focusOffset } = window.getSelection();

		return {
			anchorOffset,
			anchorPath: getPathFromNode(anchorNode),
			focusOffset,
			focusPath: getPathFromNode(focusNode),
		};
	}, expected);

	expect(selection.anchorPath).toEqual(expected.anchorPath);
	expect(selection.focusPath).toEqual(expected.focusPath);

	if (Array.isArray(expected.anchorOffset))
	{
		const [start, end] = expected.anchorOffset;
		expect(selection.anchorOffset).toBeGreaterThanOrEqual(start);
		expect(selection.anchorOffset).toBeLessThanOrEqual(end);
	}
	else
	{
		expect(selection.anchorOffset).toEqual(expected.anchorOffset);
	}

	if (Array.isArray(expected.focusOffset))
	{
		const [start, end] = expected.focusOffset;
		expect(selection.focusOffset).toBeGreaterThanOrEqual(start);
		expect(selection.focusOffset).toBeLessThanOrEqual(end);
	}
	else
	{
		expect(selection.focusOffset).toEqual(expected.focusOffset);
	}
}

export async function isMac(page)
{
	return page.evaluate(
		() =>
			typeof window !== 'undefined'
			&& /Mac|iPod|iPhone|iPad/.test(window.navigator.platform),
	);
}

export async function supportsBeforeInput(page)
{
	return page.evaluate(() => {
		if ('InputEvent' in window)
		{
			return 'getTargetRanges' in new window.InputEvent('input');
		}

		return false;
	});
}

export async function keyDownCtrlOrMeta(page)
{
	if (await isMac(page))
	{
		await page.keyboard.down('Meta');
	}
	else
	{
		await page.keyboard.down('Control');
	}
}

export async function keyUpCtrlOrMeta(page)
{
	if (await isMac(page))
	{
		await page.keyboard.up('Meta');
	}
	else
	{
		await page.keyboard.up('Control');
	}
}

export async function keyDownCtrlOrAlt(page)
{
	if (await isMac(page))
	{
		await page.keyboard.down('Alt');
	}
	else
	{
		await page.keyboard.down('Control');
	}
}

export async function keyUpCtrlOrAlt(page)
{
	if (await isMac(page))
	{
		await page.keyboard.up('Alt');
	}
	else
	{
		await page.keyboard.up('Control');
	}
}

export async function copyToClipboard(page)
{
	return page.evaluate(() => {
		const clipboardData = {};
		const editor = document.querySelector('[data-lexical-editor="true"]');
		const copyEvent = new ClipboardEvent('copy');
		Object.defineProperty(copyEvent, 'clipboardData', {
			value: {
				setData(type, value)
				{
					clipboardData[type] = value;
				},
			},
		});

		editor.dispatchEvent(copyEvent);

		return clipboardData;
	});
}

async function pasteWithClipboardDataFromPage(page, clipboardData)
{
	const canUseBeforeInput = await supportsBeforeInput(page);

	await page.evaluate(
		async ({
			clipboardData: _clipboardData,
			canUseBeforeInput: _canUseBeforeInput,
		}) => {
			const files = [];
			const items = [];
			for (const [clipboardKey, clipboardValue] of Object.entries(_clipboardData))
			{
				if (clipboardKey.startsWith('playwright/base64'))
				{
					delete _clipboardData[clipboardKey];
					const [base64, type] = clipboardValue;
					const res = await fetch(base64);
					const blob = await res.blob();
					files.push(new File([blob], 'file', { type }));
				}
				else
				{
					items.push({
						type: clipboardKey,
						kind: 'string',
					});
				}
			}

			let eventClipboardData;
			if (files.length > 0)
			{
				eventClipboardData = {
					files,
					getData(type, value)
					{
						return _clipboardData[type];
					},
					types: [...Object.keys(_clipboardData), 'Files'],
					items,
				};
			}
			else
			{
				eventClipboardData = {
					files,
					getData(type, value)
					{
						return _clipboardData[type];
					},
					types: Object.keys(_clipboardData),
					items,
				};
			}

			const editor = document.querySelector('[data-lexical-editor="true"]');
			const pasteEvent = new ClipboardEvent('paste', { bubbles: true, cancelable: true });

			Object.defineProperty(pasteEvent, 'clipboardData', { value: eventClipboardData });
			editor.dispatchEvent(pasteEvent);

			if (!pasteEvent.defaultPrevented && _canUseBeforeInput)
			{
				const inputEvent = new InputEvent('beforeinput', { bubbles: true, cancelable: true });
				Object.defineProperty(inputEvent, 'inputType', { value: 'insertFromPaste' });
				Object.defineProperty(inputEvent, 'dataTransfer', { value: eventClipboardData });
				editor.dispatchEvent(inputEvent);
			}
		},
		{ canUseBeforeInput, clipboardData },
	);
}

/**
 * @param {import('@playwright/test').Page} page
 */
export async function pasteFromClipboard(page, clipboardData)
{
	if (clipboardData === undefined)
	{
		await keyDownCtrlOrMeta(page);
		await page.keyboard.press('v');
		await keyUpCtrlOrMeta(page);

		return;
	}

	await pasteWithClipboardDataFromPage(page, clipboardData);
}

export async function sleep(delay)
{
	await new Promise((resolve) => {
		setTimeout(resolve, delay);
	});
}

// Fair time for the browser to process a newly inserted image
export async function sleepInsertImage(count = 1)
{
	await sleep(1000 * count);
}

export async function getHTML(page, selector = 'div[contenteditable="true"]')
{
	return await locate(page, selector).innerHTML();
}

export async function waitForSelector(page, selector, options)
{
	await page.waitForSelector(selector, options);
}

export function locate(page, selector)
{
	return page.locator(selector);
}

export async function selectorBoundingBox(page, selector)
{
	await locate(page, selector).boundingBox();
}

export async function click(page, selector, options)
{
	const frame = page;
	await frame.waitForSelector(selector, options);
	await frame.click(selector, options);
}

export async function doubleClick(page, selector, options)
{
	const frame = page;
	await frame.waitForSelector(selector, options);
	await frame.dblclick(selector, options);
}

export async function focus(page, selector, options)
{
	await locate(page, selector).focus(options);
}

export async function clearEditor(page)
{
	await selectAll(page);
	await page.keyboard.press('Backspace');
	await page.keyboard.press('Backspace');
}

export async function clickToolbarButton(page, buttonId)
{
	await page.locator(`.ui-text-editor-toolbar-button:has(> .--${buttonId})`).click();
}

export async function insertSampleImage(page)
{
	await clickToolbarButton(page, 'incert-image');

	await page.getByTestId('image-dialog-textbox').fill('https://i.pinimg.com/564x/3d/d8/3f/3dd83fc6cfce54d3ad2bcc992cd5ed18.jpg');
	await page.getByTestId('image-dialog-save-btn').click();

	await waitForSelector(page, `.${defaultTheme.image.img}`);
}

export async function insertYoutubeVideo(page)
{
	await clickToolbarButton(page, 'insert-video');

	await page.getByTestId('video-dialog-textbox').fill('https://www.youtube.com/watch?v=_6j7HRZFXP4');
	await page.getByTestId('video-dialog-save-btn').click();
}

export async function insertTable(page, rows = 2, columns = 3)
{
	await clickToolbarButton(page, 'table-editor');
	await page.locator(`[data-column='${columns}'][data-row='${rows}']`).click();
}

export async function insertCodeBlock(page)
{
	await clickToolbarButton(page, 'enclose-text-in-code-tag');
}

export async function toggleCodeBlock(page)
{
	await clickToolbarButton(page, 'enclose-text-in-code-tag');
}

export async function insertSpoiler(page)
{
	await clickToolbarButton(page, 'insert-spoiler');
}

export async function toggleLink(page, link)
{
	await clickToolbarButton(page, 'link-3');
	await page.getByTestId('link-textbox-input').fill(link);
	await page.getByTestId('save-link-btn').click();
}

export async function mouseMoveToSelector(page, selector)
{
	const { x, width, y, height } = await selectorBoundingBox(page, selector);
	await page.mouse.move(x + width / 2, y + height / 2);
}

export async function dragMouse(
	page,
	fromBoundingBox,
	toBoundingBox,
	positionStart = 'middle',
	positionEnd = 'middle',
	mouseUp = true,
	slow = false,
)
{
	let fromX = fromBoundingBox.x;
	let fromY = fromBoundingBox.y;
	if (positionStart === 'middle')
	{
		fromX += fromBoundingBox.width / 2;
		fromY += fromBoundingBox.height / 2;
	}
	else if (positionStart === 'end')
	{
		fromX += fromBoundingBox.width;
		fromY += fromBoundingBox.height;
	}
	await page.mouse.move(fromX, fromY);
	await page.mouse.down();

	let toX = toBoundingBox.x;
	let toY = toBoundingBox.y;
	if (positionEnd === 'middle')
	{
		toX += toBoundingBox.width / 2;
		toY += toBoundingBox.height / 2;
	}
	else if (positionEnd === 'end')
	{
		toX += toBoundingBox.width;
		toY += toBoundingBox.height;
	}

	if (slow)
	{
		//simulate more than 1 mouse move event to replicate human slow dragging
		await page.mouse.move((fromX + toX) / 2, (fromY + toY) / 2);
	}

	await page.mouse.move(toX, toY);

	if (mouseUp)
	{
		await page.mouse.up();
	}
}

export function prettifyHTML(string, { ignoreClasses, ignoreInlineStyles } = {})
{
	let output = string;

	if (ignoreClasses)
	{
		output = output.replaceAll(/\sclass="([^"]*)"/g, '');
	}

	if (ignoreInlineStyles)
	{
		output = output.replaceAll(/\sstyle="([^"]*)"/g, '');
	}

	output = output.replaceAll(/\sdir="([^"]*)"/g, '');
	output = output.replaceAll(/\sui-text-editor__ltr/g, '');
	output = output.replaceAll(/\sui-text-editor__rtl/g, '');
	output = output.replaceAll(/\sdata-placeholder="([^"]*)"/g, '');
	output = output.replaceAll(/\s__playwright_target__="[^"]+"/g, '');

	return output.trim();
}

export async function enableCompositionKeyEvents(page)
{
	const targetPage = page;
	await targetPage.evaluate(() => {
		window.addEventListener(
			'compositionstart',
			() => {
				document.activeElement.dispatchEvent(
					new KeyboardEvent('keydown', {
						bubbles: true,
						cancelable: true,
						key: 'Unidentified',
						keyCode: 220,
					}),
				);
			},
			true,
		);
	});
}

export async function pressToggleBold(page)
{
	await keyDownCtrlOrMeta(page);
	await page.keyboard.press('b');
	await keyUpCtrlOrMeta(page);
}

export async function pressToggleItalic(page)
{
	await keyDownCtrlOrMeta(page);
	await page.keyboard.press('i');
	await keyUpCtrlOrMeta(page);
}

export async function pressToggleUnderline(page)
{
	await keyDownCtrlOrMeta(page);
	await page.keyboard.press('u');
	await keyUpCtrlOrMeta(page);
}

export async function dragDraggableMenuTo(
	page,
	toSelector,
	positionStart = 'middle',
	positionEnd = 'middle',
)
{
	await dragMouse(
		page,
		await selectorBoundingBox(page, '.draggable-block-menu'),
		await selectorBoundingBox(page, toSelector),
		positionStart,
		positionEnd,
	);
}

Youez - 2016 - github.com/yon3zu
LinuXploit