playwright-browser-harness 0.2.0 → 0.3.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/README.md +48 -29
- package/dist/build.mjs +138 -68
- package/dist/driver.d.ts +28 -11
- package/dist/driver.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,11 +22,11 @@ their versions. `@sqlite.org/sqlite-wasm` is *not* a dependency; it is only a
|
|
|
22
22
|
fixture/consumer dep when you test wasm-SQLite.
|
|
23
23
|
|
|
24
24
|
`buffer` is an **optional peerDependency** — only needed (and only installed) when
|
|
25
|
-
you
|
|
26
|
-
[
|
|
25
|
+
you ask for the `'buffer'` Node polyfill (see
|
|
26
|
+
[Explicit Node polyfills](#explicit-node-polyfills)):
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
pnpm add -D buffer # only if you use nodePolyfills
|
|
29
|
+
pnpm add -D buffer # only if you use nodePolyfills: ['buffer', ...]
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
## tsconfig (required)
|
|
@@ -101,39 +101,58 @@ esbuild) **or** `prebuilt` (prebuilt dir); `coi` (default `true`), `worker`,
|
|
|
101
101
|
`wasmDirs`, `assets`, plus the bundling escape-hatches `nodePolyfills` and
|
|
102
102
|
`esbuild` (see below).
|
|
103
103
|
|
|
104
|
-
##
|
|
104
|
+
## Explicit Node polyfills
|
|
105
105
|
|
|
106
106
|
Many web3 / crypto libraries (ethereumjs, tevm, and anything pulling in
|
|
107
107
|
`readable-stream` / `safe-buffer`) transitively `import 'buffer'` and touch
|
|
108
|
-
`process` / `global`. esbuild's `platform:'browser'` will
|
|
109
|
-
so the bundle fails with `Could not resolve "buffer"`.
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
`process` / `global` / `events` / `stream`. esbuild's `platform:'browser'` will
|
|
109
|
+
**not** resolve those, so the bundle fails with `Could not resolve "buffer"`.
|
|
110
|
+
|
|
111
|
+
There is **no** catch-all preset. A named "web3" preset is a leaky abstraction:
|
|
112
|
+
it would shim `buffer`/`process`/`global` but not `events`/`stream`/`util`, so
|
|
113
|
+
you'd fall back to the `esbuild` escape-hatch anyway. Instead you **declare
|
|
114
|
+
exactly what you need**.
|
|
115
|
+
|
|
116
|
+
### `nodePolyfills?: ('buffer' | 'process' | 'global')[]` (default `[]`)
|
|
117
|
+
|
|
118
|
+
The three Node builtins the harness can shim **itself**, with zero opinions.
|
|
119
|
+
Each entry is a **self-contained** fragment — `['buffer']` shims ONLY buffer; it
|
|
120
|
+
does **not** touch `process` or `global`. `[]` or omitted = nothing.
|
|
121
|
+
|
|
122
|
+
| entry | what it does |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `'buffer'` | alias `buffer` / `node:buffer` → the [`buffer`](https://www.npmjs.com/package/buffer) npm package, and inject a `Buffer` global (also assigned onto `globalThis`). Requires the optional `buffer` peer dep (`pnpm add -D buffer`). |
|
|
125
|
+
| `'process'` | inject a minimal `process` stub: `{env:{}, browser:true, version:'', nextTick}`. |
|
|
126
|
+
| `'global'` | set `define: { global: 'globalThis' }`. |
|
|
127
|
+
|
|
128
|
+
**Anything beyond these three** (`events`, `stream`, `util`, `crypto`, …) is the
|
|
129
|
+
consumer's job via the [`esbuild`](#esbuild-escape-hatch--esbuild--plugins-inject-define-alias-loader-external-tsconfig-)
|
|
130
|
+
pass-through below.
|
|
131
|
+
|
|
132
|
+
#### Copy-paste recipe: ethereumjs / tevm
|
|
133
|
+
|
|
134
|
+
A typical web3 EVM tree needs all three builtins **plus** `events`/`stream`
|
|
135
|
+
aliased through the escape hatch:
|
|
112
136
|
|
|
113
137
|
```ts
|
|
114
138
|
const h = await mountHarness(page, {
|
|
115
139
|
cut,
|
|
116
|
-
coi: false,
|
|
117
|
-
nodePolyfills: '
|
|
118
|
-
esbuild: {
|
|
119
|
-
|
|
140
|
+
coi: false, // pure-compute EVM → no SharedArrayBuffer needed
|
|
141
|
+
nodePolyfills: ['buffer', 'process', 'global'], // the harness's three builtins
|
|
142
|
+
esbuild: {
|
|
143
|
+
// everything the harness intentionally does NOT preset:
|
|
144
|
+
alias: {events: 'events', stream: 'stream-browserify'},
|
|
120
145
|
},
|
|
121
146
|
});
|
|
122
147
|
```
|
|
123
148
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
- aliases `buffer` / `node:buffer` → the [`buffer`](https://www.npmjs.com/package/buffer) npm package,
|
|
129
|
-
- injects a `Buffer` global (also assigned onto `globalThis`),
|
|
130
|
-
- provides a minimal `process` stub: `{env:{}, browser:true, version:'', nextTick}`,
|
|
131
|
-
- sets `define: { global: 'globalThis' }`.
|
|
149
|
+
```bash
|
|
150
|
+
pnpm add -D buffer events stream-browserify
|
|
151
|
+
```
|
|
132
152
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
storage code does not.
|
|
153
|
+
> **Migrating from 0.2.0** — `nodePolyfills` shipped in 0.2.0 as `true | 'web3'`.
|
|
154
|
+
> That form was **removed** (clean break; 0.2.0 had ≈no users). Replace
|
|
155
|
+
> `true` / `'web3'` with `['buffer', 'process', 'global']`.
|
|
137
156
|
|
|
138
157
|
### esbuild escape hatch — `esbuild?: { plugins?, inject?, define?, alias?, loader?, external?, tsconfig? }`
|
|
139
158
|
|
|
@@ -148,17 +167,17 @@ winning; arrays concatenated **after** the built-ins). The harness's own
|
|
|
148
167
|
| key | merge behaviour |
|
|
149
168
|
|---|---|
|
|
150
169
|
| `plugins` | concatenated **after** the built-in `__CUT_MODULE__` resolver |
|
|
151
|
-
| `inject` | concatenated after the `nodePolyfills` injects (if any) |
|
|
170
|
+
| `inject` | concatenated after the `nodePolyfills` injects (the chosen builtins, if any) |
|
|
152
171
|
| `define` / `alias` | shallow-merged, **consumer key wins** |
|
|
153
172
|
| `loader` | merged **over** `{'.wasm':'copy'}` (e.g. add `{'.svg':'dataurl'}`) |
|
|
154
173
|
| `external` | as given |
|
|
155
174
|
| `tsconfig` | path to a tsconfig esbuild should honour |
|
|
156
175
|
|
|
157
|
-
####
|
|
176
|
+
#### Doing it entirely by hand (no `nodePolyfills`)
|
|
158
177
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
shim via the escape hatch:
|
|
178
|
+
`nodePolyfills` is just sugar for these three fragments. If you'd rather not use
|
|
179
|
+
it at all (e.g. you want one custom shim module), alias `buffer` to the npm
|
|
180
|
+
package and inject a `Buffer`/`process` shim purely via the escape hatch:
|
|
162
181
|
|
|
163
182
|
```ts
|
|
164
183
|
const h = await mountHarness(page, {
|
package/dist/build.mjs
CHANGED
|
@@ -23,71 +23,128 @@ import { existsSync } from 'node:fs';
|
|
|
23
23
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* web3/crypto code whose dependency trees reach for Node builtins.
|
|
26
|
+
* Explicit, composable Node-builtin polyfill fragments.
|
|
28
27
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* `
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* - injects a `Buffer` global (so `Buffer.from(...)` works without an import),
|
|
35
|
-
* - shims a minimal `process` (`{env,browser,version,nextTick}`),
|
|
36
|
-
* - defines `global` → `globalThis`.
|
|
28
|
+
* There is intentionally NO catch-all "web3" preset: a named preset is a leaky
|
|
29
|
+
* abstraction — it would shim `buffer`/`process`/`global` but not
|
|
30
|
+
* `events`/`stream`/`util`/`crypto`, so consumers fall back to the `esbuild`
|
|
31
|
+
* escape-hatch anyway. Instead the harness exposes exactly the three builtins it
|
|
32
|
+
* can shim with zero opinions, and each maps to a self-contained fragment:
|
|
37
33
|
*
|
|
38
|
-
* `buffer`
|
|
39
|
-
*
|
|
34
|
+
* - 'buffer' → alias `buffer`/`node:buffer` to the `buffer` npm package +
|
|
35
|
+
* inject a `Buffer` shim that also assigns `globalThis.Buffer`.
|
|
36
|
+
* - 'process' → inject a minimal `process` stub `{env,browser,version,nextTick}`.
|
|
37
|
+
* - 'global' → define `{ global: 'globalThis' }`.
|
|
40
38
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* Anything else (`events`, `stream`, `util`, `crypto`, …) is the consumer's job
|
|
40
|
+
* via the `esbuild: { alias, inject, define, plugins }` pass-through.
|
|
41
|
+
*
|
|
42
|
+
* Each helper returns an esbuild *fragment* (`{alias?, inject?, define?}`) so a
|
|
43
|
+
* consumer can compose them with their own esbuild opts. `buffer` is an
|
|
44
|
+
* optional/peer dependency: the consumer installs it when they opt into the
|
|
45
|
+
* `'buffer'` polyfill.
|
|
46
|
+
*
|
|
47
|
+
* @typedef {'buffer'|'process'|'global'} NodePolyfill
|
|
43
48
|
*/
|
|
44
|
-
async function nodePolyfillsPreset(outdir) {
|
|
45
|
-
// Resolve the `buffer` npm package from the consumer's install. We resolve
|
|
46
|
-
// the *bare specifier* so esbuild aliases `buffer`/`node:buffer` to it.
|
|
47
|
-
// (We don't hard-require it here — esbuild will surface a clear error if the
|
|
48
|
-
// consumer enabled nodePolyfills without installing `buffer`.)
|
|
49
|
-
const bufferPkg = 'buffer';
|
|
50
|
-
|
|
51
|
-
// A tiny `process` shim written next to the bundle and injected as a global.
|
|
52
|
-
// Kept minimal on purpose: env bag, browser flag, empty version, and a
|
|
53
|
-
// microtask-based nextTick — enough for readable-stream/safe-buffer & friends.
|
|
54
|
-
const procShim = join(outdir, '__process-shim.js');
|
|
55
|
-
await writeFile(
|
|
56
|
-
procShim,
|
|
57
|
-
[
|
|
58
|
-
'const process = {',
|
|
59
|
-
' env: {},',
|
|
60
|
-
' browser: true,',
|
|
61
|
-
" version: '',",
|
|
62
|
-
' nextTick: (cb, ...args) => Promise.resolve().then(() => cb(...args)),',
|
|
63
|
-
'};',
|
|
64
|
-
'export { process };',
|
|
65
|
-
'export default process;',
|
|
66
|
-
].join('\n'),
|
|
67
|
-
);
|
|
68
49
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Build a single Node-polyfill fragment by name. Self-contained: passing
|
|
52
|
+
* `'buffer'` shims ONLY buffer, etc. Unknown names throw with a clear message.
|
|
53
|
+
*
|
|
54
|
+
* @param {NodePolyfill} name which builtin to shim
|
|
55
|
+
* @param {string} outdir directory to write any generated shim modules into
|
|
56
|
+
* @returns {Promise<{alias?: Record<string,string>, inject?: string[], define?: Record<string,string>}>}
|
|
57
|
+
*/
|
|
58
|
+
export async function nodePolyfill(name, outdir) {
|
|
59
|
+
if (name === 'buffer') {
|
|
60
|
+
// Resolve the `buffer` npm package from the consumer's install via its bare
|
|
61
|
+
// specifier so esbuild aliases `buffer`/`node:buffer` to it. (We don't
|
|
62
|
+
// hard-require it here — esbuild surfaces a clear error if the consumer
|
|
63
|
+
// asked for the 'buffer' polyfill without installing `buffer`.)
|
|
64
|
+
const bufferPkg = 'buffer';
|
|
65
|
+
// A tiny module that re-exports `Buffer` from the `buffer` package so esbuild
|
|
66
|
+
// can `inject` it as the `Buffer` global. We ALSO assign it onto `globalThis`
|
|
67
|
+
// so libraries that reach for `globalThis.Buffer` / `window.Buffer` at
|
|
68
|
+
// runtime (not just an unqualified `Buffer` identifier) find it too. GOTCHA:
|
|
69
|
+
// esbuild's `inject` only provides a top-level *binding* in modules that
|
|
70
|
+
// reference the name — it does not set a real global — so this explicit
|
|
71
|
+
// assignment is what makes `globalThis.Buffer` truthy in-page.
|
|
72
|
+
const bufShim = join(outdir, '__buffer-shim.js');
|
|
73
|
+
await writeFile(
|
|
74
|
+
bufShim,
|
|
75
|
+
[
|
|
76
|
+
"import { Buffer } from 'buffer';",
|
|
77
|
+
'if (typeof globalThis !== "undefined" && !globalThis.Buffer) globalThis.Buffer = Buffer;',
|
|
78
|
+
'export { Buffer };',
|
|
79
|
+
].join('\n'),
|
|
80
|
+
);
|
|
81
|
+
return {
|
|
82
|
+
alias: { buffer: bufferPkg, 'node:buffer': bufferPkg },
|
|
83
|
+
inject: [bufShim],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (name === 'process') {
|
|
88
|
+
// A tiny `process` shim written next to the bundle and injected as a global.
|
|
89
|
+
// Kept minimal on purpose: env bag, browser flag, empty version, and a
|
|
90
|
+
// microtask-based nextTick — enough for readable-stream/safe-buffer & co.
|
|
91
|
+
const procShim = join(outdir, '__process-shim.js');
|
|
92
|
+
await writeFile(
|
|
93
|
+
procShim,
|
|
94
|
+
[
|
|
95
|
+
'const process = {',
|
|
96
|
+
' env: {},',
|
|
97
|
+
' browser: true,',
|
|
98
|
+
" version: '',",
|
|
99
|
+
' nextTick: (cb, ...args) => Promise.resolve().then(() => cb(...args)),',
|
|
100
|
+
'};',
|
|
101
|
+
'export { process };',
|
|
102
|
+
'export default process;',
|
|
103
|
+
].join('\n'),
|
|
104
|
+
);
|
|
105
|
+
return { inject: [procShim] };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (name === 'global') {
|
|
109
|
+
return { define: { global: 'globalThis' } };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
throw new Error(
|
|
113
|
+
`nodePolyfill: unknown polyfill ${JSON.stringify(name)} — valid values are 'buffer', 'process', 'global'.`,
|
|
84
114
|
);
|
|
115
|
+
}
|
|
85
116
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
117
|
+
/**
|
|
118
|
+
* The set of builtins the harness can shim itself, as a reusable/testable map of
|
|
119
|
+
* `name → (outdir) => fragment`. Exposed so a consumer can compose individual
|
|
120
|
+
* fragments with their own esbuild opts without going through `buildBundle`.
|
|
121
|
+
*
|
|
122
|
+
* @type {Record<NodePolyfill, (outdir: string) => Promise<{alias?: Record<string,string>, inject?: string[], define?: Record<string,string>}>>}
|
|
123
|
+
*/
|
|
124
|
+
export const nodePolyfills = {
|
|
125
|
+
buffer: (outdir) => nodePolyfill('buffer', outdir),
|
|
126
|
+
process: (outdir) => nodePolyfill('process', outdir),
|
|
127
|
+
global: (outdir) => nodePolyfill('global', outdir),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Compose the requested Node-polyfill fragments into a single
|
|
132
|
+
* `{alias, inject, define}` bundle. Order-stable; later entries' alias/define
|
|
133
|
+
* keys win on clash (none do today since the three fragments are disjoint).
|
|
134
|
+
*
|
|
135
|
+
* @param {NodePolyfill[]} names
|
|
136
|
+
* @param {string} outdir
|
|
137
|
+
* @returns {Promise<{alias: Record<string,string>, inject: string[], define: Record<string,string>}>}
|
|
138
|
+
*/
|
|
139
|
+
async function composeNodePolyfills(names, outdir) {
|
|
140
|
+
const out = { alias: {}, inject: [], define: {} };
|
|
141
|
+
for (const name of names) {
|
|
142
|
+
const frag = await nodePolyfill(name, outdir);
|
|
143
|
+
if (frag.alias) Object.assign(out.alias, frag.alias);
|
|
144
|
+
if (frag.inject) out.inject.push(...frag.inject);
|
|
145
|
+
if (frag.define) Object.assign(out.define, frag.define);
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
91
148
|
}
|
|
92
149
|
|
|
93
150
|
/**
|
|
@@ -99,10 +156,13 @@ async function nodePolyfillsPreset(outdir) {
|
|
|
99
156
|
* @param {string[]} [opts.assets] explicit absolute file paths to copy verbatim
|
|
100
157
|
* into outdir (e.g. sqlite3-opfs-async-proxy.js, which the OPFS VFS spawns by
|
|
101
158
|
* URL relative to the worker bundle and esbuild does NOT trace).
|
|
102
|
-
* @param {
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
159
|
+
* @param {Array<'buffer'|'process'|'global'>} [opts.nodePolyfills] explicit,
|
|
160
|
+
* composable list of Node builtins the harness shims itself. `['buffer']`
|
|
161
|
+
* shims ONLY buffer; `[]` or omitted = nothing. Each entry is self-contained:
|
|
162
|
+
* 'buffer' aliases `buffer`/`node:buffer` + injects a `Buffer` global,
|
|
163
|
+
* 'process' injects a minimal `process` stub, 'global' defines
|
|
164
|
+
* `{global:'globalThis'}`. There is NO catch-all preset; everything beyond
|
|
165
|
+
* these three (events, stream, util, crypto, …) goes through `opts.esbuild`.
|
|
106
166
|
* @param {object} [opts.esbuild] esbuild pass-through merged into the internal
|
|
107
167
|
* build. Consumer values take precedence; arrays are concatenated AFTER the
|
|
108
168
|
* built-ins so the `__CUT_MODULE__` resolver, the page-entry entry point, and
|
|
@@ -121,9 +181,16 @@ export async function buildBundle({
|
|
|
121
181
|
worker,
|
|
122
182
|
wasmDirs = [],
|
|
123
183
|
assets = [],
|
|
124
|
-
nodePolyfills =
|
|
184
|
+
nodePolyfills = [],
|
|
125
185
|
esbuild: esbuildOpts = {},
|
|
126
186
|
}) {
|
|
187
|
+
if (!Array.isArray(nodePolyfills)) {
|
|
188
|
+
throw new TypeError(
|
|
189
|
+
`buildBundle: \`nodePolyfills\` must be an array of 'buffer' | 'process' | 'global' ` +
|
|
190
|
+
`(got ${JSON.stringify(nodePolyfills)}). The 0.2.0 \`true\`/'web3' form was removed; ` +
|
|
191
|
+
`migrate to e.g. ['buffer','process','global'].`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
127
194
|
await rm(outdir, { recursive: true, force: true });
|
|
128
195
|
await mkdir(outdir, { recursive: true });
|
|
129
196
|
|
|
@@ -139,10 +206,13 @@ export async function buildBundle({
|
|
|
139
206
|
},
|
|
140
207
|
};
|
|
141
208
|
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
// (so the consumer can still override any specific key).
|
|
145
|
-
const preset =
|
|
209
|
+
// Compose the explicitly-requested Node-builtin polyfill fragments (default
|
|
210
|
+
// none). Produces alias/inject/define merged UNDER the consumer's explicit
|
|
211
|
+
// esbuild opts (so the consumer can still override any specific key).
|
|
212
|
+
const preset =
|
|
213
|
+
nodePolyfills.length > 0
|
|
214
|
+
? await composeNodePolyfills(nodePolyfills, outdir)
|
|
215
|
+
: null;
|
|
146
216
|
|
|
147
217
|
const {
|
|
148
218
|
plugins: userPlugins = [],
|
|
@@ -162,7 +232,7 @@ export async function buildBundle({
|
|
|
162
232
|
target: 'es2022',
|
|
163
233
|
platform: 'browser',
|
|
164
234
|
sourcemap: true,
|
|
165
|
-
// Merge order: built-ins →
|
|
235
|
+
// Merge order: built-ins → polyfills → consumer. Consumer wins on key clashes
|
|
166
236
|
// (define/alias/loader) and runs last (plugins). Arrays are concatenated.
|
|
167
237
|
plugins: [cutResolver, ...userPlugins],
|
|
168
238
|
inject: [...(preset?.inject ?? []), ...userInject],
|
package/dist/driver.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export interface MountOptions {
|
|
|
55
55
|
entry?: string;
|
|
56
56
|
/**
|
|
57
57
|
* Skip esbuild entirely and treat `cut`/`entry` as a prebuilt `.js` module
|
|
58
|
-
* (see `entry`). Default `false` (the esbuild path). `worker
|
|
58
|
+
* (see `entry`). Default `false` (the esbuild path). `worker` / `nodePolyfills` /
|
|
59
59
|
* `esbuild` options are ignored in this mode.
|
|
60
60
|
*/
|
|
61
61
|
noBundle?: boolean;
|
|
@@ -69,23 +69,40 @@ export interface MountOptions {
|
|
|
69
69
|
* async proxy js). */
|
|
70
70
|
assets?: string[];
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
72
|
+
* Explicit, composable Node-builtin polyfills. Declare exactly what your
|
|
73
|
+
* code-under-test needs — there is **no** catch-all preset. Default `[]`
|
|
74
|
+
* (nothing); omitted is the same as `[]`.
|
|
75
75
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
76
|
+
* The three builtins the harness can shim itself (with zero opinions):
|
|
77
|
+
* - `'buffer'` — alias `buffer` / `node:buffer` to the [`buffer`] npm
|
|
78
|
+
* package and inject a `Buffer` global (also assigned onto `globalThis`).
|
|
79
|
+
* Requires the optional `buffer` peer dependency to be installed.
|
|
80
|
+
* - `'process'` — inject a minimal `process` stub
|
|
81
|
+
* (`{ env: {}, browser: true, version: '', nextTick }`).
|
|
82
|
+
* - `'global'` — set `define: { global: 'globalThis' }`.
|
|
83
|
+
*
|
|
84
|
+
* Each entry is self-contained: `['buffer']` shims ONLY buffer and does NOT
|
|
85
|
+
* touch `process` or `global`. Anything beyond these three (`events`,
|
|
86
|
+
* `stream`, `util`, `crypto`, …) is your job via `esbuild.{alias,inject,
|
|
87
|
+
* define,plugins}` below.
|
|
88
|
+
*
|
|
89
|
+
* web3 / crypto trees (ethereumjs, tevm, anything pulling `readable-stream` /
|
|
90
|
+
* `safe-buffer`) typically want `['buffer','process','global']` plus an
|
|
91
|
+
* `esbuild.alias` for `events`/`stream`. See README "Explicit Node polyfills".
|
|
92
|
+
*
|
|
93
|
+
* **Migration from 0.2.0:** the old `true` / `'web3'` form was removed (clean
|
|
94
|
+
* break — 0.2.0 had ~no users). Replace `true`/`'web3'` with
|
|
95
|
+
* `['buffer','process','global']`.
|
|
96
|
+
*
|
|
97
|
+
* [`buffer`]: https://www.npmjs.com/package/buffer
|
|
81
98
|
*/
|
|
82
|
-
nodePolyfills?:
|
|
99
|
+
nodePolyfills?: Array<'buffer' | 'process' | 'global'>;
|
|
83
100
|
/**
|
|
84
101
|
* esbuild pass-through merged into the harness's internal browser build.
|
|
85
102
|
* Consumer values take precedence; arrays are concatenated AFTER the
|
|
86
103
|
* built-ins, so the `__CUT_MODULE__` resolver and the `.wasm` copy loader
|
|
87
104
|
* always remain. Combine with `nodePolyfills` for web3 code that still needs
|
|
88
|
-
*
|
|
105
|
+
* extra builtins (e.g. `alias: { events: 'events', stream: 'stream-browserify' }`).
|
|
89
106
|
*/
|
|
90
107
|
esbuild?: {
|
|
91
108
|
plugins?: import('esbuild').Plugin[];
|
package/dist/driver.js
CHANGED
|
@@ -47,7 +47,7 @@ export async function mountHarness(page, opts) {
|
|
|
47
47
|
worker: opts.worker,
|
|
48
48
|
wasmDirs: opts.wasmDirs ?? [],
|
|
49
49
|
assets: opts.assets ?? [],
|
|
50
|
-
nodePolyfills: opts.nodePolyfills ??
|
|
50
|
+
nodePolyfills: opts.nodePolyfills ?? [],
|
|
51
51
|
esbuild: opts.esbuild ?? {},
|
|
52
52
|
});
|
|
53
53
|
const srv = await startServer({ root: outdir, coi: opts.coi ?? true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright-browser-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Playwright harness that bundles your code, serves it under a COOP/COEP-toggleable server, drives it in a real browser, and returns structured results/timings — for testing real browser-storage persistence (IndexedDB/OPFS), cross-origin isolation, Workers, and perf that Node can't fake. Importable machinery + a tiny `init` CLI for the per-project files.",
|
|
6
6
|
"license": "MIT",
|