browser-commander 0.3.0 → 0.4.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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5af2479: Add support for custom Chrome args in launchBrowser
8
+
9
+ Adds a new `args` option to the `launchBrowser` function that allows passing custom Chrome arguments to append to the default `CHROME_ARGS`. This is useful for headless server environments (Docker, CI/CD) that require additional flags like `--no-sandbox`, `--disable-setuid-sandbox`, or `--disable-dev-shm-usage`.
10
+
11
+ Usage example:
12
+
13
+ ```javascript
14
+ import { launchBrowser } from 'browser-commander';
15
+
16
+ const { browser, page } = await launchBrowser({
17
+ engine: 'puppeteer',
18
+ headless: true,
19
+ args: ['--no-sandbox', '--disable-setuid-sandbox'],
20
+ });
21
+ ```
22
+
23
+ Fixes #11
24
+
3
25
  ## 0.3.0
4
26
 
5
27
  ### Minor Changes
package/README.md CHANGED
@@ -191,6 +191,21 @@ commander.pageTrigger({
191
191
 
192
192
  ## API Reference
193
193
 
194
+ ### launchBrowser(options)
195
+
196
+ ```javascript
197
+ const { browser, page } = await launchBrowser({
198
+ engine: 'playwright', // 'playwright' or 'puppeteer'
199
+ headless: false, // Run in headless mode
200
+ userDataDir: '~/.hh-apply/playwright-data', // Browser profile directory
201
+ slowMo: 150, // Slow down operations (ms)
202
+ verbose: false, // Enable debug logging
203
+ args: ['--no-sandbox', '--disable-setuid-sandbox'], // Custom Chrome args to append
204
+ });
205
+ ```
206
+
207
+ The `args` option allows passing custom Chrome arguments, which is useful for headless server environments (Docker, CI/CD) that require flags like `--no-sandbox`.
208
+
194
209
  ### makeBrowserCommander(options)
195
210
 
196
211
  ```javascript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-commander",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Universal browser automation library that supports both Playwright and Puppeteer with a unified API",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -11,6 +11,7 @@ import { disableTranslateInPreferences } from '../core/preferences.js';
11
11
  * @param {boolean} options.headless - Run in headless mode (default: false)
12
12
  * @param {number} options.slowMo - Slow down operations by ms (default: 150 for Playwright, 0 for Puppeteer)
13
13
  * @param {boolean} options.verbose - Enable verbose logging (default: false)
14
+ * @param {string[]} options.args - Custom Chrome arguments to append to the default CHROME_ARGS
14
15
  * @returns {Promise<Object>} - Object with browser and page
15
16
  */
16
17
  export async function launchBrowser(options = {}) {
@@ -20,8 +21,12 @@ export async function launchBrowser(options = {}) {
20
21
  headless = false,
21
22
  slowMo = engine === 'playwright' ? 150 : 0,
22
23
  verbose = false,
24
+ args = [],
23
25
  } = options;
24
26
 
27
+ // Combine default CHROME_ARGS with custom args
28
+ const chromeArgs = [...CHROME_ARGS, ...args];
29
+
25
30
  if (!['playwright', 'puppeteer'].includes(engine)) {
26
31
  throw new Error(
27
32
  `Invalid engine: ${engine}. Expected 'playwright' or 'puppeteer'`
@@ -50,7 +55,7 @@ export async function launchBrowser(options = {}) {
50
55
  slowMo,
51
56
  chromiumSandbox: true,
52
57
  viewport: null,
53
- args: CHROME_ARGS,
58
+ args: chromeArgs,
54
59
  ignoreDefaultArgs: ['--enable-automation'],
55
60
  });
56
61
  page = browser.pages()[0];
@@ -59,7 +64,7 @@ export async function launchBrowser(options = {}) {
59
64
  browser = await puppeteer.default.launch({
60
65
  headless,
61
66
  defaultViewport: null,
62
- args: ['--start-maximized', ...CHROME_ARGS],
67
+ args: ['--start-maximized', ...chromeArgs],
63
68
  userDataDir,
64
69
  });
65
70
  const pages = await browser.pages();
@@ -0,0 +1,126 @@
1
+ import { describe, it, mock, beforeEach, afterEach } from 'node:test';
2
+ import assert from 'node:assert';
3
+
4
+ describe('launcher', () => {
5
+ describe('launchBrowser args option', () => {
6
+ let originalEnv;
7
+ let mockChromium;
8
+ let mockPuppeteer;
9
+ let launchBrowser;
10
+ let capturedPlaywrightArgs;
11
+ let capturedPuppeteerArgs;
12
+
13
+ beforeEach(async () => {
14
+ // Save original environment
15
+ originalEnv = { ...process.env };
16
+
17
+ // Reset captured args
18
+ capturedPlaywrightArgs = null;
19
+ capturedPuppeteerArgs = null;
20
+
21
+ // Create mock browser context for Playwright
22
+ const mockBrowserContext = {
23
+ pages: () => [
24
+ {
25
+ bringToFront: async () => {},
26
+ },
27
+ ],
28
+ close: async () => {},
29
+ };
30
+
31
+ // Create mock browser for Puppeteer
32
+ const mockBrowser = {
33
+ pages: async () => [
34
+ {
35
+ bringToFront: async () => {},
36
+ },
37
+ ],
38
+ close: async () => {},
39
+ };
40
+
41
+ // Mock Playwright's chromium
42
+ mockChromium = {
43
+ launchPersistentContext: async (userDataDir, options) => {
44
+ capturedPlaywrightArgs = options.args;
45
+ return mockBrowserContext;
46
+ },
47
+ };
48
+
49
+ // Mock Puppeteer
50
+ mockPuppeteer = {
51
+ default: {
52
+ launch: async (options) => {
53
+ capturedPuppeteerArgs = options.args;
54
+ return mockBrowser;
55
+ },
56
+ },
57
+ };
58
+
59
+ // Use mock.module to mock the dynamic imports
60
+ // Since we can't easily mock dynamic imports in Node.js test runner,
61
+ // we'll test the CHROME_ARGS constant usage directly
62
+ });
63
+
64
+ afterEach(() => {
65
+ // Restore original environment
66
+ process.env = originalEnv;
67
+ });
68
+
69
+ it('should export CHROME_ARGS constant', async () => {
70
+ const { CHROME_ARGS } = await import('../../../src/core/constants.js');
71
+ assert.ok(Array.isArray(CHROME_ARGS));
72
+ assert.ok(CHROME_ARGS.length > 0);
73
+ });
74
+
75
+ it('should include expected default Chrome args', async () => {
76
+ const { CHROME_ARGS } = await import('../../../src/core/constants.js');
77
+ assert.ok(CHROME_ARGS.includes('--disable-session-crashed-bubble'));
78
+ assert.ok(CHROME_ARGS.includes('--no-first-run'));
79
+ assert.ok(CHROME_ARGS.includes('--no-default-browser-check'));
80
+ });
81
+
82
+ it('launchBrowser function should accept args option', async () => {
83
+ // We can verify the function signature by checking that it
84
+ // destructures args from options without throwing
85
+ const { launchBrowser } =
86
+ await import('../../../src/browser/launcher.js');
87
+ assert.ok(typeof launchBrowser === 'function');
88
+
89
+ // The function should accept options object with args array
90
+ // We can't fully test the launch without actual browsers,
91
+ // but we can verify the function exists and is callable
92
+ });
93
+
94
+ it('launchBrowser should throw for invalid engine', async () => {
95
+ const { launchBrowser } =
96
+ await import('../../../src/browser/launcher.js');
97
+
98
+ await assert.rejects(
99
+ () => launchBrowser({ engine: 'invalid-engine' }),
100
+ (error) => {
101
+ assert.ok(error.message.includes('Invalid engine'));
102
+ assert.ok(error.message.includes('invalid-engine'));
103
+ return true;
104
+ }
105
+ );
106
+ });
107
+
108
+ it('launchBrowser should accept args in options', async () => {
109
+ const { launchBrowser } =
110
+ await import('../../../src/browser/launcher.js');
111
+
112
+ // Verify the function signature accepts args
113
+ // This test validates that the args parameter is correctly destructured
114
+ // by attempting to call with an invalid engine (which fails before browser launch)
115
+ // but proves args is accepted without error during options parsing
116
+ const customArgs = ['--no-sandbox', '--disable-setuid-sandbox'];
117
+
118
+ await assert.rejects(
119
+ () => launchBrowser({ engine: 'invalid', args: customArgs }),
120
+ /Invalid engine/
121
+ );
122
+
123
+ // If we got here, the args option was accepted without error
124
+ });
125
+ });
126
+ });