mirror of
https://github.com/microsoft/playwright.git
synced 2024-11-24 06:49:04 +03:00
chore: allow editing aria template in recorder (tests) (#33522)
This commit is contained in:
parent
c29f573243
commit
503f74da90
11
package-lock.json
generated
11
package-lock.json
generated
@ -2910,10 +2910,11 @@
|
||||
"periscopic": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/codemirror-shadow-1": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/codemirror-shadow-1/-/codemirror-shadow-1-0.0.1.tgz",
|
||||
"integrity": "sha512-kD3OZpCCHr3LHRKfbGx5IogHTWq4Uo9jH2bXPVa7/n6ppkgI66rx4tniQY1BpqWp/JNhQmQsXhQoaZ1TH6t0xQ=="
|
||||
"node_modules/codemirror": {
|
||||
"version": "5.65.18",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.18.tgz",
|
||||
"integrity": "sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
@ -8112,7 +8113,7 @@
|
||||
"packages/web": {
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"codemirror-shadow-1": "0.0.1",
|
||||
"codemirror": "5.65.18",
|
||||
"xterm": "^5.1.0",
|
||||
"xterm-addon-fit": "^0.7.0"
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ This project incorporates components from the projects listed below. The origina
|
||||
- balanced-match@1.0.2 (https://github.com/juliangruber/balanced-match)
|
||||
- brace-expansion@1.1.11 (https://github.com/juliangruber/brace-expansion)
|
||||
- buffer-crc32@0.2.13 (https://github.com/brianloveswords/buffer-crc32)
|
||||
- codemirror-shadow-1@0.0.1 (https://github.com/codemirror/CodeMirror)
|
||||
- codemirror@5.65.18 (https://github.com/codemirror/CodeMirror)
|
||||
- colors@1.4.0 (https://github.com/Marak/colors.js)
|
||||
- commander@8.3.0 (https://github.com/tj/commander.js)
|
||||
- concat-map@0.0.1 (https://github.com/substack/node-concat-map)
|
||||
@ -208,7 +208,7 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL
|
||||
=========================================
|
||||
END OF buffer-crc32@0.2.13 AND INFORMATION
|
||||
|
||||
%% codemirror-shadow-1@0.0.1 NOTICES AND INFORMATION BEGIN HERE
|
||||
%% codemirror@5.65.18 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
|
||||
@ -232,7 +232,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
=========================================
|
||||
END OF codemirror-shadow-1@0.0.1 AND INFORMATION
|
||||
END OF codemirror@5.65.18 AND INFORMATION
|
||||
|
||||
%% colors@1.4.0 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
|
@ -204,7 +204,7 @@ export type MatcherReceived = {
|
||||
|
||||
export function matchesAriaTree(rootElement: Element, template: AriaTemplateNode): { matches: AriaNode[], received: MatcherReceived } {
|
||||
const root = generateAriaTree(rootElement);
|
||||
const matches = matchesNodeDeep(root, template);
|
||||
const matches = matchesNodeDeep(root, template, false);
|
||||
return {
|
||||
matches,
|
||||
received: {
|
||||
@ -215,8 +215,9 @@ export function matchesAriaTree(rootElement: Element, template: AriaTemplateNode
|
||||
}
|
||||
|
||||
export function getAllByAria(rootElement: Element, template: AriaTemplateNode): Element[] {
|
||||
const result = matchesAriaTree(rootElement, template);
|
||||
return result.matches.map(n => n.element);
|
||||
const root = generateAriaTree(rootElement);
|
||||
const matches = matchesNodeDeep(root, template, true);
|
||||
return matches.map(n => n.element);
|
||||
}
|
||||
|
||||
function matchesNode(node: AriaNode | string, template: AriaTemplateNode, depth: number): boolean {
|
||||
@ -265,12 +266,12 @@ function containsList(children: (AriaNode | string)[], template: AriaTemplateNod
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchesNodeDeep(root: AriaNode, template: AriaTemplateNode): AriaNode[] {
|
||||
function matchesNodeDeep(root: AriaNode, template: AriaTemplateNode, collectAll: boolean): AriaNode[] {
|
||||
const results: AriaNode[] = [];
|
||||
const visit = (node: AriaNode | string): boolean => {
|
||||
if (matchesNode(node, template, 0)) {
|
||||
results.push(node as AriaNode);
|
||||
return true;
|
||||
return !collectAll;
|
||||
}
|
||||
if (typeof node === 'string')
|
||||
return false;
|
||||
|
@ -207,9 +207,9 @@ class InspectTool implements RecorderTool {
|
||||
class RecordActionTool implements RecorderTool {
|
||||
private _recorder: Recorder;
|
||||
private _performingActions = new Set<actions.PerformOnRecordAction>();
|
||||
private _hoveredModel: HighlightModeWithSelector | null = null;
|
||||
private _hoveredModel: HighlightModelWithSelector | null = null;
|
||||
private _hoveredElement: HTMLElement | null = null;
|
||||
private _activeModel: HighlightModeWithSelector | null = null;
|
||||
private _activeModel: HighlightModelWithSelector | null = null;
|
||||
private _expectProgrammaticKeyUp = false;
|
||||
private _pendingClickAction: { action: actions.ClickAction, timeout: number } | undefined;
|
||||
|
||||
@ -605,7 +605,7 @@ class RecordActionTool implements RecorderTool {
|
||||
|
||||
class TextAssertionTool implements RecorderTool {
|
||||
private _recorder: Recorder;
|
||||
private _hoverHighlight: HighlightModeWithSelector | null = null;
|
||||
private _hoverHighlight: HighlightModelWithSelector | null = null;
|
||||
private _action: actions.AssertAction | null = null;
|
||||
private _dialog: Dialog;
|
||||
private _textCache = new Map<Element | ShadowRoot, ElementText>();
|
||||
@ -1460,7 +1460,7 @@ type HighlightModel = HighlightOptions & {
|
||||
elements: Element[];
|
||||
};
|
||||
|
||||
type HighlightModeWithSelector = HighlightModel & {
|
||||
type HighlightModelWithSelector = HighlightModel & {
|
||||
selector: string;
|
||||
};
|
||||
|
||||
|
@ -52,6 +52,8 @@ export type AriaTemplateNode = AriaTemplateRoleNode | AriaTemplateTextNode;
|
||||
export function parseYamlTemplate(fragment: ParsedYaml): AriaTemplateNode {
|
||||
const result: AriaTemplateNode = { kind: 'role', role: 'fragment' };
|
||||
populateNode(result, fragment);
|
||||
if (result.children && result.children.length === 1)
|
||||
return result.children[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ This project incorporates components from the projects listed below. The origina
|
||||
- chalk@4.1.2 (https://github.com/chalk/chalk)
|
||||
- chokidar@3.6.0 (https://github.com/paulmillr/chokidar)
|
||||
- ci-info@3.9.0 (https://github.com/watson/ci-info)
|
||||
- codemirror-shadow-1@0.0.1 (https://github.com/codemirror/CodeMirror)
|
||||
- codemirror@5.65.18 (https://github.com/codemirror/CodeMirror)
|
||||
- color-convert@1.9.3 (https://github.com/Qix-/color-convert)
|
||||
- color-convert@2.0.1 (https://github.com/Qix-/color-convert)
|
||||
- color-name@1.1.3 (https://github.com/dfcreative/color-name)
|
||||
@ -3103,7 +3103,7 @@ SOFTWARE.
|
||||
=========================================
|
||||
END OF ci-info@3.9.0 AND INFORMATION
|
||||
|
||||
%% codemirror-shadow-1@0.0.1 NOTICES AND INFORMATION BEGIN HERE
|
||||
%% codemirror@5.65.18 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
|
||||
@ -3127,7 +3127,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
=========================================
|
||||
END OF codemirror-shadow-1@0.0.1 AND INFORMATION
|
||||
END OF codemirror@5.65.18 AND INFORMATION
|
||||
|
||||
%% color-convert@1.9.3 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
|
@ -29,7 +29,6 @@ import { asLocator } from '@isomorphic/locatorGenerators';
|
||||
import { toggleTheme } from '@web/theme';
|
||||
import { copy } from '@web/uiUtils';
|
||||
import yaml from 'yaml';
|
||||
import type { YAMLError } from 'yaml';
|
||||
import { parseAriaKey } from '@isomorphic/ariaSnapshot';
|
||||
import type { AriaKeyError, ParsedYaml } from '@isomorphic/ariaSnapshot';
|
||||
|
||||
@ -199,7 +198,7 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||
{
|
||||
id: 'aria',
|
||||
title: 'Aria snapshot',
|
||||
render: () => <CodeMirrorWrapper text={ariaSnapshot || ''} language={'yaml'} readOnly={false} onChange={onAriaEditorChange} highlight={ariaSnapshotErrors} wrapLines={true} />
|
||||
render: () => <CodeMirrorWrapper text={ariaSnapshot || ''} language={'yaml'} readOnly={false} onChange={onAriaEditorChange} highlight={ariaSnapshotErrors} wrapLines={false} />
|
||||
},
|
||||
]}
|
||||
selectedTab={selectedTab}
|
||||
@ -211,32 +210,31 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||
|
||||
function parseAriaSnapshot(ariaSnapshot: string): { fragment?: ParsedYaml, errors: SourceHighlight[] } {
|
||||
const lineCounter = new yaml.LineCounter();
|
||||
let yamlDoc: yaml.Document;
|
||||
try {
|
||||
yamlDoc = yaml.parseDocument(ariaSnapshot, {
|
||||
const yamlDoc = yaml.parseDocument(ariaSnapshot, {
|
||||
keepSourceTokens: true,
|
||||
lineCounter,
|
||||
prettyErrors: false,
|
||||
});
|
||||
} catch (e) {
|
||||
const error = e as YAMLError;
|
||||
const pos = error.linePos?.[0];
|
||||
return {
|
||||
errors: [{
|
||||
line: pos?.line || 0,
|
||||
type: 'error',
|
||||
message: error.message,
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
const errors: SourceHighlight[] = [];
|
||||
for (const error of yamlDoc.errors) {
|
||||
errors.push({
|
||||
line: lineCounter.linePos(error.pos[0]).line,
|
||||
type: 'error',
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
|
||||
if (yamlDoc.errors.length)
|
||||
return { errors };
|
||||
|
||||
const handleKey = (key: yaml.Scalar<string>) => {
|
||||
try {
|
||||
parseAriaKey(key.value);
|
||||
} catch (e) {
|
||||
const keyError = e as AriaKeyError;
|
||||
errors.push({
|
||||
message: keyError.message,
|
||||
message: keyError.shortMessage,
|
||||
line: lineCounter.linePos(key.srcToken!.offset + keyError.pos).line,
|
||||
type: 'error',
|
||||
});
|
||||
|
@ -4,7 +4,7 @@
|
||||
"version": "0.0.0",
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"codemirror-shadow-1": "0.0.1",
|
||||
"codemirror": "5.65.18",
|
||||
"xterm": "^5.1.0",
|
||||
"xterm-addon-fit": "^0.7.0"
|
||||
}
|
||||
|
@ -15,17 +15,17 @@
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import codemirror from 'codemirror-shadow-1';
|
||||
import codemirror from 'codemirror';
|
||||
import type codemirrorType from 'codemirror';
|
||||
import 'codemirror-shadow-1/lib/codemirror.css';
|
||||
import 'codemirror-shadow-1/mode/css/css';
|
||||
import 'codemirror-shadow-1/mode/htmlmixed/htmlmixed';
|
||||
import 'codemirror-shadow-1/mode/javascript/javascript';
|
||||
import 'codemirror-shadow-1/mode/python/python';
|
||||
import 'codemirror-shadow-1/mode/clike/clike';
|
||||
import 'codemirror-shadow-1/mode/markdown/markdown';
|
||||
import 'codemirror-shadow-1/addon/mode/simple';
|
||||
import 'codemirror-shadow-1/mode/yaml/yaml';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
import 'codemirror/mode/css/css';
|
||||
import 'codemirror/mode/htmlmixed/htmlmixed';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
import 'codemirror/mode/python/python';
|
||||
import 'codemirror/mode/clike/clike';
|
||||
import 'codemirror/mode/markdown/markdown';
|
||||
import 'codemirror/addon/mode/simple';
|
||||
import 'codemirror/mode/yaml/yaml';
|
||||
|
||||
export type CodeMirror = typeof codemirrorType;
|
||||
export default codemirror;
|
||||
|
@ -115,8 +115,13 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
||||
return;
|
||||
|
||||
let valueChanged = false;
|
||||
if (codemirror.getValue() !== text) {
|
||||
codemirror.setValue(text);
|
||||
// CodeMirror has a bug that renders cursor poorly on a last line.
|
||||
let normalizedText = text;
|
||||
if (!readOnly && !wrapLines && !normalizedText.endsWith('\n'))
|
||||
normalizedText = normalizedText + '\n';
|
||||
|
||||
if (codemirror.getValue() !== normalizedText) {
|
||||
codemirror.setValue(normalizedText);
|
||||
valueChanged = true;
|
||||
if (focusOnChange) {
|
||||
codemirror.execCommand('selectAll');
|
||||
@ -170,7 +175,7 @@ export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
||||
if (changeListener)
|
||||
codemirror.off('change', changeListener);
|
||||
};
|
||||
}, [codemirror, text, highlight, revealLine, focusOnChange, onChange]);
|
||||
}, [codemirror, text, highlight, revealLine, focusOnChange, onChange, readOnly]);
|
||||
|
||||
return <div data-testid={dataTestId} className='cm-wrapper' ref={codemirrorElement} onClick={onCodeMirrorClick}></div>;
|
||||
};
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { test, expect } from './inspectorTest';
|
||||
import { roundBox } from '../../page/pageTest';
|
||||
|
||||
test.describe(() => {
|
||||
test.skip(({ mode }) => mode !== 'default');
|
||||
@ -59,4 +60,90 @@ test.describe(() => {
|
||||
await expect.poll(() =>
|
||||
recorder.text('C#')).toContain(`await Expect(page.GetByRole(AriaRole.Button)).ToMatchAriaSnapshotAsync("- button /Submit \\\\d+/");`);
|
||||
});
|
||||
|
||||
test('should inspect aria snapshot', async ({ openRecorder }) => {
|
||||
const { recorder } = await openRecorder();
|
||||
await recorder.setContentAndWait(`<main><button>Submit</button></main>`);
|
||||
await recorder.page.click('x-pw-tool-item.pick-locator');
|
||||
await recorder.page.hover('button');
|
||||
await recorder.trustedClick();
|
||||
await recorder.recorderPage.getByRole('tab', { name: 'Aria snapshot ' }).click();
|
||||
await expect(recorder.recorderPage.locator('.tab-aria .CodeMirror')).toMatchAriaSnapshot(`
|
||||
- textbox
|
||||
- text: '- button "Submit"'
|
||||
`);
|
||||
});
|
||||
|
||||
test('should update aria snapshot highlight', async ({ openRecorder }) => {
|
||||
const { recorder } = await openRecorder();
|
||||
await recorder.setContentAndWait(`<main>
|
||||
<button>Submit</button>
|
||||
<button>Cancel</button>
|
||||
</main>`);
|
||||
|
||||
const submitButton = recorder.page.getByRole('button', { name: 'Submit' });
|
||||
const cancelButton = recorder.page.getByRole('button', { name: 'Cancel' });
|
||||
|
||||
await recorder.recorderPage.getByRole('button', { name: 'Record' }).click();
|
||||
|
||||
await recorder.page.click('x-pw-tool-item.pick-locator');
|
||||
await submitButton.hover();
|
||||
await recorder.trustedClick();
|
||||
await recorder.recorderPage.getByRole('tab', { name: 'Aria snapshot ' }).click();
|
||||
await expect(recorder.recorderPage.locator('.tab-aria .CodeMirror')).toMatchAriaSnapshot(`
|
||||
- text: '- button "Submit"'
|
||||
`);
|
||||
|
||||
await recorder.recorderPage.locator('.tab-aria .CodeMirror').click();
|
||||
await recorder.recorderPage.keyboard.press('ArrowLeft');
|
||||
for (let i = 0; i < '"Submit"'.length; i++)
|
||||
await recorder.recorderPage.keyboard.press('Backspace');
|
||||
|
||||
{
|
||||
// No accessible name => two boxes.
|
||||
const box11 = roundBox(await submitButton.boundingBox());
|
||||
const box12 = roundBox(await recorder.page.locator('x-pw-highlight').first().boundingBox());
|
||||
expect(box11).toEqual(box12);
|
||||
|
||||
const box21 = roundBox(await cancelButton.boundingBox());
|
||||
const box22 = roundBox(await recorder.page.locator('x-pw-highlight').last().boundingBox());
|
||||
expect(box21).toEqual(box22);
|
||||
}
|
||||
|
||||
{
|
||||
// Different button.
|
||||
await recorder.recorderPage.locator('.tab-aria .CodeMirror').pressSequentially('"Cancel"');
|
||||
await expect(recorder.page.locator('x-pw-highlight')).toBeVisible();
|
||||
const box1 = roundBox(await cancelButton.boundingBox());
|
||||
const box2 = roundBox(await recorder.page.locator('x-pw-highlight').boundingBox());
|
||||
expect(box1).toEqual(box2);
|
||||
}
|
||||
});
|
||||
|
||||
test('should show aria snapshot error', async ({ openRecorder }) => {
|
||||
const { recorder } = await openRecorder();
|
||||
await recorder.setContentAndWait(`<main>
|
||||
<button>Submit</button>
|
||||
<button>Cancel</button>
|
||||
</main>`);
|
||||
|
||||
const submitButton = recorder.page.getByRole('button', { name: 'Submit' });
|
||||
await recorder.recorderPage.getByRole('button', { name: 'Record' }).click();
|
||||
|
||||
await recorder.page.click('x-pw-tool-item.pick-locator');
|
||||
await submitButton.hover();
|
||||
await recorder.trustedClick();
|
||||
|
||||
await recorder.recorderPage.getByRole('tab', { name: 'Aria snapshot ' }).click();
|
||||
await expect(recorder.recorderPage.locator('.tab-aria .CodeMirror')).toMatchAriaSnapshot(`
|
||||
- text: '- button "Submit"'
|
||||
`);
|
||||
|
||||
await recorder.recorderPage.locator('.tab-aria .CodeMirror').click();
|
||||
await recorder.recorderPage.keyboard.press('ArrowLeft');
|
||||
await recorder.recorderPage.keyboard.press('Backspace');
|
||||
await expect(recorder.recorderPage.locator('.tab-aria .CodeMirror')).toMatchAriaSnapshot(`
|
||||
- text: '- button "Submit Unterminated string'
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
@ -17,7 +17,8 @@
|
||||
import type { Page } from 'playwright-core';
|
||||
import { test as it, expect, Recorder } from './inspectorTest';
|
||||
import { waitForTestLog } from '../../config/utils';
|
||||
|
||||
import { roundBox } from '../../page/pageTest';
|
||||
import type { BoundingBox } from '../../page/pageTest';
|
||||
|
||||
it('should resume when closing inspector', async ({ page, recorderPageGetter, closeRecorder, mode }) => {
|
||||
it.skip(mode !== 'default');
|
||||
@ -385,7 +386,7 @@ it.describe('pause', () => {
|
||||
})();
|
||||
const recorderPage = await recorderPageGetter();
|
||||
|
||||
const box1Promise = waitForTestLog<Box>(page, 'Highlight box for test: ');
|
||||
const box1Promise = waitForTestLog<BoundingBox>(page, 'Highlight box for test: ');
|
||||
await recorderPage.getByText('Locator', { exact: true }).click();
|
||||
await recorderPage.locator('.tabbed-pane .CodeMirror').click();
|
||||
await recorderPage.keyboard.type('getByText(\'Submit\')');
|
||||
@ -407,7 +408,7 @@ it.describe('pause', () => {
|
||||
})();
|
||||
const recorderPage = await recorderPageGetter();
|
||||
|
||||
const box1Promise = waitForTestLog<Box>(page, 'Highlight box for test: ');
|
||||
const box1Promise = waitForTestLog<BoundingBox>(page, 'Highlight box for test: ');
|
||||
await recorderPage.getByText('Locator', { exact: true }).click();
|
||||
await recorderPage.locator('.tabbed-pane .CodeMirror').click();
|
||||
await recorderPage.keyboard.type('GetByText("Submit")');
|
||||
@ -472,7 +473,7 @@ it.describe('pause', () => {
|
||||
})();
|
||||
const recorderPage = await recorderPageGetter();
|
||||
|
||||
const box1Promise = waitForTestLog<Box>(page, 'Highlight box for test: ');
|
||||
const box1Promise = waitForTestLog<BoundingBox>(page, 'Highlight box for test: ');
|
||||
await recorderPage.click('[title="Step over (F10)"]');
|
||||
const box2 = roundBox((await page.locator('#target').boundingBox())!);
|
||||
const box1 = roundBox(await box1Promise);
|
||||
@ -514,13 +515,3 @@ async function sanitizeLog(recorderPage: Page): Promise<string[]> {
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
type Box = { x: number, y: number, width: number, height: number };
|
||||
function roundBox(box: Box): Box {
|
||||
return {
|
||||
x: Math.round(box.x * 1000),
|
||||
y: Math.round(box.y * 1000),
|
||||
width: Math.round(box.width * 1000),
|
||||
height: Math.round(box.height * 1000),
|
||||
};
|
||||
}
|
||||
|
@ -14,10 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './pageTest';
|
||||
import type { Locator } from 'playwright-core';
|
||||
|
||||
type BoundingBox = Awaited<ReturnType<Locator['boundingBox']>>;
|
||||
import { test as it, expect, roundBox } from './pageTest';
|
||||
|
||||
it.skip(({ mode }) => mode !== 'default', 'Highlight element has a closed shadow-root on != default');
|
||||
|
||||
@ -30,12 +27,3 @@ it('should highlight locator', async ({ page }) => {
|
||||
const box2 = roundBox(await page.locator('x-pw-highlight').boundingBox());
|
||||
expect(box1).toEqual(box2);
|
||||
});
|
||||
|
||||
function roundBox(box: BoundingBox): BoundingBox {
|
||||
return {
|
||||
x: Math.round(box.x),
|
||||
y: Math.round(box.y),
|
||||
width: Math.round(box.width),
|
||||
height: Math.round(box.height),
|
||||
};
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Frame, Page, TestType } from '@playwright/test';
|
||||
import type { Frame, Page, TestType, Locator } from '@playwright/test';
|
||||
import type { PlatformWorkerFixtures } from '../config/platformFixtures';
|
||||
import type { TestModeTestFixtures, TestModeWorkerFixtures, TestModeWorkerOptions } from '../config/testModeFixtures';
|
||||
import { androidTest } from '../android/androidTest';
|
||||
@ -26,6 +26,7 @@ import type { ServerFixtures, ServerWorkerOptions } from '../config/serverFixtur
|
||||
export { expect } from '@playwright/test';
|
||||
|
||||
let impl: TestType<PageTestFixtures & ServerFixtures & TestModeTestFixtures, PageWorkerFixtures & PlatformWorkerFixtures & TestModeWorkerFixtures & TestModeWorkerOptions & ServerWorkerOptions> = browserTest;
|
||||
export type BoundingBox = Awaited<ReturnType<Locator['boundingBox']>>;
|
||||
|
||||
if (process.env.PWPAGE_IMPL === 'android')
|
||||
impl = androidTest;
|
||||
@ -43,3 +44,12 @@ export async function rafraf(target: Page | Frame, count = 1) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function roundBox(box: BoundingBox): BoundingBox {
|
||||
return {
|
||||
x: Math.round(box.x),
|
||||
y: Math.round(box.y),
|
||||
width: Math.round(box.width),
|
||||
height: Math.round(box.height),
|
||||
};
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ This project incorporates components from the projects listed below. The origina
|
||||
}
|
||||
}
|
||||
|
||||
const packages = await checkDir('node_modules/codemirror-shadow-1');
|
||||
const packages = await checkDir('node_modules/codemirror');
|
||||
for (const [key, value] of Object.entries(packages)) {
|
||||
if (value.licenseText)
|
||||
allPackages[key] = value;
|
||||
|
Loading…
Reference in New Issue
Block a user