Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions packages/playwright-core/src/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,14 @@ commandWithOpenOptions('codegen [url]', 'open page and generate code for user ac
['--target <language>', `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit`, codegenId()],
['--test-id-attribute <attributeName>', 'use the specified attribute to generate data test ID selectors'],
]).action(function(url, options) {
codegen(options, url).catch(logErrorAndExit);
codegen(options, url).catch(error => {
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
// in a stray navigation aborted error. We should ignore it.
} else {
throw error;
}
});
}).addHelpText('afterAll', `
Examples:

Expand Down Expand Up @@ -480,8 +487,12 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
process.stdout.write(text);
process.stdout.write('\n-------------8<-------------\n');
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
if (autoExitCondition && text.includes(autoExitCondition))
closeBrowser();
if (autoExitCondition && text.includes(autoExitCondition)) {
// Firefox needs a break here
setTimeout(() => {
closeBrowser();
}, 1000);
}
};
// Make sure we exit abnormally when browser crashes.
const logs: string[] = [];
Expand Down Expand Up @@ -615,14 +626,7 @@ async function openPage(context: BrowserContext, url: string | undefined): Promi
url = 'file://' + path.resolve(url);
else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:'))
url = 'http://' + url;
await page.goto(url).catch(error => {
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
// in a stray navigation aborted error. We should ignore it.
} else {
throw error;
}
});
await page.goto(url);
}
return page;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/playwright-core/src/server/DEPS.list
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
../utilsBundle.ts
../zipBundle.ts
./
./codegen/language.ts
./codegen/languages.ts
./codegen/
./isomorphic/
./har/
./recorder/
Expand Down
7 changes: 3 additions & 4 deletions packages/playwright-core/src/server/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import { SdkObject } from './instrumentation';
import * as network from './network';
import { InitScript } from './page';
import { Page, PageBinding } from './page';
import { Recorder } from './recorder';
import { RecorderApp } from './recorder/recorderApp';
import { Selectors } from './selectors';
import { Tracing } from './trace/recorder/tracing';
Expand Down Expand Up @@ -129,15 +128,15 @@ export abstract class BrowserContext extends SdkObject {

// When PWDEBUG=1, show inspector for each context.
if (debugMode() === 'inspector')
await Recorder.show(this, RecorderApp.factory(this), { pauseOnNextStatement: true });
await RecorderApp.show(this, { pauseOnNextStatement: true });

// When paused, show inspector.
if (this._debugger.isPaused())
Recorder.showInspectorNoReply(this, RecorderApp.factory(this));
await RecorderApp.showInspectorNoReply(this);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await RecorderApp.showInspectorNoReply(this);
RecorderApp.showInspectorNoReply(this);


this._debugger.on(Debugger.Events.PausedStateChanged, () => {
if (this._debugger.isPaused())
Recorder.showInspectorNoReply(this, RecorderApp.factory(this));
RecorderApp.showInspectorNoReply(this);
});

if (debugMode() === 'console')
Expand Down
6 changes: 3 additions & 3 deletions packages/playwright-core/src/server/codegen/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ import { PythonLanguageGenerator } from './python';

export function languageSet() {
return new Set([
new JavaLanguageGenerator('junit'),
new JavaLanguageGenerator('library'),
new JavaScriptLanguageGenerator(/* isPlaywrightTest */false),
new JavaScriptLanguageGenerator(/* isPlaywrightTest */true),
new JavaScriptLanguageGenerator(/* isPlaywrightTest */false),
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */true),
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */false),
new PythonLanguageGenerator(/* isAsync */true, /* isPytest */false),
new CSharpLanguageGenerator('mstest'),
new CSharpLanguageGenerator('nunit'),
new CSharpLanguageGenerator('library'),
new JavaLanguageGenerator('junit'),
new JavaLanguageGenerator('library'),
new JsonlLanguageGenerator(),
]);
}
44 changes: 31 additions & 13 deletions packages/playwright-core/src/server/debugController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ import { parseAriaSnapshotUnsafe } from '../utils/isomorphic/ariaSnapshot';
import { yaml } from '../utilsBundle';
import { EmptyRecorderApp } from './recorder/recorderApp';
import { unsafeLocatorOrSelectorAsSelector } from '../utils/isomorphic/locatorParser';
import { generateCode } from './codegen/language';
import { collapseActions } from './recorder/recorderUtils';
import { JavaScriptLanguageGenerator } from './codegen/javascript';

import type { Language } from '../utils';
import type { Browser } from './browser';
import type { BrowserContext } from './browserContext';
import type { InstrumentationListener } from './instrumentation';
import type { Playwright } from './playwright';
import type { ElementInfo, Mode, Source } from '@recorder/recorderTypes';
import type { ElementInfo, Mode } from '@recorder/recorderTypes';
import type { Progress } from '@protocol/progress';
import type * as actions from '@recorder/actions';

export class DebugController extends SdkObject {
static Events = {
Expand All @@ -43,15 +47,13 @@ export class DebugController extends SdkObject {
private _trackHierarchyListener: InstrumentationListener | undefined;
private _playwright: Playwright;
_sdkLanguage: Language = 'javascript';
_codegenId: string = 'playwright-test';

constructor(playwright: Playwright) {
super({ attribution: { isInternalPlaywright: true }, instrumentation: createInstrumentation() } as any, undefined, 'DebugController');
this._playwright = playwright;
}

initialize(codegenId: string, sdkLanguage: Language) {
this._codegenId = codegenId;
this._sdkLanguage = sdkLanguage;
}

Expand Down Expand Up @@ -86,8 +88,7 @@ export class DebugController extends SdkObject {
await p.mainFrame().goto(progress, url);
}

async setRecorderMode(progress: Progress, params: { mode: Mode, file?: string, testIdAttributeName?: string }) {
// TODO: |file| is only used in the legacy mode.
async setRecorderMode(progress: Progress, params: { mode: Mode, testIdAttributeName?: string }) {
await progress.race(this._closeBrowsersWithoutPages());

if (params.mode === 'none') {
Expand Down Expand Up @@ -115,8 +116,6 @@ export class DebugController extends SdkObject {
// Toggle the mode.
for (const recorder of await progress.race(this._allRecorders())) {
recorder.hideHighlightedSelector();
if (params.mode !== 'inspecting')
recorder.setOutput(this._codegenId, params.file);
recorder.setMode(params.mode);
}
}
Expand Down Expand Up @@ -188,28 +187,47 @@ export class DebugController extends SdkObject {

class InspectingRecorderApp extends EmptyRecorderApp {
private _debugController: DebugController;
private _actions: actions.ActionInContext[] = [];
private _languageGenerator: JavaScriptLanguageGenerator;

constructor(debugController: DebugController) {
super();
this._debugController = debugController;
this._languageGenerator = new JavaScriptLanguageGenerator(/* isPlaywrightTest */true);
}

override async elementPicked(elementInfo: ElementInfo): Promise<void> {
const locator: string = asLocator(this._debugController._sdkLanguage, elementInfo.selector);
this._debugController.emit(DebugController.Events.InspectRequested, { selector: elementInfo.selector, locator, ariaSnapshot: elementInfo.ariaSnapshot });
}

override async setSources(sources: Source[]): Promise<void> {
const source = sources.find(s => s.id === this._debugController._codegenId);
const { text, header, footer, actions } = source || { text: '' };
this._debugController.emit(DebugController.Events.SourceChanged, { text, header, footer, actions });
}

override async setPaused(paused: boolean) {
this._debugController.emit(DebugController.Events.Paused, { paused });
}

override async setMode(mode: Mode) {
this._debugController.emit(DebugController.Events.SetModeRequested, { mode });
}

override async actionAdded(action: actions.ActionInContext): Promise<void> {
this._actions.push(action);
this._actionsChanged();
}

override async signalAdded(signal: actions.Signal): Promise<void> {
const lastAction = this._actions[this._actions.length - 1];
if (lastAction)
lastAction.action.signals.push(signal);
this._actionsChanged();
}

private _actionsChanged() {
const actions = collapseActions(this._actions);
const { header, footer, text, actionTexts } = generateCode(actions, this._languageGenerator, {
browserName: 'chromium',
launchOptions: {},
contextOptions: {},
});
this._debugController.emit(DebugController.Events.SourceChanged, { text, header, footer, actions: actionTexts });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { APIRequestContextDispatcher, RequestDispatcher, ResponseDispatcher, Rou
import { BindingCallDispatcher, PageDispatcher, WorkerDispatcher } from './pageDispatcher';
import { CRBrowserContext } from '../chromium/crBrowser';
import { serializeError } from '../errors';
import { Recorder } from '../recorder';
import { TracingDispatcher } from './tracingDispatcher';
import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher';
import { WritableStreamDispatcher } from './writableStreamDispatcher';
Expand Down Expand Up @@ -332,7 +331,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
}

async enableRecorder(params: channels.BrowserContextEnableRecorderParams, progress: Progress): Promise<void> {
await Recorder.show(this._context, RecorderApp.factory(this._context), params);
await RecorderApp.show(this._context, params);
}

async pause(params: channels.BrowserContextPauseParams, progress: Progress) {
Expand Down
Loading
Loading