Skip to content
Open
4 changes: 3 additions & 1 deletion packages/runner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ await run({
## Features

- Supports all Chromium and Firefox based browsers
- Zero dependencies
- Minimal dependencies
- One-line config for persisting data between launches
- Launch multiple extensions at once

## Requirements

Expand All @@ -56,6 +57,7 @@ You also need to have a specific version of the browser installed that supports
- [x] Provide install functions to allow hooking into already running instances of Chrome/Firefox
- [ ] Try to setup E2E tests on Firefox with Puppeteer using this approach
- [ ] Try to setup E2E tests on Chrome with Puppeteer using this approach
- [ ] Add a "reload extension" API

## Options

Expand Down
1 change: 1 addition & 0 deletions packages/runner/demo-extension-1/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello background 1!');
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Test",
"name": "Test 1",
"version": "1.0.0",
"manifest_version": 3,
"background": {
Expand Down
1 change: 1 addition & 0 deletions packages/runner/demo-extension-2/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello background 2!');
9 changes: 9 additions & 0 deletions packages/runner/demo-extension-2/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "Test 2",
"version": "1.0.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js",
"scripts": ["background.js"]
}
}
1 change: 0 additions & 1 deletion packages/runner/demo-extension/background.js

This file was deleted.

6 changes: 4 additions & 2 deletions packages/runner/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import { run } from './src';

// Uncomment to enable debug logs
process.env.DEBUG = '@wxt-dev/runner';
process.env.DEBUG = 'wxt:runner:*';

await run({
extensionDir: 'demo-extension',
extensionDir: 'demo-extension-1',
chromiumAdditionalExtensionDirs: ['demo-extension-2'],
firefoxAdditionalExtensionDirs: ['demo-extension-2'],
target: process.argv[2],
});
2 changes: 1 addition & 1 deletion packages/runner/src/debug.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { createDebug } from 'obug';

export const runnerDebug = createDebug('wxt:runner', { color: 31 });
export const runnerDebug = createDebug('wxt:runner');
1 change: 0 additions & 1 deletion packages/runner/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './run';
export * from './options';
export * from './install';
15 changes: 4 additions & 11 deletions packages/runner/src/install.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { ChildProcess } from 'node:child_process';
import { createBidiConnection } from './bidi';
import { createCdpConnection } from './cdp';
import type { BidiConnection } from './bidi';
import type { CDPConnection } from './cdp';

/**
* Install an extension to an already running instance of Firefox.
Expand All @@ -11,14 +10,9 @@ import { createCdpConnection } from './cdp';
* to be installed.
*/
export async function installFirefox(
debuggerUrl: string,
bidi: BidiConnection,
extensionDir: string,
): Promise<BidiWebExtensionInstallResponse> {
using bidi = await createBidiConnection(debuggerUrl);

// Start a session
await bidi.send<unknown>('session.new', { capabilities: {} });

// Install the extension
return await bidi.send<BidiWebExtensionInstallResponse>(
'webExtension.install',
Expand Down Expand Up @@ -46,10 +40,9 @@ export type BidiWebExtensionInstallResponse = {
* Otherwise it the CDP doesn't have permission to install extensions.
*/
export async function installChromium(
browserProcess: ChildProcess,
cdp: CDPConnection,
extensionDir: string,
): Promise<CdpExtensionsLoadUnpackedResponse> {
using cdp = createCdpConnection(browserProcess);
return await cdp.send<CdpExtensionsLoadUnpackedResponse>(
'Extensions.loadUnpacked',
{
Expand Down
38 changes: 30 additions & 8 deletions packages/runner/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ export type RunOptions = {
* arguments with required ones to install extensions are ignored.
*/
chromiumArgs?: string[];
/**
* Customize the port Chrome's debugger is listening on. Defaults to a random
* open port.
*/
chromiumRemoteDebuggingPort?: number;
/**
* Additional directories to install extensions from on Chrome. Useful for
* installing devtool extensions or other extensions yours depends on.
*/
chromiumAdditionalExtensionDirs?: string[];
/**
* Control how data is persisted between launches. Either save data at a user
* level, project level, or don't persist data at all. Defaults to `project`.
Expand All @@ -33,15 +43,13 @@ export type RunOptions = {
* 'project'`. Can be absolute or relative to the current working directory.
*/
projectDataDir?: string;
/**
* Customize the port Chrome's debugger is listening on. Defaults to a random
* open port.
*/
chromiumRemoteDebuggingPort?: number;
/**
* Directory where the extension will be installed from. Should contain a
* `manifest.json` file. Can be relative to the current working directory.
* Defaults to the current working directory.
* `manifest.json` file.
*
* Can be relative to the current working directory.
*
* @default process.cwd()
*/
extensionDir?: string;
/**
Expand All @@ -54,6 +62,11 @@ export type RunOptions = {
* open port.
*/
firefoxRemoteDebuggingPort?: number;
/**
* Additional directories to install extensions from on Firefox. Useful for
* installing devtool extensions or other extensions yours depends on.
*/
firefoxAdditionalExtensionDirs?: string[];
/**
* Specify the browser to open. Defaults to `"chrome"`, but you can pass any
* string.
Expand All @@ -66,13 +79,15 @@ export type ResolvedRunOptions = {
browserBinary: string;
chromiumArgs: string[];
chromiumRemoteDebuggingPort: number;
chromiumAdditionalExtensionDirs: string[];
/** Absolute path to the directory where browser data will be stored. */
dataDir: string;
dataPersistence: 'user' | 'project' | 'none';
/** Absolute path to the extension directory. */
extensionDir: string;
firefoxArgs: string[];
firefoxRemoteDebuggingPort: number;
firefoxAdditionalExtensionDirs: string[];
target: string;
};

Expand Down Expand Up @@ -117,13 +132,20 @@ export async function resolveRunOptions(
dataDir,
dataPersistence,
chromiumRemoteDebuggingPort,
extensionDir: resolve(options?.extensionDir ?? '.'),
chromiumAdditionalExtensionDirs:
options?.chromiumAdditionalExtensionDirs?.map((dir) => resolve(dir)) ??
[],
extensionDir: options?.extensionDir
? resolve(options.extensionDir)
: process.cwd(),
firefoxArgs: resolveFirefoxArgs(
options?.firefoxArgs,
firefoxRemoteDebuggingPort,
dataDir,
),
firefoxRemoteDebuggingPort,
firefoxAdditionalExtensionDirs:
options?.firefoxAdditionalExtensionDirs?.map((dir) => resolve(dir)) ?? [],
target,
};
debug('Resolved options:', resolved);
Expand Down
Loading
Loading