browser-commander 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +25 -4
- package/package.json +1 -1
- package/src/browser/launch-options.js +68 -10
- package/src/browser/launcher.js +13 -3
- package/src/browser/real-browser.js +24 -4
- package/src/core/constants.js +1 -0
- package/src/exports.js +4 -1
- package/tests/unit/browser/launch-options.test.js +55 -0
- package/tests/unit/browser/real-browser.test.js +26 -1
- package/tests/unit/core/constants.test.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b3560c8: Apply automation-friendly Chromium launch defaults, including `--password-store=basic`, and add append/opt-out launch argument controls.
|
|
8
|
+
|
|
9
|
+
## 0.14.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- d22b80e: Add the `launchRealBrowser()` API name for launching and attaching to a genuine installed Chrome-family browser.
|
|
14
|
+
|
|
3
15
|
## 0.13.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -103,9 +103,17 @@ const { browser, page } = await launchBrowser({
|
|
|
103
103
|
channel: 'chrome',
|
|
104
104
|
// Or: executablePath: '/usr/bin/google-chrome',
|
|
105
105
|
headless: true,
|
|
106
|
+
extraArgs: ['--lang=en-US'],
|
|
107
|
+
// Per-flag escape hatch; `args` remains a compatible append-only alias.
|
|
108
|
+
ignoreDefaultArgs: ['--disable-infobars'],
|
|
106
109
|
});
|
|
107
110
|
```
|
|
108
111
|
|
|
112
|
+
Browser Commander applies the documented
|
|
113
|
+
[automation-friendly launch defaults](../docs/feature-parity.md#automation-friendly-launch-defaults),
|
|
114
|
+
including `--password-store=basic` to avoid an additional OS credential
|
|
115
|
+
dialog. `ignoreDefaultArgs: true` omits every Browser Commander default.
|
|
116
|
+
|
|
109
117
|
Attach to a Chrome-family browser that is already listening for CDP connections:
|
|
110
118
|
|
|
111
119
|
```javascript
|
|
@@ -118,19 +126,25 @@ const { browser, page } = await connectBrowser({
|
|
|
118
126
|
const commander = makeBrowserCommander({ page });
|
|
119
127
|
```
|
|
120
128
|
|
|
121
|
-
|
|
129
|
+
Attachment cannot change the existing process's launch arguments. Start it
|
|
130
|
+
with a loopback remote-debugging port, a dedicated `--user-data-dir`, and the
|
|
131
|
+
automation-friendly defaults above, or use `launchRealBrowser()`.
|
|
132
|
+
|
|
133
|
+
`launchRealBrowser()` can find and start a genuine installed Chrome,
|
|
122
134
|
Edge, Brave, or Chromium with a loopback CDP endpoint and then attach to it. It
|
|
123
135
|
always uses a dedicated profile; Chrome 136 and newer do not honor remote
|
|
124
136
|
debugging switches for the default profile. See the
|
|
125
137
|
[Chrome remote-debugging security change](https://developer.chrome.com/blog/remote-debugging-port).
|
|
126
138
|
|
|
127
139
|
```javascript
|
|
128
|
-
import {
|
|
140
|
+
import { launchRealBrowser } from 'browser-commander';
|
|
129
141
|
|
|
130
|
-
const connection = await
|
|
142
|
+
const connection = await launchRealBrowser({
|
|
131
143
|
engine: 'puppeteer',
|
|
132
144
|
channel: 'chrome',
|
|
133
145
|
userDataDir: '/tmp/my-automation-profile',
|
|
146
|
+
extraArgs: ['--lang=en-US'],
|
|
147
|
+
ignoreDefaultArgs: ['--disable-infobars'],
|
|
134
148
|
seedCookies: [
|
|
135
149
|
{ name: 'session', value: 'saved', url: 'https://example.com' },
|
|
136
150
|
],
|
|
@@ -140,6 +154,9 @@ await connection.browser.close();
|
|
|
140
154
|
|
|
141
155
|
Cookie seeding copies only cookies you explicitly provide; the helper does not
|
|
142
156
|
read, decrypt, or expose cookies from a browser's default profile.
|
|
157
|
+
`launchAndConnectRealBrowser()` remains available as a descriptive alias.
|
|
158
|
+
Remote-debugging, loopback, and profile arguments remain managed even when all
|
|
159
|
+
optional defaults are ignored; `headless: true` adds `--headless=new`.
|
|
143
160
|
|
|
144
161
|
Reuse a saved authenticated session by passing Playwright-compatible storage
|
|
145
162
|
state as a JSON file path or object. Cookies and localStorage are restored for
|
|
@@ -359,7 +376,7 @@ const { browser, page } = await connectBrowser({
|
|
|
359
376
|
Playwright accepts `timeout` and Puppeteer accepts `protocolTimeout`.
|
|
360
377
|
`storageState` can also seed Playwright-compatible cookies and localStorage.
|
|
361
378
|
|
|
362
|
-
###
|
|
379
|
+
### launchRealBrowser(options)
|
|
363
380
|
|
|
364
381
|
Start an installed browser and connect through `connectBrowser()`. Use
|
|
365
382
|
`channel` (`chrome`, `chrome-beta`, `chrome-dev`, `chrome-canary`, `msedge`,
|
|
@@ -369,6 +386,10 @@ a managed directory under `~/.browser-commander/real-browser/`, rejects known
|
|
|
369
386
|
default browser-profile paths, protects its remote-debugging arguments, and
|
|
370
387
|
returns the spawned `browserProcess`, resolved `cdpEndpoint`, executable path,
|
|
371
388
|
and profile path alongside `{ browser, page }`.
|
|
389
|
+
`launchAndConnectRealBrowser()` is an alias with identical behavior.
|
|
390
|
+
`extraArgs` appends custom switches, while `ignoreDefaultArgs` accepts a list
|
|
391
|
+
of defaults to omit (or `true` to omit all optional defaults). The older
|
|
392
|
+
`args` append option remains supported.
|
|
372
393
|
|
|
373
394
|
### saveStorageState(page, filePath)
|
|
374
395
|
|
package/package.json
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
import { CHROME_ARGS } from '../core/constants.js';
|
|
2
|
+
|
|
3
|
+
function stringArray(value, name) {
|
|
4
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
5
|
+
throw new TypeError(`${name} must be an array of strings`);
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Resolve Browser Commander defaults, compatibility args, and extra args. */
|
|
11
|
+
export function resolveChromeArgs({
|
|
12
|
+
args = [],
|
|
13
|
+
extraArgs = [],
|
|
14
|
+
ignoreDefaultArgs = [],
|
|
15
|
+
} = {}) {
|
|
16
|
+
stringArray(args, 'args');
|
|
17
|
+
stringArray(extraArgs, 'extraArgs');
|
|
18
|
+
if (
|
|
19
|
+
typeof ignoreDefaultArgs !== 'boolean' &&
|
|
20
|
+
!Array.isArray(ignoreDefaultArgs)
|
|
21
|
+
) {
|
|
22
|
+
throw new TypeError('ignoreDefaultArgs must be a boolean or string array');
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(ignoreDefaultArgs)) {
|
|
25
|
+
stringArray(ignoreDefaultArgs, 'ignoreDefaultArgs');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const normalizedIgnoreDefaultArgs =
|
|
29
|
+
ignoreDefaultArgs === false ? [] : ignoreDefaultArgs;
|
|
30
|
+
const ignored = new Set(
|
|
31
|
+
normalizedIgnoreDefaultArgs === true
|
|
32
|
+
? CHROME_ARGS
|
|
33
|
+
: normalizedIgnoreDefaultArgs
|
|
34
|
+
);
|
|
35
|
+
return {
|
|
36
|
+
args: [
|
|
37
|
+
...CHROME_ARGS.filter((argument) => !ignored.has(argument)),
|
|
38
|
+
...args,
|
|
39
|
+
...extraArgs,
|
|
40
|
+
],
|
|
41
|
+
ignoreDefaultArgs: normalizedIgnoreDefaultArgs,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
1
45
|
function setBrowserSelectionOptions(options, { channel, executablePath }) {
|
|
2
46
|
if (channel !== undefined) {
|
|
3
47
|
options.channel = channel;
|
|
@@ -15,14 +59,21 @@ export function buildPlaywrightLaunchOptions({
|
|
|
15
59
|
colorScheme,
|
|
16
60
|
channel,
|
|
17
61
|
executablePath,
|
|
62
|
+
ignoreDefaultArgs = [],
|
|
18
63
|
}) {
|
|
64
|
+
const normalizedIgnoreDefaultArgs =
|
|
65
|
+
ignoreDefaultArgs === false ? [] : ignoreDefaultArgs;
|
|
66
|
+
const engineIgnoreDefaultArgs =
|
|
67
|
+
normalizedIgnoreDefaultArgs === true
|
|
68
|
+
? true
|
|
69
|
+
: [...new Set(['--enable-automation', ...normalizedIgnoreDefaultArgs])];
|
|
19
70
|
const options = {
|
|
20
71
|
headless,
|
|
21
72
|
slowMo,
|
|
22
73
|
chromiumSandbox: true,
|
|
23
74
|
viewport: null,
|
|
24
75
|
args: chromeArgs,
|
|
25
|
-
ignoreDefaultArgs:
|
|
76
|
+
ignoreDefaultArgs: engineIgnoreDefaultArgs,
|
|
26
77
|
};
|
|
27
78
|
|
|
28
79
|
if (colorScheme !== undefined) {
|
|
@@ -38,14 +89,21 @@ export function buildPuppeteerLaunchOptions({
|
|
|
38
89
|
userDataDir,
|
|
39
90
|
channel,
|
|
40
91
|
executablePath,
|
|
92
|
+
ignoreDefaultArgs = [],
|
|
41
93
|
}) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
94
|
+
const normalizedIgnoreDefaultArgs =
|
|
95
|
+
ignoreDefaultArgs === false ? [] : ignoreDefaultArgs;
|
|
96
|
+
const options = {
|
|
97
|
+
headless,
|
|
98
|
+
defaultViewport: null,
|
|
99
|
+
args: ['--start-maximized', ...chromeArgs],
|
|
100
|
+
userDataDir,
|
|
101
|
+
};
|
|
102
|
+
if (
|
|
103
|
+
normalizedIgnoreDefaultArgs === true ||
|
|
104
|
+
normalizedIgnoreDefaultArgs.length > 0
|
|
105
|
+
) {
|
|
106
|
+
options.ignoreDefaultArgs = normalizedIgnoreDefaultArgs;
|
|
107
|
+
}
|
|
108
|
+
return setBrowserSelectionOptions(options, { channel, executablePath });
|
|
51
109
|
}
|
package/src/browser/launcher.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import os from 'os';
|
|
3
|
-
import { CHROME_ARGS } from '../core/constants.js';
|
|
4
3
|
import { disableTranslateInPreferences } from '../core/preferences.js';
|
|
5
4
|
import { emulateMedia } from './media.js';
|
|
6
5
|
import {
|
|
7
6
|
buildPlaywrightLaunchOptions,
|
|
8
7
|
buildPuppeteerLaunchOptions,
|
|
8
|
+
resolveChromeArgs,
|
|
9
9
|
} from './launch-options.js';
|
|
10
10
|
import {
|
|
11
11
|
loadStorageState,
|
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
* @param {number} options.slowMo - Slow down operations by ms (default: 150 for Playwright, 0 for Puppeteer)
|
|
23
23
|
* @param {boolean} options.verbose - Enable verbose logging (default: false)
|
|
24
24
|
* @param {string[]} options.args - Custom Chrome arguments to append to the default CHROME_ARGS
|
|
25
|
+
* @param {string[]} [options.extraArgs] - Additional Chrome arguments appended after legacy args
|
|
26
|
+
* @param {boolean|string[]} [options.ignoreDefaultArgs] - Browser Commander defaults to omit, or true for all
|
|
25
27
|
* @param {string|null} [options.colorScheme] - Emulate color scheme: 'light', 'dark', 'no-preference', or null to reset
|
|
26
28
|
* @param {string} [options.channel] - Installed browser channel, such as 'chrome', 'chrome-beta', or 'msedge'
|
|
27
29
|
* @param {string} [options.executablePath] - Explicit path to a Chrome or Chromium executable
|
|
@@ -36,14 +38,20 @@ export async function launchBrowser(options = {}) {
|
|
|
36
38
|
slowMo = engine === 'playwright' ? 150 : 0,
|
|
37
39
|
verbose = false,
|
|
38
40
|
args = [],
|
|
41
|
+
extraArgs = [],
|
|
42
|
+
ignoreDefaultArgs = [],
|
|
39
43
|
colorScheme,
|
|
40
44
|
channel,
|
|
41
45
|
executablePath,
|
|
42
46
|
storageState,
|
|
43
47
|
} = options;
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
const resolvedChromeArgs = resolveChromeArgs({
|
|
50
|
+
args,
|
|
51
|
+
extraArgs,
|
|
52
|
+
ignoreDefaultArgs,
|
|
53
|
+
});
|
|
54
|
+
const chromeArgs = resolvedChromeArgs.args;
|
|
47
55
|
|
|
48
56
|
if (!['playwright', 'puppeteer'].includes(engine)) {
|
|
49
57
|
throw new Error(
|
|
@@ -77,6 +85,7 @@ export async function launchBrowser(options = {}) {
|
|
|
77
85
|
colorScheme,
|
|
78
86
|
channel,
|
|
79
87
|
executablePath,
|
|
88
|
+
ignoreDefaultArgs: resolvedChromeArgs.ignoreDefaultArgs,
|
|
80
89
|
});
|
|
81
90
|
browser = await chromium.launchPersistentContext(
|
|
82
91
|
userDataDir,
|
|
@@ -96,6 +105,7 @@ export async function launchBrowser(options = {}) {
|
|
|
96
105
|
userDataDir,
|
|
97
106
|
channel,
|
|
98
107
|
executablePath,
|
|
108
|
+
ignoreDefaultArgs: resolvedChromeArgs.ignoreDefaultArgs,
|
|
99
109
|
})
|
|
100
110
|
);
|
|
101
111
|
const pages = await browser.pages();
|
|
@@ -5,6 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
7
|
import { connectBrowser } from './connector.js';
|
|
8
|
+
import { resolveChromeArgs } from './launch-options.js';
|
|
8
9
|
|
|
9
10
|
const MANAGED_ARGUMENTS = [
|
|
10
11
|
'--remote-debugging-address',
|
|
@@ -240,6 +241,8 @@ export function buildRealBrowserArgs({
|
|
|
240
241
|
remoteDebuggingPort = 0,
|
|
241
242
|
headless = false,
|
|
242
243
|
args = [],
|
|
244
|
+
extraArgs = [],
|
|
245
|
+
ignoreDefaultArgs = [],
|
|
243
246
|
}) {
|
|
244
247
|
if (
|
|
245
248
|
!Number.isInteger(remoteDebuggingPort) ||
|
|
@@ -250,7 +253,8 @@ export function buildRealBrowserArgs({
|
|
|
250
253
|
'remoteDebuggingPort must be an integer from 0 to 65535'
|
|
251
254
|
);
|
|
252
255
|
}
|
|
253
|
-
const
|
|
256
|
+
const customArgs = [...args, ...extraArgs];
|
|
257
|
+
const conflictingArgument = customArgs.find((argument) =>
|
|
254
258
|
MANAGED_ARGUMENTS.some(
|
|
255
259
|
(managed) => argument === managed || argument.startsWith(`${managed}=`)
|
|
256
260
|
)
|
|
@@ -261,14 +265,15 @@ export function buildRealBrowserArgs({
|
|
|
261
265
|
);
|
|
262
266
|
}
|
|
263
267
|
|
|
268
|
+
const defaultArgs = resolveChromeArgs({ ignoreDefaultArgs }).args;
|
|
269
|
+
|
|
264
270
|
return [
|
|
265
271
|
'--remote-debugging-address=127.0.0.1',
|
|
266
272
|
`--remote-debugging-port=${remoteDebuggingPort}`,
|
|
267
273
|
`--user-data-dir=${userDataDir}`,
|
|
268
|
-
|
|
269
|
-
'--no-default-browser-check',
|
|
274
|
+
...defaultArgs,
|
|
270
275
|
...(headless ? ['--headless=new'] : []),
|
|
271
|
-
...
|
|
276
|
+
...customArgs,
|
|
272
277
|
];
|
|
273
278
|
}
|
|
274
279
|
|
|
@@ -353,6 +358,8 @@ export async function waitForCdpEndpoint({
|
|
|
353
358
|
* @param {number} [options.remoteDebuggingPort=0] - Loopback CDP port; zero lets Chrome choose
|
|
354
359
|
* @param {boolean} [options.headless=false] - Run the installed browser headlessly
|
|
355
360
|
* @param {string[]} [options.args] - Additional browser arguments
|
|
361
|
+
* @param {string[]} [options.extraArgs] - Additional browser arguments appended after legacy args
|
|
362
|
+
* @param {boolean|string[]} [options.ignoreDefaultArgs] - Browser Commander defaults to omit, or true for all
|
|
356
363
|
* @param {number} [options.startupTimeout=30000] - CDP readiness timeout in milliseconds
|
|
357
364
|
* @param {Object[]} [options.seedCookies] - Cookies to seed after connecting
|
|
358
365
|
* @param {boolean} [options.verbose=false] - Show browser and connection logs
|
|
@@ -362,6 +369,15 @@ export async function launchAndConnectRealBrowser(options = {}) {
|
|
|
362
369
|
return await launchAndConnectRealBrowserWithDependencies(options);
|
|
363
370
|
}
|
|
364
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Short Playwright-style name for {@link launchAndConnectRealBrowser}.
|
|
374
|
+
*
|
|
375
|
+
* Both names are the same function so existing callers can keep using the
|
|
376
|
+
* descriptive name while new code can use the API proposed for real-browser
|
|
377
|
+
* launch.
|
|
378
|
+
*/
|
|
379
|
+
export const launchRealBrowser = launchAndConnectRealBrowser;
|
|
380
|
+
|
|
365
381
|
/** Dependency-injected implementation used by the public helper and tests. */
|
|
366
382
|
export async function launchAndConnectRealBrowserWithDependencies(
|
|
367
383
|
options = {},
|
|
@@ -375,6 +391,8 @@ export async function launchAndConnectRealBrowserWithDependencies(
|
|
|
375
391
|
remoteDebuggingPort = 0,
|
|
376
392
|
headless = false,
|
|
377
393
|
args = [],
|
|
394
|
+
extraArgs = [],
|
|
395
|
+
ignoreDefaultArgs = [],
|
|
378
396
|
startupTimeout = 30_000,
|
|
379
397
|
verbose = false,
|
|
380
398
|
cdpEndpoint,
|
|
@@ -400,6 +418,8 @@ export async function launchAndConnectRealBrowserWithDependencies(
|
|
|
400
418
|
remoteDebuggingPort,
|
|
401
419
|
headless,
|
|
402
420
|
args,
|
|
421
|
+
extraArgs,
|
|
422
|
+
ignoreDefaultArgs,
|
|
403
423
|
});
|
|
404
424
|
const spawnBrowser = dependencies.spawnBrowser ?? spawn;
|
|
405
425
|
const browserProcess = spawnBrowser(resolvedExecutablePath, browserArgs, {
|
package/src/core/constants.js
CHANGED
package/src/exports.js
CHANGED
|
@@ -43,7 +43,10 @@ export {
|
|
|
43
43
|
|
|
44
44
|
// Re-export browser management
|
|
45
45
|
export { connectBrowser } from './browser/connector.js';
|
|
46
|
-
export {
|
|
46
|
+
export {
|
|
47
|
+
launchAndConnectRealBrowser,
|
|
48
|
+
launchRealBrowser,
|
|
49
|
+
} from './browser/real-browser.js';
|
|
47
50
|
export { launchBrowser } from './browser/launcher.js';
|
|
48
51
|
export { saveStorageState } from './browser/storage-state.js';
|
|
49
52
|
export { emulateMedia } from './browser/media.js';
|
|
@@ -4,9 +4,64 @@ import assert from 'node:assert';
|
|
|
4
4
|
import {
|
|
5
5
|
buildPlaywrightLaunchOptions,
|
|
6
6
|
buildPuppeteerLaunchOptions,
|
|
7
|
+
resolveChromeArgs,
|
|
7
8
|
} from '../../../src/browser/launch-options.js';
|
|
8
9
|
|
|
9
10
|
describe('browser launch options', () => {
|
|
11
|
+
it('applies safe defaults, appends extra arguments, and supports per-flag opt-out', () => {
|
|
12
|
+
const options = resolveChromeArgs({
|
|
13
|
+
args: ['--legacy-arg'],
|
|
14
|
+
extraArgs: ['--lang=en-US'],
|
|
15
|
+
ignoreDefaultArgs: ['--no-default-browser-check'],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
assert.ok(options.args.includes('--password-store=basic'));
|
|
19
|
+
assert.ok(options.args.includes('--no-first-run'));
|
|
20
|
+
assert.equal(options.args.includes('--no-default-browser-check'), false);
|
|
21
|
+
assert.deepEqual(options.args.slice(-2), ['--legacy-arg', '--lang=en-US']);
|
|
22
|
+
assert.deepEqual(options.ignoreDefaultArgs, ['--no-default-browser-check']);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('can ignore every Browser Commander default', () => {
|
|
26
|
+
const options = resolveChromeArgs({
|
|
27
|
+
extraArgs: ['--lang=en-US'],
|
|
28
|
+
ignoreDefaultArgs: true,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
assert.deepEqual(options.args, ['--lang=en-US']);
|
|
32
|
+
assert.equal(options.ignoreDefaultArgs, true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('can opt out of the password-store default specifically', () => {
|
|
36
|
+
const options = resolveChromeArgs({
|
|
37
|
+
ignoreDefaultArgs: ['--password-store=basic'],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.equal(options.args.includes('--password-store=basic'), false);
|
|
41
|
+
assert.ok(options.args.includes('--no-first-run'));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('forwards ignored defaults to both browser engines', () => {
|
|
45
|
+
const playwright = buildPlaywrightLaunchOptions({
|
|
46
|
+
headless: false,
|
|
47
|
+
slowMo: 150,
|
|
48
|
+
chromeArgs: [],
|
|
49
|
+
ignoreDefaultArgs: ['--no-first-run'],
|
|
50
|
+
});
|
|
51
|
+
const puppeteer = buildPuppeteerLaunchOptions({
|
|
52
|
+
headless: false,
|
|
53
|
+
chromeArgs: [],
|
|
54
|
+
userDataDir: '/tmp/browser-commander-test',
|
|
55
|
+
ignoreDefaultArgs: ['--no-first-run'],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
assert.deepEqual(playwright.ignoreDefaultArgs, [
|
|
59
|
+
'--enable-automation',
|
|
60
|
+
'--no-first-run',
|
|
61
|
+
]);
|
|
62
|
+
assert.deepEqual(puppeteer.ignoreDefaultArgs, ['--no-first-run']);
|
|
63
|
+
});
|
|
64
|
+
|
|
10
65
|
it('forwards channel and executablePath to Playwright', () => {
|
|
11
66
|
const options = buildPlaywrightLaunchOptions({
|
|
12
67
|
headless: true,
|
|
@@ -9,8 +9,12 @@ import {
|
|
|
9
9
|
buildRealBrowserArgs,
|
|
10
10
|
launchAndConnectRealBrowser,
|
|
11
11
|
launchAndConnectRealBrowserWithDependencies,
|
|
12
|
+
launchRealBrowser,
|
|
12
13
|
} from '../../../src/browser/real-browser.js';
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
launchAndConnectRealBrowser as publicHelper,
|
|
16
|
+
launchRealBrowser as publicShortHelper,
|
|
17
|
+
} from '../../../src/index.js';
|
|
14
18
|
|
|
15
19
|
describe('launchAndConnectRealBrowser', () => {
|
|
16
20
|
let temporaryDirectory;
|
|
@@ -24,6 +28,8 @@ describe('launchAndConnectRealBrowser', () => {
|
|
|
24
28
|
|
|
25
29
|
it('is exported from the package API', () => {
|
|
26
30
|
assert.equal(publicHelper, launchAndConnectRealBrowser);
|
|
31
|
+
assert.equal(launchRealBrowser, launchAndConnectRealBrowser);
|
|
32
|
+
assert.equal(publicShortHelper, launchRealBrowser);
|
|
27
33
|
});
|
|
28
34
|
|
|
29
35
|
it('builds a loopback-only CDP command with a dedicated profile', () => {
|
|
@@ -38,13 +44,32 @@ describe('launchAndConnectRealBrowser', () => {
|
|
|
38
44
|
'--remote-debugging-address=127.0.0.1',
|
|
39
45
|
'--remote-debugging-port=9333',
|
|
40
46
|
'--user-data-dir=/tmp/browser-commander-dedicated',
|
|
47
|
+
'--disable-session-crashed-bubble',
|
|
48
|
+
'--hide-crash-restore-bubble',
|
|
49
|
+
'--disable-infobars',
|
|
50
|
+
'--password-store=basic',
|
|
41
51
|
'--no-first-run',
|
|
42
52
|
'--no-default-browser-check',
|
|
53
|
+
'--disable-crash-restore',
|
|
43
54
|
'--headless=new',
|
|
44
55
|
'--lang=en-US',
|
|
45
56
|
]);
|
|
46
57
|
});
|
|
47
58
|
|
|
59
|
+
it('supports additive arguments and per-default opt-out', () => {
|
|
60
|
+
const args = buildRealBrowserArgs({
|
|
61
|
+
userDataDir: '/tmp/browser-commander-dedicated',
|
|
62
|
+
args: ['--legacy-arg'],
|
|
63
|
+
extraArgs: ['--lang=en-US'],
|
|
64
|
+
ignoreDefaultArgs: ['--no-first-run'],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
assert.ok(args.includes('--password-store=basic'));
|
|
68
|
+
assert.equal(args.includes('--no-first-run'), false);
|
|
69
|
+
assert.ok(args.includes('--no-default-browser-check'));
|
|
70
|
+
assert.deepEqual(args.slice(-2), ['--legacy-arg', '--lang=en-US']);
|
|
71
|
+
});
|
|
72
|
+
|
|
48
73
|
it('rejects custom arguments that could bypass protected CDP settings', () => {
|
|
49
74
|
for (const argument of [
|
|
50
75
|
'--remote-debugging-address=0.0.0.0',
|
|
@@ -10,6 +10,7 @@ describe('constants', () => {
|
|
|
10
10
|
|
|
11
11
|
it('should contain expected browser arguments', () => {
|
|
12
12
|
assert.ok(CHROME_ARGS.includes('--disable-infobars'));
|
|
13
|
+
assert.ok(CHROME_ARGS.includes('--password-store=basic'));
|
|
13
14
|
assert.ok(CHROME_ARGS.includes('--no-first-run'));
|
|
14
15
|
assert.ok(CHROME_ARGS.includes('--no-default-browser-check'));
|
|
15
16
|
});
|