mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: more codegen fixes (#32816)
This commit is contained in:
parent
0480bd0cac
commit
61801aa1ee
@ -205,7 +205,7 @@ class InspectTool implements RecorderTool {
|
||||
|
||||
class RecordActionTool implements RecorderTool {
|
||||
private _recorder: Recorder;
|
||||
private _performingAction: actions.PerformOnRecordAction | null = null;
|
||||
private _performingActions = new Set<actions.PerformOnRecordAction>();
|
||||
private _hoveredModel: HighlightModel | null = null;
|
||||
private _hoveredElement: HTMLElement | null = null;
|
||||
private _activeModel: HighlightModel | null = null;
|
||||
@ -333,21 +333,21 @@ class RecordActionTool implements RecorderTool {
|
||||
onPointerDown(event: PointerEvent) {
|
||||
if (this._shouldIgnoreMouseEvent(event))
|
||||
return;
|
||||
if (!this._performingAction)
|
||||
if (!this._performingActions.size)
|
||||
consumeEvent(event);
|
||||
}
|
||||
|
||||
onPointerUp(event: PointerEvent) {
|
||||
if (this._shouldIgnoreMouseEvent(event))
|
||||
return;
|
||||
if (!this._performingAction)
|
||||
if (!this._performingActions.size)
|
||||
consumeEvent(event);
|
||||
}
|
||||
|
||||
onMouseDown(event: MouseEvent) {
|
||||
if (this._shouldIgnoreMouseEvent(event))
|
||||
return;
|
||||
if (!this._performingAction)
|
||||
if (!this._performingActions.size)
|
||||
consumeEvent(event);
|
||||
this._activeModel = this._hoveredModel;
|
||||
}
|
||||
@ -355,7 +355,7 @@ class RecordActionTool implements RecorderTool {
|
||||
onMouseUp(event: MouseEvent) {
|
||||
if (this._shouldIgnoreMouseEvent(event))
|
||||
return;
|
||||
if (!this._performingAction)
|
||||
if (!this._performingActions.size)
|
||||
consumeEvent(event);
|
||||
}
|
||||
|
||||
@ -509,12 +509,13 @@ class RecordActionTool implements RecorderTool {
|
||||
private _actionInProgress(event: Event): boolean {
|
||||
// If Playwright is performing action for us, bail.
|
||||
const isKeyEvent = event instanceof KeyboardEvent;
|
||||
if (this._performingAction?.name === 'press' && isKeyEvent && event.key === this._performingAction.key)
|
||||
return true;
|
||||
|
||||
const isMouseOrPointerEvent = event instanceof MouseEvent || event instanceof PointerEvent;
|
||||
if (isMouseOrPointerEvent && (this._performingAction?.name === 'click' || this._performingAction?.name === 'check' || this._performingAction?.name === 'uncheck'))
|
||||
return true;
|
||||
for (const action of this._performingActions) {
|
||||
if (isKeyEvent && action.name === 'press' && event.key === action.key)
|
||||
return true;
|
||||
if (isMouseOrPointerEvent && (action.name === 'click' || action.name === 'check' || action.name === 'uncheck'))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Consume event if action is not being executed.
|
||||
consumeEvent(event);
|
||||
@ -540,9 +541,9 @@ class RecordActionTool implements RecorderTool {
|
||||
this._hoveredModel = null;
|
||||
this._activeModel = null;
|
||||
this._recorder.updateHighlight(null, false);
|
||||
this._performingAction = action;
|
||||
this._performingActions.add(action);
|
||||
void this._recorder.performAction(action).then(() => {
|
||||
this._performingAction = null;
|
||||
this._performingActions.delete(action);
|
||||
|
||||
// If that was a keyboard action, it similarly requires new selectors for active model.
|
||||
this._onFocus(false);
|
||||
|
@ -421,18 +421,32 @@ await page.GetByRole(AriaRole.Textbox).PressAsync("Shift+Enter");`);
|
||||
<input name="two"></input>
|
||||
`);
|
||||
|
||||
await page.click('input[name="one"]');
|
||||
await recorder.waitForOutput('JavaScript', 'click');
|
||||
await page.keyboard.type('foobar123');
|
||||
await recorder.waitForOutput('JavaScript', 'foobar123');
|
||||
const input1 = page.locator('input[name="one"]');
|
||||
const input2 = page.locator('input[name="two"]');
|
||||
|
||||
await page.keyboard.press('Tab');
|
||||
await recorder.waitForOutput('JavaScript', 'Tab');
|
||||
await page.keyboard.type('barfoo321');
|
||||
// I can't explain it atm, first character is being consumed for no apparent reason.
|
||||
if (browserName === 'webkit' && codegenMode === 'trace-events')
|
||||
await page.waitForTimeout(1000);
|
||||
await recorder.waitForOutput('JavaScript', 'barfoo321');
|
||||
{
|
||||
await input1.click();
|
||||
await recorder.waitForOutput('JavaScript', 'click');
|
||||
await expect(input1).toBeFocused();
|
||||
}
|
||||
|
||||
{
|
||||
await page.keyboard.type('foobar123');
|
||||
await recorder.waitForOutput('JavaScript', 'foobar123');
|
||||
await expect(input1).toHaveValue('foobar123');
|
||||
}
|
||||
|
||||
{
|
||||
await page.keyboard.press('Tab');
|
||||
await recorder.waitForOutput('JavaScript', 'Tab');
|
||||
await expect(input2).toBeFocused();
|
||||
}
|
||||
|
||||
{
|
||||
await page.keyboard.type('barfoo321');
|
||||
await recorder.waitForOutput('JavaScript', 'barfoo321');
|
||||
await expect(input2).toHaveValue('barfoo321');
|
||||
}
|
||||
|
||||
const text = recorder.sources().get('JavaScript')!.text;
|
||||
expect(text).toContain(`
|
||||
|
@ -220,55 +220,30 @@ await page.GetByRole(AriaRole.Textbox).SetInputFilesAsync(new[] { });`);
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const sources = await recorder.waitForOutput('JavaScript', 'download1Promise');
|
||||
const sources = await recorder.waitForOutput('JavaScript', 'downloadPromise');
|
||||
|
||||
expect.soft(sources.get('JavaScript')!.text).toContain(`
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await page.getByRole('link', { name: 'Download' }).click();
|
||||
const download = await downloadPromise;`);
|
||||
expect.soft(sources.get('JavaScript')!.text).toContain(`
|
||||
const download1Promise = page.waitForEvent('download');
|
||||
await page.getByRole('link', { name: 'Download' }).click();
|
||||
const download1 = await download1Promise;`);
|
||||
|
||||
expect.soft(sources.get('Java')!.text).toContain(`
|
||||
Download download = page.waitForDownload(() -> {
|
||||
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Download")).click();
|
||||
});`);
|
||||
expect.soft(sources.get('Java')!.text).toContain(`
|
||||
Download download1 = page.waitForDownload(() -> {
|
||||
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Download")).click();
|
||||
});`);
|
||||
|
||||
expect.soft(sources.get('Python')!.text).toContain(`
|
||||
with page.expect_download() as download_info:
|
||||
page.get_by_role("link", name="Download").click()
|
||||
download = download_info.value`);
|
||||
expect.soft(sources.get('Python')!.text).toContain(`
|
||||
with page.expect_download() as download1_info:
|
||||
page.get_by_role("link", name="Download").click()
|
||||
download1 = download1_info.value`);
|
||||
|
||||
expect.soft(sources.get('Python Async')!.text).toContain(`
|
||||
async with page.expect_download() as download_info:
|
||||
await page.get_by_role("link", name="Download").click()
|
||||
download = await download_info.value`);
|
||||
expect.soft(sources.get('Python Async')!.text).toContain(`
|
||||
async with page.expect_download() as download1_info:
|
||||
await page.get_by_role("link", name="Download").click()
|
||||
download1 = await download1_info.value`);
|
||||
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
var download = await page.RunAndWaitForDownloadAsync(async () =>
|
||||
{
|
||||
await page.GetByRole(AriaRole.Link, new() { Name = "Download" }).ClickAsync();
|
||||
});`);
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
var download1 = await page.RunAndWaitForDownloadAsync(async () =>
|
||||
{
|
||||
await page.GetByRole(AriaRole.Link, new() { Name = "Download" }).ClickAsync();
|
||||
});`);
|
||||
|
@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { TestServer } from 'tests/config/testserver';
|
||||
import type { Recorder } from './inspectorTest';
|
||||
import { test, expect } from './inspectorTest';
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
test.describe('cli codegen', () => {
|
||||
test.skip(({ mode }) => mode !== 'default');
|
||||
@ -90,7 +93,82 @@ await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).Nth(1).ClickAsy
|
||||
expect(message.text()).toBe('click2');
|
||||
});
|
||||
|
||||
test('should generate frame locators', async ({ openRecorder, server }) => {
|
||||
test('should generate frame locators (1)', async ({ openRecorder, server }) => {
|
||||
const { page, recorder } = await openRecorder();
|
||||
const { frameHello1 } = await createFrameHierarchy(page, recorder, server);
|
||||
|
||||
const [sources] = await Promise.all([
|
||||
recorder.waitForOutput('JavaScript', 'Hello1'),
|
||||
frameHello1.click('text=Hello1'),
|
||||
]);
|
||||
|
||||
expect.soft(sources.get('JavaScript')!.text).toContain(`
|
||||
await page.locator('#frame1').contentFrame().getByText('Hello1').click();`);
|
||||
|
||||
expect.soft(sources.get('Java')!.text).toContain(`
|
||||
page.locator("#frame1").contentFrame().getByText("Hello1").click();`);
|
||||
|
||||
expect.soft(sources.get('Python')!.text).toContain(`
|
||||
page.locator("#frame1").content_frame.get_by_text("Hello1").click()`);
|
||||
|
||||
expect.soft(sources.get('Python Async')!.text).toContain(`
|
||||
await page.locator("#frame1").content_frame.get_by_text("Hello1").click()`);
|
||||
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
await page.Locator("#frame1").ContentFrame.GetByText("Hello1").ClickAsync();`);
|
||||
});
|
||||
|
||||
test('should generate frame locators (2)', async ({ openRecorder, server }) => {
|
||||
const { page, recorder } = await openRecorder();
|
||||
const { frameHello2 } = await createFrameHierarchy(page, recorder, server);
|
||||
|
||||
const [sources] = await Promise.all([
|
||||
recorder.waitForOutput('JavaScript', 'Hello2'),
|
||||
frameHello2.click('text=Hello2'),
|
||||
]);
|
||||
|
||||
expect.soft(sources.get('JavaScript')!.text).toContain(`
|
||||
await page.locator('#frame1').contentFrame().locator('iframe').contentFrame().getByText('Hello2').click();`);
|
||||
|
||||
expect.soft(sources.get('Java')!.text).toContain(`
|
||||
page.locator("#frame1").contentFrame().locator("iframe").contentFrame().getByText("Hello2").click();`);
|
||||
|
||||
expect.soft(sources.get('Python')!.text).toContain(`
|
||||
page.locator("#frame1").content_frame.locator("iframe").content_frame.get_by_text("Hello2").click()`);
|
||||
|
||||
expect.soft(sources.get('Python Async')!.text).toContain(`
|
||||
await page.locator("#frame1").content_frame.locator("iframe").content_frame.get_by_text("Hello2").click()`);
|
||||
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
await page.Locator("#frame1").ContentFrame.Locator("iframe").ContentFrame.GetByText("Hello2").ClickAsync();`);
|
||||
});
|
||||
|
||||
test('should generate frame locators (3)', async ({ openRecorder, server }) => {
|
||||
const { page, recorder } = await openRecorder();
|
||||
const { frameAnonymous } = await createFrameHierarchy(page, recorder, server);
|
||||
|
||||
const [sources] = await Promise.all([
|
||||
recorder.waitForOutput('JavaScript', 'HelloNameAnonymous'),
|
||||
frameAnonymous.click('text=HelloNameAnonymous'),
|
||||
]);
|
||||
|
||||
expect.soft(sources.get('JavaScript')!.text).toContain(`
|
||||
await page.locator('#frame1').contentFrame().locator('iframe').contentFrame().locator('iframe').nth(2).contentFrame().getByText('HelloNameAnonymous').click();`);
|
||||
|
||||
expect.soft(sources.get('Java')!.text).toContain(`
|
||||
page.locator("#frame1").contentFrame().locator("iframe").contentFrame().locator("iframe").nth(2).contentFrame().getByText("HelloNameAnonymous").click();`);
|
||||
|
||||
expect.soft(sources.get('Python')!.text).toContain(`
|
||||
page.locator("#frame1").content_frame.locator("iframe").content_frame.locator("iframe").nth(2).content_frame.get_by_text("HelloNameAnonymous").click()`);
|
||||
|
||||
expect.soft(sources.get('Python Async')!.text).toContain(`
|
||||
await page.locator("#frame1").content_frame.locator("iframe").content_frame.locator("iframe").nth(2).content_frame.get_by_text("HelloNameAnonymous").click()`);
|
||||
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
await page.Locator("#frame1").ContentFrame.Locator("iframe").ContentFrame.Locator("iframe").Nth(2).ContentFrame.GetByText("HelloNameAnonymous").ClickAsync();`);
|
||||
});
|
||||
|
||||
test('should generate frame locators (4)', async ({ openRecorder, server }) => {
|
||||
const { page, recorder } = await openRecorder();
|
||||
/*
|
||||
iframe
|
||||
@ -99,8 +177,6 @@ await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).Nth(1).ClickAsy
|
||||
div Hello2
|
||||
iframe[name=one]
|
||||
div HelloNameOne
|
||||
iframe[name=two]
|
||||
dev HelloNameTwo
|
||||
iframe
|
||||
dev HelloAnonymous
|
||||
*/
|
||||
@ -109,8 +185,6 @@ await page.GetByRole(AriaRole.Button, new() { Name = "Submit" }).Nth(1).ClickAsy
|
||||
`, server.EMPTY_PAGE, 6);
|
||||
const frameHello1 = page.mainFrame().childFrames()[0];
|
||||
const frameHello2 = frameHello1.childFrames()[0];
|
||||
const frameOne = page.frame({ name: 'one' })!;
|
||||
await frameOne.setContent(`<div>HelloNameOne</div>`);
|
||||
const frameTwo = page.frame({ name: 'two' })!;
|
||||
await frameTwo.setContent(`<div>HelloNameTwo</div>`);
|
||||
const frameAnonymous = frameHello2.childFrames().find(f => !f.name())!;
|
||||
@ -157,27 +231,6 @@ await page.Locator("#frame1").ContentFrame.GetByText("Hello1").ClickAsync();`);
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
await page.Locator("#frame1").ContentFrame.Locator("iframe").ContentFrame.GetByText("Hello2").ClickAsync();`);
|
||||
|
||||
|
||||
[sources] = await Promise.all([
|
||||
recorder.waitForOutput('JavaScript', 'one'),
|
||||
frameOne.click('text=HelloNameOne'),
|
||||
]);
|
||||
|
||||
expect.soft(sources.get('JavaScript')!.text).toContain(`
|
||||
await page.locator('#frame1').contentFrame().locator('iframe').contentFrame().locator('iframe[name="one"]').contentFrame().getByText('HelloNameOne').click();`);
|
||||
|
||||
expect.soft(sources.get('Java')!.text).toContain(`
|
||||
page.locator("#frame1").contentFrame().locator("iframe").contentFrame().locator("iframe[name=\\"one\\"]").contentFrame().getByText("HelloNameOne").click();`);
|
||||
|
||||
expect.soft(sources.get('Python')!.text).toContain(`
|
||||
page.locator("#frame1").content_frame.locator("iframe").content_frame.locator("iframe[name=\\"one\\"]").content_frame.get_by_text("HelloNameOne").click()`);
|
||||
|
||||
expect.soft(sources.get('Python Async')!.text).toContain(`
|
||||
await page.locator("#frame1").content_frame.locator("iframe").content_frame.locator("iframe[name=\\"one\\"]").content_frame.get_by_text("HelloNameOne").click()`);
|
||||
|
||||
expect.soft(sources.get('C#')!.text).toContain(`
|
||||
await page.Locator("#frame1").ContentFrame.Locator("iframe").ContentFrame.Locator("iframe[name=\\"one\\"]").ContentFrame.GetByText("HelloNameOne").ClickAsync();`);
|
||||
|
||||
[sources] = await Promise.all([
|
||||
recorder.waitForOutput('JavaScript', 'HelloNameAnonymous'),
|
||||
frameAnonymous.click('text=HelloNameAnonymous'),
|
||||
@ -758,3 +811,31 @@ await page.GetByLabel("Coun\\"try").ClickAsync();`);
|
||||
await expect(recorder.page.locator('x-pw-glass')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
async function createFrameHierarchy(page: Page, recorder: Recorder, server: TestServer) {
|
||||
/*
|
||||
iframe
|
||||
div Hello1
|
||||
iframe
|
||||
div Hello2
|
||||
iframe[name=one]
|
||||
div HelloNameOne
|
||||
iframe
|
||||
dev HelloAnonymous
|
||||
*/
|
||||
await recorder.setContentAndWait(`
|
||||
<iframe id=frame1 srcdoc="<div>Hello1</div><iframe srcdoc='<div>Hello2</div><iframe name=one></iframe><iframe name=two></iframe><iframe></iframe>'>">
|
||||
`, server.EMPTY_PAGE, 6);
|
||||
const frameHello1 = page.mainFrame().childFrames()[0];
|
||||
const frameHello2 = frameHello1.childFrames()[0];
|
||||
const frameTwo = page.frame({ name: 'two' })!;
|
||||
await frameTwo.setContent(`<div>HelloNameTwo</div>`);
|
||||
const frameAnonymous = frameHello2.childFrames().find(f => !f.name())!;
|
||||
await frameAnonymous.setContent(`<div>HelloNameAnonymous</div>`);
|
||||
return {
|
||||
frameHello1,
|
||||
frameHello2,
|
||||
frameTwo,
|
||||
frameAnonymous,
|
||||
};
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ export const test = contextTest.extend<CLITestArgs>({
|
||||
},
|
||||
});
|
||||
|
||||
class Recorder {
|
||||
export class Recorder {
|
||||
page: Page;
|
||||
_highlightCallback: Function;
|
||||
_highlightInstalled: boolean;
|
||||
|
Loading…
x
Reference in New Issue
Block a user