@browsermation/test 0.0.51 → 0.0.53

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/dist/bin/cli.js CHANGED
@@ -42258,7 +42258,7 @@ var {
42258
42258
  // package.json
42259
42259
  var package_default = {
42260
42260
  name: "@browsermation/test",
42261
- version: "0.0.51",
42261
+ version: "0.0.53",
42262
42262
  description: "The testing platform for Playwright by Browsermation.",
42263
42263
  main: "./dist/index.js",
42264
42264
  types: "./dist/index.d.ts",
@@ -42285,10 +42285,11 @@ var package_default = {
42285
42285
  ],
42286
42286
  scripts: {
42287
42287
  "build:cli": "esbuild src/bin/cli.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/bin/cli.js",
42288
+ "build:hook": "esbuild src/bin/hook.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/bin/hook.js",
42288
42289
  "build:reporter": "esbuild src/reporter/reporter.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/reporter.js",
42289
42290
  "build:index": "esbuild src/index.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/index.js",
42290
42291
  "build:types": "tsc --emitDeclarationOnly --outDir dist",
42291
- build: "rm -rf dist && npm run build:cli && npm run build:index && npm run build:reporter && npm run build:types",
42292
+ build: "rm -rf dist && npm run build:cli && npm run build:hook && npm run build:index && npm run build:reporter && npm run build:types",
42292
42293
  start: "node dist/bin/cli.js",
42293
42294
  "build:start": "npm run build && npm start",
42294
42295
  publishPackage: "npm run build && npm publish --access public"
@@ -42315,6 +42316,7 @@ var package_default = {
42315
42316
  chalk: "^5.4.1",
42316
42317
  commander: "^14.0.0",
42317
42318
  "form-data": "^4.0.3",
42319
+ "import-in-the-middle": "^1.14.2",
42318
42320
  ora: "^8.2.0",
42319
42321
  "tiny-invariant": "^1.3.3",
42320
42322
  "ts-morph": "^26.0.0",
@@ -46661,6 +46663,14 @@ function startTunnel(tunnelProcess, options) {
46661
46663
  );
46662
46664
  process.exit(1);
46663
46665
  }
46666
+ if (!options?.port) {
46667
+ console.error(
46668
+ source_default.red.bold(
46669
+ "\u274C Error: Please provide a port to expose via the tunnel using the --tunnel or --port option."
46670
+ )
46671
+ );
46672
+ process.exit(1);
46673
+ }
46664
46674
  const tunnelDomain = `${options.subdomain || crypto.randomUUID()}.browsermationtunnel.com`;
46665
46675
  tunnelProcess = (0, import_node_child_process.spawn)("ssh", [
46666
46676
  "-o",
@@ -46668,7 +46678,7 @@ function startTunnel(tunnelProcess, options) {
46668
46678
  "-o",
46669
46679
  "UserKnownHostsFile=/dev/null",
46670
46680
  "-R",
46671
- `:80:localhost:${options.tunnel}`,
46681
+ `:80:localhost:${options.port}`,
46672
46682
  "v0@browsermationtunnel.com",
46673
46683
  "-p",
46674
46684
  "2200",
@@ -46759,7 +46769,9 @@ program2.command("test").option("-t, --tunnel <port>").option("-p, --proxy").opt
46759
46769
  proxy: false
46760
46770
  };
46761
46771
  if (options.tunnel) {
46762
- const startTunnelResult = await startTunnel(tunnelProcess, options);
46772
+ const startTunnelResult = await startTunnel(tunnelProcess, {
46773
+ port: options.tunnel
46774
+ });
46763
46775
  tunnelProcess = startTunnelResult.tunnelProcess;
46764
46776
  }
46765
46777
  if (options.proxy) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,325 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
27
+ // node_modules/module-details-from-path/index.js
28
+ var require_module_details_from_path = __commonJS({
29
+ "node_modules/module-details-from-path/index.js"(exports2, module2) {
30
+ "use strict";
31
+ var sep = require("path").sep;
32
+ module2.exports = function(file) {
33
+ var segments = file.split(sep);
34
+ var index = segments.lastIndexOf("node_modules");
35
+ if (index === -1) return;
36
+ if (!segments[index + 1]) return;
37
+ var scoped = segments[index + 1][0] === "@";
38
+ var name = scoped ? segments[index + 1] + "/" + segments[index + 2] : segments[index + 1];
39
+ var offset = scoped ? 3 : 2;
40
+ var basedir = "";
41
+ var lastBaseDirSegmentIndex = index + offset - 1;
42
+ for (var i = 0; i <= lastBaseDirSegmentIndex; i++) {
43
+ if (i === lastBaseDirSegmentIndex) {
44
+ basedir += segments[i];
45
+ } else {
46
+ basedir += segments[i] + sep;
47
+ }
48
+ }
49
+ var path = "";
50
+ var lastSegmentIndex = segments.length - 1;
51
+ for (var i2 = index + offset; i2 <= lastSegmentIndex; i2++) {
52
+ if (i2 === lastSegmentIndex) {
53
+ path += segments[i2];
54
+ } else {
55
+ path += segments[i2] + sep;
56
+ }
57
+ }
58
+ return {
59
+ name,
60
+ basedir,
61
+ path
62
+ };
63
+ };
64
+ }
65
+ });
66
+
67
+ // node_modules/import-in-the-middle/lib/register.js
68
+ var require_register = __commonJS({
69
+ "node_modules/import-in-the-middle/lib/register.js"(exports2) {
70
+ var importHooks = [];
71
+ var setters = /* @__PURE__ */ new WeakMap();
72
+ var getters = /* @__PURE__ */ new WeakMap();
73
+ var specifiers = /* @__PURE__ */ new Map();
74
+ var toHook = [];
75
+ var proxyHandler = {
76
+ set(target, name, value) {
77
+ return setters.get(target)[name](value);
78
+ },
79
+ get(target, name) {
80
+ if (name === Symbol.toStringTag) {
81
+ return "Module";
82
+ }
83
+ const getter = getters.get(target)[name];
84
+ if (typeof getter === "function") {
85
+ return getter();
86
+ }
87
+ },
88
+ defineProperty(target, property, descriptor) {
89
+ if (!("value" in descriptor)) {
90
+ throw new Error("Getters/setters are not supported for exports property descriptors.");
91
+ }
92
+ return setters.get(target)[property](descriptor.value);
93
+ }
94
+ };
95
+ function register2(name, namespace, set, get, specifier) {
96
+ specifiers.set(name, specifier);
97
+ setters.set(namespace, set);
98
+ getters.set(namespace, get);
99
+ const proxy = new Proxy(namespace, proxyHandler);
100
+ importHooks.forEach((hook) => hook(name, proxy));
101
+ toHook.push([name, proxy]);
102
+ }
103
+ var experimentalPatchInternals = false;
104
+ function getExperimentalPatchInternals() {
105
+ return experimentalPatchInternals;
106
+ }
107
+ function setExperimentalPatchInternals(value) {
108
+ experimentalPatchInternals = value;
109
+ }
110
+ exports2.register = register2;
111
+ exports2.importHooks = importHooks;
112
+ exports2.specifiers = specifiers;
113
+ exports2.toHook = toHook;
114
+ exports2.getExperimentalPatchInternals = getExperimentalPatchInternals;
115
+ exports2.setExperimentalPatchInternals = setExperimentalPatchInternals;
116
+ }
117
+ });
118
+
119
+ // node_modules/import-in-the-middle/index.js
120
+ var require_import_in_the_middle = __commonJS({
121
+ "node_modules/import-in-the-middle/index.js"(exports2, module2) {
122
+ var path = require("path");
123
+ var parse = require_module_details_from_path();
124
+ var { fileURLToPath } = require("url");
125
+ var { MessageChannel } = require("worker_threads");
126
+ var {
127
+ importHooks,
128
+ specifiers,
129
+ toHook,
130
+ getExperimentalPatchInternals
131
+ } = require_register();
132
+ function addHook(hook) {
133
+ importHooks.push(hook);
134
+ toHook.forEach(([name, namespace]) => hook(name, namespace));
135
+ }
136
+ function removeHook(hook) {
137
+ const index = importHooks.indexOf(hook);
138
+ if (index > -1) {
139
+ importHooks.splice(index, 1);
140
+ }
141
+ }
142
+ function callHookFn(hookFn, namespace, name, baseDir) {
143
+ const newDefault = hookFn(namespace, name, baseDir);
144
+ if (newDefault && newDefault !== namespace) {
145
+ namespace.default = newDefault;
146
+ }
147
+ }
148
+ var sendModulesToLoader;
149
+ function createAddHookMessageChannel2() {
150
+ const { port1, port2 } = new MessageChannel();
151
+ let pendingAckCount = 0;
152
+ let resolveFn;
153
+ sendModulesToLoader = (modules) => {
154
+ pendingAckCount++;
155
+ port1.postMessage(modules);
156
+ };
157
+ port1.on("message", () => {
158
+ pendingAckCount--;
159
+ if (resolveFn && pendingAckCount <= 0) {
160
+ resolveFn();
161
+ }
162
+ }).unref();
163
+ function waitForAllMessagesAcknowledged() {
164
+ const timer = setInterval(() => {
165
+ }, 1e3);
166
+ const promise = new Promise((resolve) => {
167
+ resolveFn = resolve;
168
+ }).then(() => {
169
+ clearInterval(timer);
170
+ });
171
+ if (pendingAckCount === 0) {
172
+ resolveFn();
173
+ }
174
+ return promise;
175
+ }
176
+ const addHookMessagePort = port2;
177
+ const registerOptions2 = { data: { addHookMessagePort, include: [] }, transferList: [addHookMessagePort] };
178
+ return { registerOptions: registerOptions2, addHookMessagePort, waitForAllMessagesAcknowledged };
179
+ }
180
+ function Hook2(modules, options, hookFn) {
181
+ if (this instanceof Hook2 === false) return new Hook2(modules, options, hookFn);
182
+ if (typeof modules === "function") {
183
+ hookFn = modules;
184
+ modules = null;
185
+ options = null;
186
+ } else if (typeof options === "function") {
187
+ hookFn = options;
188
+ options = null;
189
+ }
190
+ const internals = options ? options.internals === true : false;
191
+ if (sendModulesToLoader && Array.isArray(modules)) {
192
+ sendModulesToLoader(modules);
193
+ }
194
+ this._iitmHook = (name, namespace) => {
195
+ const filename = name;
196
+ const isBuiltin = name.startsWith("node:");
197
+ let baseDir;
198
+ if (isBuiltin) {
199
+ name = name.replace(/^node:/, "");
200
+ } else {
201
+ if (name.startsWith("file://")) {
202
+ try {
203
+ name = fileURLToPath(name);
204
+ } catch (e) {
205
+ }
206
+ }
207
+ const details = parse(name);
208
+ if (details) {
209
+ name = details.name;
210
+ baseDir = details.basedir;
211
+ }
212
+ }
213
+ if (modules) {
214
+ for (const moduleName of modules) {
215
+ if (moduleName === name) {
216
+ if (baseDir) {
217
+ if (internals) {
218
+ name = name + path.sep + path.relative(baseDir, fileURLToPath(filename));
219
+ } else {
220
+ if (!getExperimentalPatchInternals() && !baseDir.endsWith(specifiers.get(filename))) continue;
221
+ }
222
+ }
223
+ callHookFn(hookFn, namespace, name, baseDir);
224
+ }
225
+ }
226
+ } else {
227
+ callHookFn(hookFn, namespace, name, baseDir);
228
+ }
229
+ };
230
+ addHook(this._iitmHook);
231
+ }
232
+ Hook2.prototype.unhook = function() {
233
+ removeHook(this._iitmHook);
234
+ };
235
+ module2.exports = Hook2;
236
+ module2.exports.Hook = Hook2;
237
+ module2.exports.addHook = addHook;
238
+ module2.exports.removeHook = removeHook;
239
+ module2.exports.createAddHookMessageChannel = createAddHookMessageChannel2;
240
+ }
241
+ });
242
+
243
+ // src/bin/hook.ts
244
+ var import_module = require("module");
245
+ var import_import_in_the_middle = __toESM(require_import_in_the_middle());
246
+ var import_meta = {};
247
+ var { registerOptions } = (0, import_import_in_the_middle.createAddHookMessageChannel)();
248
+ (0, import_module.register)("import-in-the-middle/hook.mjs", import_meta.url, registerOptions);
249
+ var HOP_BY_HOP = /* @__PURE__ */ new Set([
250
+ "connection",
251
+ "proxy-connection",
252
+ "keep-alive",
253
+ "te",
254
+ "trailer",
255
+ "transfer-encoding",
256
+ "upgrade",
257
+ "proxy-authorization",
258
+ "proxy-authenticate",
259
+ "host"
260
+ ]);
261
+ function sanitizeReqHeaders(h, hasBody) {
262
+ const out = {};
263
+ for (const [k, v] of Object.entries(h ?? {})) {
264
+ const key = k.toLowerCase();
265
+ if (HOP_BY_HOP.has(key)) continue;
266
+ if (key === "content-length" && !hasBody) continue;
267
+ if (typeof v === "string") out[key] = v;
268
+ }
269
+ delete out["accept-encoding"];
270
+ return out;
271
+ }
272
+ async function loopbackProxy(route) {
273
+ const req = route.request();
274
+ const url = new URL(req.url());
275
+ const isHttps = url.protocol === "https:";
276
+ const port = url.port ? Number(url.port) : isHttps ? 443 : 80;
277
+ const target = `${isHttps ? "https" : "http"}://127.0.0.1:${port}${url.pathname}${url.search}`;
278
+ const method = req.method();
279
+ const isHead = method === "HEAD";
280
+ const isGet = method === "GET";
281
+ const postBuf = req.postDataBuffer();
282
+ const body = !isGet && !isHead && postBuf && postBuf.length ? new Blob([postBuf]) : void 0;
283
+ const headers = sanitizeReqHeaders(await req.headers(), !!body);
284
+ const init = {
285
+ method,
286
+ headers,
287
+ ...body ? { body } : {},
288
+ // only include body when valid
289
+ // If you ever switch to a Readable stream body, also add: duplex: 'half'
290
+ signal: AbortSignal.timeout(3e4)
291
+ };
292
+ const upstream = await fetch(target, init);
293
+ const status = upstream.status;
294
+ const respHeadersRaw = Object.fromEntries(upstream.headers);
295
+ const buf = isHead ? Buffer.alloc(0) : Buffer.from(await upstream.arrayBuffer());
296
+ const respHeaders = {};
297
+ for (const [k, v] of Object.entries(respHeadersRaw)) {
298
+ const key = k.toLowerCase();
299
+ if (HOP_BY_HOP.has(key)) continue;
300
+ if (key === "content-length") continue;
301
+ respHeaders[key] = v;
302
+ }
303
+ if (!isHead) respHeaders["content-length"] = String(buf.length);
304
+ await route.fulfill({
305
+ status,
306
+ headers: respHeaders,
307
+ ...isHead ? {} : { body: buf }
308
+ });
309
+ }
310
+ new import_import_in_the_middle.Hook(["@playwright/test"], (exported, name, baseDir) => {
311
+ const base = exported;
312
+ const routedTest = base.test.extend({
313
+ routeSetup: [
314
+ async ({ context }, use) => {
315
+ const regex = /^https?:\/\/(?:127\.0\.0\.1|\[::1\]|(?:[\w-]+\.)*localhost)(?::\d+)?/i;
316
+ await context.route(regex, loopbackProxy);
317
+ await use();
318
+ await context.unroute(regex, loopbackProxy);
319
+ },
320
+ { auto: true }
321
+ ]
322
+ });
323
+ exported.test = routedTest;
324
+ return exported;
325
+ });
package/dist/index.js CHANGED
@@ -545,6 +545,14 @@ function startTunnel(tunnelProcess2, options) {
545
545
  );
546
546
  process.exit(1);
547
547
  }
548
+ if (!options?.port) {
549
+ console.error(
550
+ source_default.red.bold(
551
+ "\u274C Error: Please provide a port to expose via the tunnel using the --tunnel or --port option."
552
+ )
553
+ );
554
+ process.exit(1);
555
+ }
548
556
  const tunnelDomain = `${options.subdomain || crypto.randomUUID()}.browsermationtunnel.com`;
549
557
  tunnelProcess2 = (0, import_node_child_process.spawn)("ssh", [
550
558
  "-o",
@@ -552,7 +560,7 @@ function startTunnel(tunnelProcess2, options) {
552
560
  "-o",
553
561
  "UserKnownHostsFile=/dev/null",
554
562
  "-R",
555
- `:80:localhost:${options.tunnel}`,
563
+ `:80:localhost:${options.port}`,
556
564
  "v0@browsermationtunnel.com",
557
565
  "-p",
558
566
  "2200",
@@ -659,7 +667,7 @@ async function defineConfig(config) {
659
667
  use: {
660
668
  ...config.use,
661
669
  connectOptions: {
662
- wsEndpoint: endpointUrl
670
+ wsEndpoint: "endpointUrl"
663
671
  }
664
672
  }
665
673
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browsermation/test",
3
- "version": "0.0.51",
3
+ "version": "0.0.53",
4
4
  "description": "The testing platform for Playwright by Browsermation.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -27,10 +27,11 @@
27
27
  ],
28
28
  "scripts": {
29
29
  "build:cli": "esbuild src/bin/cli.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/bin/cli.js",
30
+ "build:hook": "esbuild src/bin/hook.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/bin/hook.js",
30
31
  "build:reporter": "esbuild src/reporter/reporter.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/reporter.js",
31
32
  "build:index": "esbuild src/index.ts --bundle --platform=node --external:playwright --target=node22 --outfile=dist/index.js",
32
33
  "build:types": "tsc --emitDeclarationOnly --outDir dist",
33
- "build": "rm -rf dist && npm run build:cli && npm run build:index && npm run build:reporter && npm run build:types",
34
+ "build": "rm -rf dist && npm run build:cli && npm run build:hook && npm run build:index && npm run build:reporter && npm run build:types",
34
35
  "start": "node dist/bin/cli.js",
35
36
  "build:start": "npm run build && npm start",
36
37
  "publishPackage": "npm run build && npm publish --access public"
@@ -57,6 +58,7 @@
57
58
  "chalk": "^5.4.1",
58
59
  "commander": "^14.0.0",
59
60
  "form-data": "^4.0.3",
61
+ "import-in-the-middle": "^1.14.2",
60
62
  "ora": "^8.2.0",
61
63
  "tiny-invariant": "^1.3.3",
62
64
  "ts-morph": "^26.0.0",