fix(recorder): remove waitForNavigation from codegen (#14166)

This commit is contained in:
Pavel Feldman 2022-05-18 10:02:09 -07:00 committed by GitHub
parent b5beeab98b
commit d5ea1b38f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 58 additions and 102 deletions

View File

@ -136,7 +136,6 @@ export class CodeGenerator extends EventEmitter {
return; return;
if (signal.name === 'download' && signals.length && signals[signals.length - 1].name === 'navigation') if (signal.name === 'download' && signals.length && signals[signals.length - 1].name === 'navigation')
signals.length = signals.length - 1; signals.length = signals.length - 1;
signal.isAsync = true;
this._lastAction.action.signals.push(signal); this._lastAction.action.signals.push(signal);
this.emit('change'); this.emit('change');
return; return;

View File

@ -70,17 +70,7 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
const lines: string[] = []; const lines: string[] = [];
const actionCall = this._generateActionCall(action, actionInContext.frame.isMainFrame); const actionCall = this._generateActionCall(action, actionInContext.frame.isMainFrame);
if (signals.waitForNavigation) { lines.push(`await ${subject}.${actionCall};`);
lines.push(`await ${pageAlias}.RunAndWaitForNavigationAsync(async () =>`);
lines.push(`{`);
lines.push(` await ${subject}.${actionCall};`);
lines.push(`}/*, new ${actionInContext.frame.isMainFrame ? 'Page' : 'Frame'}WaitForNavigationOptions`);
lines.push(`{`);
lines.push(` UrlString = ${quote(signals.waitForNavigation.url)}`);
lines.push(`}*/);`);
} else {
lines.push(`await ${subject}.${actionCall};`);
}
if (signals.download) { if (signals.download) {
lines.unshift(`var download${signals.download.downloadAlias} = await ${pageAlias}.RunAndWaitForDownloadAsync(async () =>\n{`); lines.unshift(`var download${signals.download.downloadAlias} = await ${pageAlias}.RunAndWaitForDownloadAsync(async () =>\n{`);
@ -96,7 +86,7 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
formatter.add(line); formatter.add(line);
if (signals.assertNavigation) if (signals.assertNavigation)
formatter.add(` // Assert.AreEqual(${quote(signals.assertNavigation.url)}, ${pageAlias}.Url);`); formatter.add(`await ${pageAlias}.WaitForURLAsync(${quote(signals.assertNavigation.url)});`);
return formatter.format(); return formatter.format();
} }

View File

@ -81,18 +81,10 @@ export class JavaLanguageGenerator implements LanguageGenerator {
});`; });`;
} }
if (signals.waitForNavigation) {
code = `
// ${pageAlias}.waitForNavigation(new Page.WaitForNavigationOptions().setUrl(${quote(signals.waitForNavigation.url)}), () ->
${pageAlias}.waitForNavigation(() -> {
${code}
});`;
}
formatter.add(code); formatter.add(code);
if (signals.assertNavigation) if (signals.assertNavigation)
formatter.add(`// assertThat(${pageAlias}).hasURL(${quote(signals.assertNavigation.url)});`); formatter.add(`assertThat(${pageAlias}).hasURL(${quote(signals.assertNavigation.url)});`);
return formatter.format(); return formatter.format();
} }

View File

@ -75,7 +75,7 @@ export class JavaScriptLanguageGenerator implements LanguageGenerator {
});`); });`);
} }
const emitPromiseAll = signals.waitForNavigation || signals.popup || signals.download; const emitPromiseAll = signals.popup || signals.download;
if (emitPromiseAll) { if (emitPromiseAll) {
// Generate either await Promise.all([]) or // Generate either await Promise.all([]) or
// const [popup1] = await Promise.all([]). // const [popup1] = await Promise.all([]).
@ -91,26 +91,22 @@ export class JavaScriptLanguageGenerator implements LanguageGenerator {
if (signals.popup) if (signals.popup)
formatter.add(`${pageAlias}.waitForEvent('popup'),`); formatter.add(`${pageAlias}.waitForEvent('popup'),`);
// Navigation signal.
if (signals.waitForNavigation)
formatter.add(`${pageAlias}.waitForNavigation(/*{ url: ${quote(signals.waitForNavigation.url)} }*/),`);
// Download signals. // Download signals.
if (signals.download) if (signals.download)
formatter.add(`${pageAlias}.waitForEvent('download'),`); formatter.add(`${pageAlias}.waitForEvent('download'),`);
const prefix = (signals.popup || signals.waitForNavigation || signals.download) ? '' : 'await '; const prefix = (signals.popup || signals.download) ? '' : 'await ';
const actionCall = this._generateActionCall(action); const actionCall = this._generateActionCall(action);
const suffix = (signals.waitForNavigation || emitPromiseAll) ? '' : ';'; const suffix = emitPromiseAll ? '' : ';';
formatter.add(`${prefix}${subject}.${actionCall}${suffix}`); formatter.add(`${prefix}${subject}.${actionCall}${suffix}`);
if (emitPromiseAll) { if (emitPromiseAll) {
formatter.add(`]);`); formatter.add(`]);`);
} else if (signals.assertNavigation) { } else if (signals.assertNavigation) {
if (this._isTest) if (this._isTest)
formatter.add(` await expect(${pageAlias}).toHaveURL(${quote(signals.assertNavigation.url)});`); formatter.add(`await expect(${pageAlias}).toHaveURL(${quote(signals.assertNavigation.url)});`);
else else
formatter.add(` // assert.equal(${pageAlias}.url(), ${quote(signals.assertNavigation.url)});`); formatter.add(`await ${pageAlias}.waitForURL(${quote(signals.assertNavigation.url)});`);
} }
return formatter.format(); return formatter.format();
} }

View File

@ -47,15 +47,12 @@ export function sanitizeDeviceOptions(device: any, options: BrowserContextOption
} }
export function toSignalMap(action: Action) { export function toSignalMap(action: Action) {
let waitForNavigation: NavigationSignal | undefined;
let assertNavigation: NavigationSignal | undefined; let assertNavigation: NavigationSignal | undefined;
let popup: PopupSignal | undefined; let popup: PopupSignal | undefined;
let download: DownloadSignal | undefined; let download: DownloadSignal | undefined;
let dialog: DialogSignal | undefined; let dialog: DialogSignal | undefined;
for (const signal of action.signals) { for (const signal of action.signals) {
if (signal.name === 'navigation' && signal.isAsync) if (signal.name === 'navigation')
waitForNavigation = signal;
else if (signal.name === 'navigation' && !signal.isAsync)
assertNavigation = signal; assertNavigation = signal;
else if (signal.name === 'popup') else if (signal.name === 'popup')
popup = signal; popup = signal;
@ -65,7 +62,6 @@ export function toSignalMap(action: Action) {
dialog = signal; dialog = signal;
} }
return { return {
waitForNavigation,
assertNavigation, assertNavigation,
popup, popup,
download, download,

View File

@ -95,18 +95,14 @@ export class PythonLanguageGenerator implements LanguageGenerator {
download = ${this._awaitPrefix}download_info.value`; download = ${this._awaitPrefix}download_info.value`;
} }
if (signals.waitForNavigation) {
code = `
# ${this._asyncPrefix}with ${pageAlias}.expect_navigation(url=${quote(signals.waitForNavigation.url)}):
${this._asyncPrefix}with ${pageAlias}.expect_navigation() {
${code}
}`;
}
formatter.add(code); formatter.add(code);
if (signals.assertNavigation) if (signals.assertNavigation) {
formatter.add(` # ${this._awaitPrefix}expect(${pageAlias}).to_have_url(${quote(signals.assertNavigation.url)})`); if (this._isPyTest)
formatter.add(`${this._awaitPrefix}expect(${pageAlias}).to_have_url(${quote(signals.assertNavigation.url)})`);
else
formatter.add(`${this._awaitPrefix}${pageAlias}.wait_for_url(${quote(signals.assertNavigation.url)})`);
}
return formatter.format(); return formatter.format();
} }

View File

@ -96,7 +96,6 @@ export type Action = ClickAction | CheckAction | ClosesPageAction | OpenPageActi
// Signals. // Signals.
export type BaseSignal = { export type BaseSignal = {
isAsync?: boolean,
}; };
export type NavigationSignal = BaseSignal & { export type NavigationSignal = BaseSignal & {

View File

@ -607,39 +607,44 @@ test.describe('cli codegen', () => {
expect(selector).toBe('text=link'); expect(selector).toBe('text=link');
const [, sources] = await Promise.all([ const [, sources] = await Promise.all([
page.waitForNavigation(), page.waitForNavigation(),
recorder.waitForOutput('JavaScript', 'assert'), recorder.waitForOutput('JavaScript', 'waitForURL'),
page.dispatchEvent('a', 'click', { detail: 1 }) page.dispatchEvent('a', 'click', { detail: 1 })
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript').text).toContain(`
// Click text=link // Click text=link
await page.locator('text=link').click(); await page.locator('text=link').click();
// assert.equal(page.url(), 'about:blank#foo');`); await page.waitForURL('about:blank#foo');`);
expect(sources.get('Playwright Test').text).toContain(` expect.soft(sources.get('Playwright Test').text).toContain(`
// Click text=link // Click text=link
await page.locator('text=link').click(); await page.locator('text=link').click();
await expect(page).toHaveURL('about:blank#foo');`); await expect(page).toHaveURL('about:blank#foo');`);
expect(sources.get('Java').text).toContain(` expect.soft(sources.get('Java').text).toContain(`
// Click text=link // Click text=link
page.locator("text=link").click(); page.locator("text=link").click();
// assertThat(page).hasURL("about:blank#foo");`); assertThat(page).hasURL("about:blank#foo");`);
expect(sources.get('Python').text).toContain(` expect.soft(sources.get('Python').text).toContain(`
# Click text=link # Click text=link
page.locator(\"text=link\").click() page.locator("text=link").click()
# expect(page).to_have_url(\"about:blank#foo\")`); page.wait_for_url("about:blank#foo")`);
expect(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async').text).toContain(`
# Click text=link # Click text=link
await page.locator(\"text=link\").click() await page.locator("text=link").click()
# await expect(page).to_have_url(\"about:blank#foo\")`); await page.wait_for_url("about:blank#foo")`);
expect(sources.get('C#').text).toContain(` expect.soft(sources.get('Pytest').text).toContain(`
# Click text=link
page.locator("text=link").click()
expect(page).to_have_url("about:blank#foo")`);
expect.soft(sources.get('C#').text).toContain(`
// Click text=link // Click text=link
await page.Locator(\"text=link\").ClickAsync(); await page.Locator("text=link").ClickAsync();
// Assert.AreEqual(\"about:blank#foo\", page.Url);`); await page.WaitForURLAsync("about:blank#foo");`);
expect(page.url()).toContain('about:blank#foo'); expect(page.url()).toContain('about:blank#foo');
}); });
@ -655,45 +660,34 @@ test.describe('cli codegen', () => {
const [, sources] = await Promise.all([ const [, sources] = await Promise.all([
page.waitForNavigation(), page.waitForNavigation(),
recorder.waitForOutput('JavaScript', 'waitForNavigation'), recorder.waitForOutput('JavaScript', 'waitForURL'),
page.dispatchEvent('a', 'click', { detail: 1 }) page.dispatchEvent('a', 'click', { detail: 1 })
]); ]);
expect(sources.get('JavaScript').text).toContain(` expect.soft(sources.get('JavaScript').text).toContain(`
// Click text=link // Click text=link
await Promise.all([ await page.locator('text=link').click();
page.waitForNavigation(/*{ url: 'about:blank#foo' }*/), await page.waitForURL('about:blank#foo');`);
page.locator('text=link').click()
]);`);
expect(sources.get('Java').text).toContain(` expect.soft(sources.get('Java').text).toContain(`
// Click text=link // Click text=link
// page.waitForNavigation(new Page.WaitForNavigationOptions().setUrl("about:blank#foo"), () -> page.locator("text=link").click();
page.waitForNavigation(() -> { assertThat(page).hasURL("about:blank#foo");`);
page.locator("text=link").click();
});`);
expect(sources.get('Python').text).toContain(` expect.soft(sources.get('Python').text).toContain(`
# Click text=link # Click text=link
# with page.expect_navigation(url=\"about:blank#foo\"): page.locator(\"text=link\").click()
with page.expect_navigation(): page.wait_for_url("about:blank#foo")`);
page.locator(\"text=link\").click()`);
expect(sources.get('Python Async').text).toContain(` expect.soft(sources.get('Python Async').text).toContain(`
# Click text=link # Click text=link
# async with page.expect_navigation(url=\"about:blank#foo\"): await page.locator(\"text=link\").click()
async with page.expect_navigation(): await page.wait_for_url("about:blank#foo")`);
await page.locator(\"text=link\").click()`);
expect(sources.get('C#').text).toContain(` expect.soft(sources.get('C#').text).toContain(`
// Click text=link // Click text=link
await page.RunAndWaitForNavigationAsync(async () => await page.Locator(\"text=link\").ClickAsync();
{ await page.WaitForURLAsync(\"about:blank#foo\");`);
await page.Locator(\"text=link\").ClickAsync();
}/*, new PageWaitForNavigationOptions
{
UrlString = \"about:blank#foo\"
}*/);`);
expect(page.url()).toContain('about:blank#foo'); expect(page.url()).toContain('about:blank#foo');
}); });

View File

@ -532,10 +532,10 @@ test.describe('cli codegen', () => {
const [, sources] = await Promise.all([ const [, sources] = await Promise.all([
// This will click, finish the click, then mouse move, then navigate. // This will click, finish the click, then mouse move, then navigate.
page.click('button'), page.click('button'),
recorder.waitForOutput('JavaScript', 'waitForNavigation'), recorder.waitForOutput('JavaScript', 'waitForURL'),
]); ]);
expect(sources.get('JavaScript').text).toContain(`page.waitForNavigation(/*{ url: '${server.EMPTY_PAGE}' }*/)`); expect(sources.get('JavaScript').text).toContain(`page.waitForURL('${server.EMPTY_PAGE}')`);
}); });
test('should --save-trace', async ({ runCLI }, testInfo) => { test('should --save-trace', async ({ runCLI }, testInfo) => {

View File

@ -115,18 +115,12 @@ class Recorder {
} }
async waitForOutput(file: string, text: string): Promise<Map<string, Source>> { async waitForOutput(file: string, text: string): Promise<Map<string, Source>> {
const sources: Source[] = await this.recorderPage.evaluate((params: { text: string, file: string }) => { const handle = await this.recorderPage.waitForFunction((params: { text: string, file: string }) => {
const w = window as any; const w = window as any;
return new Promise(f => { const source = (w.playwrightSourcesEchoForTest || []).find((s: Source) => s.file === params.file);
const poll = () => { return source && source.text.includes(params.text) ? w.playwrightSourcesEchoForTest : null;
const source = (w.playwrightSourcesEchoForTest || []).find((s: Source) => s.file === params.file); }, { text, file }, { timeout: 8000, polling: 300 });
if (source && source.text.includes(params.text)) const sources: Source[] = await handle.jsonValue();
f(w.playwrightSourcesEchoForTest);
setTimeout(poll, 300);
};
poll();
});
}, { text, file });
for (const source of sources) for (const source of sources)
this._sources.set(source.file, source); this._sources.set(source.file, source);
return this._sources; return this._sources;