Skip to content

Commit c921c38

Browse files
authored
feat(codegen): add user-data-dir option (#35814)
1 parent 86bd3eb commit c921c38

File tree

3 files changed

+81
-34
lines changed

3 files changed

+81
-34
lines changed

docs/src/codegen.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,30 @@ pwsh bin/Debug/netX/playwright.ps1 codegen --load-storage=auth.json github.com/m
414414

415415
<img width="1394" alt="github signed in showing use of load storage scharp" src="https://user-images.githubusercontent.com/13063165/220928354-caa0e958-fe09-4125-9b54-67483064da51.png" />
416416

417+
#### Use existing userDataDir
418+
419+
Run `codegen` with `--user-data-dir` to set a fixed [user data directory](https://playwright.dev/docs/api/class-browsertype#browser-type-launch-persistent-context-option-user-data-dir) for the browser session. If you create a custom browser user data directory, codegen will use this existing browser profile and have access to any authentication state present in that profile.
420+
421+
:::warning
422+
[As of Chrome 136, the default user data directory cannot be accessed via automated tooling](https://developer.chrome.com/blog/remote-debugging-port), such as Playwright. You must create a separate user data directory for use in testing.
423+
:::
424+
425+
```bash js
426+
npx playwright codegen --user-data-dir=/path/to/your/browser/data/ github.com/microsoft/playwright
427+
```
428+
429+
```bash java
430+
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="codegen --user-data-dir=/path/to/your/browser/data/ github.com/microsoft/playwright"
431+
```
432+
433+
```bash python
434+
playwright codegen --user-data-dir=/path/to/your/browser/data/ github.com/microsoft/playwright
435+
```
436+
437+
```bash csharp
438+
pwsh bin/Debug/netX/playwright.ps1 codegen --user-data-dir=/path/to/your/browser/data/ github.com/microsoft/playwright
439+
```
440+
417441
## Record using custom setup
418442

419443
If you would like to use codegen in some non-standard setup (for example, use [`method: BrowserContext.route`]), it is possible to call [`method: Page.pause`] that will open a separate window with codegen controls.

packages/playwright-core/src/cli/program.ts

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ type Options = {
430430
timezone?: string;
431431
viewportSize?: string;
432432
userAgent?: string;
433+
userDataDir?: string;
433434
};
434435

435436
type CaptureOptions = {
@@ -479,37 +480,6 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
479480
launchOptions.proxy.bypass = options.proxyBypass;
480481
}
481482

482-
const browser = await browserType.launch(launchOptions);
483-
484-
if (process.env.PWTEST_CLI_IS_UNDER_TEST) {
485-
(process as any)._didSetSourcesForTest = (text: string) => {
486-
process.stdout.write('\n-------------8<-------------\n');
487-
process.stdout.write(text);
488-
process.stdout.write('\n-------------8<-------------\n');
489-
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
490-
if (autoExitCondition && text.includes(autoExitCondition)) {
491-
// Firefox needs a break here
492-
setTimeout(() => {
493-
closeBrowser();
494-
}, 1000);
495-
}
496-
};
497-
// Make sure we exit abnormally when browser crashes.
498-
const logs: string[] = [];
499-
require('playwright-core/lib/utilsBundle').debug.log = (...args: any[]) => {
500-
const line = require('util').format(...args) + '\n';
501-
logs.push(line);
502-
process.stderr.write(line);
503-
};
504-
browser.on('disconnected', () => {
505-
const hasCrashLine = logs.some(line => line.includes('process did exit:') && !line.includes('process did exit: exitCode=0, signal=null'));
506-
if (hasCrashLine) {
507-
process.stderr.write('Detected browser crash.\n');
508-
gracefullyProcessExitDoNotHang(1);
509-
}
510-
});
511-
}
512-
513483
// Viewport size
514484
if (options.viewportSize) {
515485
try {
@@ -574,9 +544,41 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
574544
contextOptions.serviceWorkers = 'block';
575545
}
576546

577-
// Close app when the last window closes.
547+
let browser: Browser;
548+
let context: BrowserContext;
578549

579-
const context = await browser.newContext(contextOptions);
550+
if (options.userDataDir) {
551+
context = await browserType.launchPersistentContext(options.userDataDir, { ...launchOptions, ...contextOptions });
552+
browser = context.browser()!;
553+
} else {
554+
browser = await browserType.launch(launchOptions);
555+
context = await browser.newContext(contextOptions);
556+
}
557+
558+
if (process.env.PWTEST_CLI_IS_UNDER_TEST) {
559+
(process as any)._didSetSourcesForTest = (text: string) => {
560+
process.stdout.write('\n-------------8<-------------\n');
561+
process.stdout.write(text);
562+
process.stdout.write('\n-------------8<-------------\n');
563+
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
564+
if (autoExitCondition && text.includes(autoExitCondition))
565+
closeBrowser();
566+
};
567+
// Make sure we exit abnormally when browser crashes.
568+
const logs: string[] = [];
569+
require('playwright-core/lib/utilsBundle').debug.log = (...args: any[]) => {
570+
const line = require('util').format(...args) + '\n';
571+
logs.push(line);
572+
process.stderr.write(line);
573+
};
574+
browser.on('disconnected', () => {
575+
const hasCrashLine = logs.some(line => line.includes('process did exit:') && !line.includes('process did exit: exitCode=0, signal=null'));
576+
if (hasCrashLine) {
577+
process.stderr.write('Detected browser crash.\n');
578+
gracefullyProcessExitDoNotHang(1);
579+
}
580+
});
581+
}
580582

581583
let closingBrowser = false;
582584
async function closeBrowser() {
@@ -620,7 +622,9 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
620622
}
621623

622624
async function openPage(context: BrowserContext, url: string | undefined): Promise<Page> {
623-
const page = await context.newPage();
625+
let page = context.pages()[0];
626+
if (!page)
627+
page = await context.newPage();
624628
if (url) {
625629
if (fs.existsSync(url))
626630
url = 'file://' + path.resolve(url);
@@ -759,6 +763,7 @@ function commandWithOpenOptions(command: string, description: string, options: a
759763
.option('--timezone <time zone>', 'time zone to emulate, for example "Europe/Rome"')
760764
.option('--timeout <timeout>', 'timeout for Playwright actions in milliseconds, no timeout by default')
761765
.option('--user-agent <ua string>', 'specify user agent string')
766+
.option('--user-data-dir <directory>', 'use the specified user data directory instead of a new context')
762767
.option('--viewport-size <size>', 'specify browser viewport size in pixels, for example "1280, 720"');
763768
}
764769

tests/installation/playwright-cli.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import { test, expect } from './npmTest';
1717
import path from 'path';
1818
import fs from 'fs';
19+
import os from 'os';
1920

2021
test('cli should work', async ({ exec, tmpWorkspace }) => {
2122
await exec('npm i playwright');
@@ -31,6 +32,23 @@ test('cli should work', async ({ exec, tmpWorkspace }) => {
3132
expect(result).toContain(`{ page }`);
3233
});
3334

35+
await test.step('codegen with user data dir', async () => {
36+
const userDataDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'playwright-test-custom-user-data-dir'));
37+
38+
try {
39+
const result = await exec(`npx playwright codegen --user-data-dir ${userDataDir} about:blank`, {
40+
env: {
41+
PWTEST_CLI_IS_UNDER_TEST: '1',
42+
PWTEST_CLI_AUTO_EXIT_WHEN: `goto('about:blank')`,
43+
}
44+
});
45+
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
46+
expect(result).toContain(`{ page }`);
47+
} finally {
48+
fs.rmdirSync(userDataDir, { recursive: true });
49+
}
50+
});
51+
3452
await test.step('codegen --target=javascript', async () => {
3553
const result = await exec('npx playwright codegen --target=javascript', {
3654
env: {

0 commit comments

Comments
 (0)