browser-commander 0.5.4 → 0.6.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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7d83530: Document extensibility escape hatch: `commander.page` and `launchBrowser()` return values expose the raw underlying Playwright/Puppeteer page object as an official mechanism for accessing engine-specific APIs not yet supported by browser-commander (e.g. `page.pdf()`, `page.emulateMedia()`, `page.keyboard`, `page.on('dialog', ...)`). Adds tests verifying `commander.page` is the exact raw page object.
8
+
3
9
  ## 0.5.4
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -318,6 +318,67 @@ action: async (ctx) => {
318
318
  };
319
319
  ```
320
320
 
321
+ ## Extensibility / Escape Hatch
322
+
323
+ `browser-commander` cannot anticipate every browser API. When you need an API that is not yet supported, you can access the raw underlying engine objects directly as an **official extensibility escape hatch**.
324
+
325
+ ### Using `commander.page` for engine-specific APIs
326
+
327
+ `makeBrowserCommander` exposes `commander.page` — this is the **raw Playwright or Puppeteer page object**, not a wrapper. Use it directly for APIs browser-commander doesn't yet support:
328
+
329
+ ```javascript
330
+ const { browser, page } = await launchBrowser({ engine: 'playwright' });
331
+ const commander = makeBrowserCommander({ page });
332
+
333
+ // Access engine-specific API via commander.page
334
+ // Example: PDF generation (issue #35)
335
+ const pdfBuffer = await commander.page.pdf({
336
+ format: 'A4',
337
+ printBackground: true,
338
+ margin: { top: '1cm', right: '1cm', bottom: '1cm', left: '1cm' },
339
+ });
340
+
341
+ // Example: Color scheme emulation (issue #36)
342
+ await commander.page.emulateMedia({ colorScheme: 'dark' });
343
+
344
+ // Example: Keyboard interactions (issue #37)
345
+ await commander.page.keyboard.press('Escape');
346
+
347
+ // Example: Dialog handling (issue #38)
348
+ commander.page.on('dialog', async (dialog) => {
349
+ await dialog.dismiss();
350
+ });
351
+ ```
352
+
353
+ ### Using `launchBrowser` raw return values
354
+
355
+ `launchBrowser()` returns the raw `{ browser, page }` objects from the underlying engine. You can use these directly:
356
+
357
+ ```javascript
358
+ const { browser, page } = await launchBrowser({ engine: 'playwright' });
359
+
360
+ // Use raw page directly for engine-specific APIs
361
+ await page.pdf({ format: 'A4' });
362
+
363
+ // Or create a commander for the unified API
364
+ const commander = makeBrowserCommander({ page });
365
+ ```
366
+
367
+ ### No more `_page` hacks
368
+
369
+ If you previously used `page._page || page` to access the raw page, replace it with `commander.page`:
370
+
371
+ ```javascript
372
+ // BEFORE (fragile hack):
373
+ const rawPage = page._page || page;
374
+ await rawPage.pdf({ format: 'A4' });
375
+
376
+ // AFTER (official API):
377
+ await commander.page.pdf({ format: 'A4' });
378
+ ```
379
+
380
+ This is the **official extensibility mechanism** while awaiting browser-commander to add first-class support for these APIs. Please [report missing APIs](https://github.com/link-foundation/browser-commander/issues) so they can be added.
381
+
321
382
  ## Debugging
322
383
 
323
384
  Enable verbose mode for detailed logs:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-commander",
3
- "version": "0.5.4",
3
+ "version": "0.6.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",
@@ -170,5 +170,62 @@ describe('factory', () => {
170
170
  // Should not throw
171
171
  await commander.destroy();
172
172
  });
173
+
174
+ // Extensibility escape hatch tests (issue #39)
175
+ it('should expose the raw page object as commander.page (extensibility escape hatch)', () => {
176
+ const page = createMockPlaywrightPage();
177
+ page.locator = (sel) => ({
178
+ count: async () => 1,
179
+ waitFor: async () => {},
180
+ });
181
+ page.context = () => ({});
182
+
183
+ const commander = makeBrowserCommander({ page });
184
+
185
+ // commander.page must be the exact same object as the raw page passed in
186
+ // This is the official extensibility escape hatch for APIs not yet in browser-commander
187
+ assert.strictEqual(
188
+ commander.page,
189
+ page,
190
+ 'commander.page must be the raw engine page (not a wrapper)'
191
+ );
192
+ });
193
+
194
+ it('should allow using commander.page to call engine-specific APIs not in browser-commander', () => {
195
+ const page = createMockPlaywrightPage();
196
+ page.locator = (sel) => ({
197
+ count: async () => 1,
198
+ waitFor: async () => {},
199
+ });
200
+ page.context = () => ({});
201
+
202
+ // Add a custom method to simulate engine-specific API (e.g. page.pdf(), page.emulateMedia())
203
+ page.customEngineMethod = () => 'engine-specific-result';
204
+
205
+ const commander = makeBrowserCommander({ page });
206
+
207
+ // Users can call engine-specific APIs via commander.page without needing _page hacks
208
+ const result = commander.page.customEngineMethod();
209
+ assert.strictEqual(
210
+ result,
211
+ 'engine-specific-result',
212
+ 'commander.page should allow calling engine-specific APIs'
213
+ );
214
+ });
215
+
216
+ it('should expose raw page with Puppeteer page too (extensibility escape hatch)', () => {
217
+ const page = createMockPuppeteerPage();
218
+ delete page.locator;
219
+ delete page.context;
220
+ page.$eval = async () => {};
221
+
222
+ const commander = makeBrowserCommander({ page });
223
+
224
+ assert.strictEqual(
225
+ commander.page,
226
+ page,
227
+ 'commander.page must be the raw Puppeteer page (not a wrapper)'
228
+ );
229
+ });
173
230
  });
174
231
  });