browsermation 0.0.98-beta.1 → 0.0.98-beta.3
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 +963 -251
- package/package.json +3 -3
package/dist/bin/cli.js
CHANGED
|
@@ -3638,7 +3638,7 @@ var require_util = __commonJS({
|
|
|
3638
3638
|
return path7;
|
|
3639
3639
|
}
|
|
3640
3640
|
exports2.normalize = normalize;
|
|
3641
|
-
function
|
|
3641
|
+
function join8(aRoot, aPath) {
|
|
3642
3642
|
if (aRoot === "") {
|
|
3643
3643
|
aRoot = ".";
|
|
3644
3644
|
}
|
|
@@ -3670,11 +3670,11 @@ var require_util = __commonJS({
|
|
|
3670
3670
|
}
|
|
3671
3671
|
return joined;
|
|
3672
3672
|
}
|
|
3673
|
-
exports2.join =
|
|
3673
|
+
exports2.join = join8;
|
|
3674
3674
|
exports2.isAbsolute = function(aPath) {
|
|
3675
3675
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
3676
3676
|
};
|
|
3677
|
-
function
|
|
3677
|
+
function relative5(aRoot, aPath) {
|
|
3678
3678
|
if (aRoot === "") {
|
|
3679
3679
|
aRoot = ".";
|
|
3680
3680
|
}
|
|
@@ -3693,7 +3693,7 @@ var require_util = __commonJS({
|
|
|
3693
3693
|
}
|
|
3694
3694
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
3695
3695
|
}
|
|
3696
|
-
exports2.relative =
|
|
3696
|
+
exports2.relative = relative5;
|
|
3697
3697
|
var supportsNullProto = (function() {
|
|
3698
3698
|
var obj = /* @__PURE__ */ Object.create(null);
|
|
3699
3699
|
return !("__proto__" in obj);
|
|
@@ -3843,7 +3843,7 @@ var require_util = __commonJS({
|
|
|
3843
3843
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
3844
3844
|
}
|
|
3845
3845
|
}
|
|
3846
|
-
sourceURL =
|
|
3846
|
+
sourceURL = join8(urlGenerate(parsed), sourceURL);
|
|
3847
3847
|
}
|
|
3848
3848
|
return normalize(sourceURL);
|
|
3849
3849
|
}
|
|
@@ -15075,11 +15075,11 @@ ${lanes.join("\n")}
|
|
|
15075
15075
|
return toComponents;
|
|
15076
15076
|
}
|
|
15077
15077
|
const components = toComponents.slice(start);
|
|
15078
|
-
const
|
|
15078
|
+
const relative5 = [];
|
|
15079
15079
|
for (; start < fromComponents.length; start++) {
|
|
15080
|
-
|
|
15080
|
+
relative5.push("..");
|
|
15081
15081
|
}
|
|
15082
|
-
return ["", ...
|
|
15082
|
+
return ["", ...relative5, ...components];
|
|
15083
15083
|
}
|
|
15084
15084
|
function getRelativePathFromDirectory(fromDirectory, to, getCanonicalFileNameOrIgnoreCase) {
|
|
15085
15085
|
Debug.assert(getRootLength(fromDirectory) > 0 === getRootLength(to) > 0, "Paths must either both be absolute or both be relative");
|
|
@@ -53636,11 +53636,11 @@ ${lanes.join("\n")}
|
|
|
53636
53636
|
if (i < rootLength) {
|
|
53637
53637
|
return void 0;
|
|
53638
53638
|
}
|
|
53639
|
-
const
|
|
53640
|
-
if (
|
|
53639
|
+
const sep3 = directory.lastIndexOf(directorySeparator, i - 1);
|
|
53640
|
+
if (sep3 === -1) {
|
|
53641
53641
|
return void 0;
|
|
53642
53642
|
}
|
|
53643
|
-
return directory.substr(0, Math.max(
|
|
53643
|
+
return directory.substr(0, Math.max(sep3, rootLength));
|
|
53644
53644
|
}
|
|
53645
53645
|
}
|
|
53646
53646
|
}
|
|
@@ -59546,9 +59546,9 @@ ${lanes.join("\n")}
|
|
|
59546
59546
|
if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) {
|
|
59547
59547
|
return;
|
|
59548
59548
|
}
|
|
59549
|
-
const
|
|
59549
|
+
const relative5 = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName);
|
|
59550
59550
|
for (const symlinkDirectory of symlinkDirectories) {
|
|
59551
|
-
const option = resolvePath(symlinkDirectory,
|
|
59551
|
+
const option = resolvePath(symlinkDirectory, relative5);
|
|
59552
59552
|
const result2 = cb(option, target === referenceRedirect);
|
|
59553
59553
|
shouldFilterIgnoredPaths = true;
|
|
59554
59554
|
if (result2) return result2;
|
|
@@ -218118,7 +218118,7 @@ var require_path_browserify = __commonJS({
|
|
|
218118
218118
|
}
|
|
218119
218119
|
return res;
|
|
218120
218120
|
}
|
|
218121
|
-
function _format(
|
|
218121
|
+
function _format(sep3, pathObject) {
|
|
218122
218122
|
var dir = pathObject.dir || pathObject.root;
|
|
218123
218123
|
var base = pathObject.base || (pathObject.name || "") + (pathObject.ext || "");
|
|
218124
218124
|
if (!dir) {
|
|
@@ -218127,7 +218127,7 @@ var require_path_browserify = __commonJS({
|
|
|
218127
218127
|
if (dir === pathObject.root) {
|
|
218128
218128
|
return dir + base;
|
|
218129
218129
|
}
|
|
218130
|
-
return dir +
|
|
218130
|
+
return dir + sep3 + base;
|
|
218131
218131
|
}
|
|
218132
218132
|
var posix = {
|
|
218133
218133
|
// path.resolve([from ...], to)
|
|
@@ -218178,7 +218178,7 @@ var require_path_browserify = __commonJS({
|
|
|
218178
218178
|
assertPath(path7);
|
|
218179
218179
|
return path7.length > 0 && path7.charCodeAt(0) === 47;
|
|
218180
218180
|
},
|
|
218181
|
-
join: function
|
|
218181
|
+
join: function join8() {
|
|
218182
218182
|
if (arguments.length === 0)
|
|
218183
218183
|
return ".";
|
|
218184
218184
|
var joined;
|
|
@@ -218196,7 +218196,7 @@ var require_path_browserify = __commonJS({
|
|
|
218196
218196
|
return ".";
|
|
218197
218197
|
return posix.normalize(joined);
|
|
218198
218198
|
},
|
|
218199
|
-
relative: function
|
|
218199
|
+
relative: function relative5(from, to) {
|
|
218200
218200
|
assertPath(from);
|
|
218201
218201
|
assertPath(to);
|
|
218202
218202
|
if (from === to) return "";
|
|
@@ -218265,7 +218265,7 @@ var require_path_browserify = __commonJS({
|
|
|
218265
218265
|
_makeLong: function _makeLong(path7) {
|
|
218266
218266
|
return path7;
|
|
218267
218267
|
},
|
|
218268
|
-
dirname: function
|
|
218268
|
+
dirname: function dirname3(path7) {
|
|
218269
218269
|
assertPath(path7);
|
|
218270
218270
|
if (path7.length === 0) return ".";
|
|
218271
218271
|
var code = path7.charCodeAt(0);
|
|
@@ -220696,10 +220696,10 @@ var require_dist2 = __commonJS({
|
|
|
220696
220696
|
ignore: ignorePatterns
|
|
220697
220697
|
};
|
|
220698
220698
|
}
|
|
220699
|
-
function formatPaths(paths,
|
|
220699
|
+
function formatPaths(paths, relative5) {
|
|
220700
220700
|
for (let i = paths.length - 1; i >= 0; i--) {
|
|
220701
220701
|
const path$2 = paths[i];
|
|
220702
|
-
paths[i] =
|
|
220702
|
+
paths[i] = relative5(path$2);
|
|
220703
220703
|
}
|
|
220704
220704
|
return paths;
|
|
220705
220705
|
}
|
|
@@ -220796,26 +220796,26 @@ var require_dist2 = __commonJS({
|
|
|
220796
220796
|
props.root = props.root.replace(BACKSLASHES, "");
|
|
220797
220797
|
const root = props.root;
|
|
220798
220798
|
if (options.debug) log("internal properties:", props);
|
|
220799
|
-
const
|
|
220800
|
-
return [new fdir.fdir(fdirOptions).crawl(root),
|
|
220799
|
+
const relative5 = cwd !== root && !options.absolute && buildRelative(cwd, props.root);
|
|
220800
|
+
return [new fdir.fdir(fdirOptions).crawl(root), relative5];
|
|
220801
220801
|
}
|
|
220802
220802
|
async function glob(patternsOrOptions, options) {
|
|
220803
220803
|
if (patternsOrOptions && (options === null || options === void 0 ? void 0 : options.patterns)) throw new Error("Cannot pass patterns as both an argument and an option");
|
|
220804
220804
|
const isModern = isReadonlyArray(patternsOrOptions) || typeof patternsOrOptions === "string";
|
|
220805
220805
|
const opts = isModern ? options : patternsOrOptions;
|
|
220806
220806
|
const patterns = isModern ? patternsOrOptions : patternsOrOptions.patterns;
|
|
220807
|
-
const [crawler,
|
|
220808
|
-
if (!
|
|
220809
|
-
return formatPaths(await crawler.withPromise(),
|
|
220807
|
+
const [crawler, relative5] = getCrawler(patterns, opts);
|
|
220808
|
+
if (!relative5) return crawler.withPromise();
|
|
220809
|
+
return formatPaths(await crawler.withPromise(), relative5);
|
|
220810
220810
|
}
|
|
220811
220811
|
function globSync(patternsOrOptions, options) {
|
|
220812
220812
|
if (patternsOrOptions && (options === null || options === void 0 ? void 0 : options.patterns)) throw new Error("Cannot pass patterns as both an argument and an option");
|
|
220813
220813
|
const isModern = isReadonlyArray(patternsOrOptions) || typeof patternsOrOptions === "string";
|
|
220814
220814
|
const opts = isModern ? options : patternsOrOptions;
|
|
220815
220815
|
const patterns = isModern ? patternsOrOptions : patternsOrOptions.patterns;
|
|
220816
|
-
const [crawler,
|
|
220817
|
-
if (!
|
|
220818
|
-
return formatPaths(crawler.sync(),
|
|
220816
|
+
const [crawler, relative5] = getCrawler(patterns, opts);
|
|
220817
|
+
if (!relative5) return crawler.sync();
|
|
220818
|
+
return formatPaths(crawler.sync(), relative5);
|
|
220819
220819
|
}
|
|
220820
220820
|
exports2.convertPathToPattern = convertPathToPattern;
|
|
220821
220821
|
exports2.escapePath = escapePath;
|
|
@@ -246761,8 +246761,8 @@ var require_readdir_glob = __commonJS({
|
|
|
246761
246761
|
useStat = true;
|
|
246762
246762
|
}
|
|
246763
246763
|
const filename = dir + "/" + name;
|
|
246764
|
-
const
|
|
246765
|
-
const absolute = path7 + "/" +
|
|
246764
|
+
const relative5 = filename.slice(1);
|
|
246765
|
+
const absolute = path7 + "/" + relative5;
|
|
246766
246766
|
let stats = null;
|
|
246767
246767
|
if (useStat || followSymlinks) {
|
|
246768
246768
|
stats = await stat(absolute, followSymlinks);
|
|
@@ -246774,12 +246774,12 @@ var require_readdir_glob = __commonJS({
|
|
|
246774
246774
|
stats = { isDirectory: () => false };
|
|
246775
246775
|
}
|
|
246776
246776
|
if (stats.isDirectory()) {
|
|
246777
|
-
if (!shouldSkip(
|
|
246778
|
-
yield { relative:
|
|
246777
|
+
if (!shouldSkip(relative5)) {
|
|
246778
|
+
yield { relative: relative5, absolute, stats };
|
|
246779
246779
|
yield* exploreWalkAsync(filename, path7, followSymlinks, useStat, shouldSkip, false);
|
|
246780
246780
|
}
|
|
246781
246781
|
} else {
|
|
246782
|
-
yield { relative:
|
|
246782
|
+
yield { relative: relative5, absolute, stats };
|
|
246783
246783
|
}
|
|
246784
246784
|
}
|
|
246785
246785
|
}
|
|
@@ -246849,11 +246849,11 @@ var require_readdir_glob = __commonJS({
|
|
|
246849
246849
|
}
|
|
246850
246850
|
setTimeout(() => this._next(), 0);
|
|
246851
246851
|
}
|
|
246852
|
-
_shouldSkipDirectory(
|
|
246853
|
-
return this.skipMatchers.some((m) => m.match(
|
|
246852
|
+
_shouldSkipDirectory(relative5) {
|
|
246853
|
+
return this.skipMatchers.some((m) => m.match(relative5));
|
|
246854
246854
|
}
|
|
246855
|
-
_fileMatches(
|
|
246856
|
-
const file =
|
|
246855
|
+
_fileMatches(relative5, isDirectory) {
|
|
246856
|
+
const file = relative5 + (isDirectory ? "/" : "");
|
|
246857
246857
|
return (this.matchers.length === 0 || this.matchers.some((m) => m.match(file))) && !this.ignoreMatchers.some((m) => m.match(file)) && (!this.options.nodir || !isDirectory);
|
|
246858
246858
|
}
|
|
246859
246859
|
_next() {
|
|
@@ -246862,16 +246862,16 @@ var require_readdir_glob = __commonJS({
|
|
|
246862
246862
|
if (!obj.done) {
|
|
246863
246863
|
const isDirectory = obj.value.stats.isDirectory();
|
|
246864
246864
|
if (this._fileMatches(obj.value.relative, isDirectory)) {
|
|
246865
|
-
let
|
|
246865
|
+
let relative5 = obj.value.relative;
|
|
246866
246866
|
let absolute = obj.value.absolute;
|
|
246867
246867
|
if (this.options.mark && isDirectory) {
|
|
246868
|
-
|
|
246868
|
+
relative5 += "/";
|
|
246869
246869
|
absolute += "/";
|
|
246870
246870
|
}
|
|
246871
246871
|
if (this.options.stat) {
|
|
246872
|
-
this.emit("match", { relative:
|
|
246872
|
+
this.emit("match", { relative: relative5, absolute, stat: obj.value.stats });
|
|
246873
246873
|
} else {
|
|
246874
|
-
this.emit("match", { relative:
|
|
246874
|
+
this.emit("match", { relative: relative5, absolute });
|
|
246875
246875
|
}
|
|
246876
246876
|
}
|
|
246877
246877
|
this._next(this.iterator);
|
|
@@ -249841,7 +249841,7 @@ var require_BufferList = __commonJS({
|
|
|
249841
249841
|
this.head = this.tail = null;
|
|
249842
249842
|
this.length = 0;
|
|
249843
249843
|
};
|
|
249844
|
-
BufferList.prototype.join = function
|
|
249844
|
+
BufferList.prototype.join = function join8(s) {
|
|
249845
249845
|
if (this.length === 0) return "";
|
|
249846
249846
|
var p = this.head;
|
|
249847
249847
|
var ret = "" + p.data;
|
|
@@ -252376,8 +252376,8 @@ var require_primordials = __commonJS({
|
|
|
252376
252376
|
ArrayPrototypeIndexOf(self2, el) {
|
|
252377
252377
|
return self2.indexOf(el);
|
|
252378
252378
|
},
|
|
252379
|
-
ArrayPrototypeJoin(self2,
|
|
252380
|
-
return self2.join(
|
|
252379
|
+
ArrayPrototypeJoin(self2, sep3) {
|
|
252380
|
+
return self2.join(sep3);
|
|
252381
252381
|
},
|
|
252382
252382
|
ArrayPrototypeMap(self2, fn) {
|
|
252383
252383
|
return self2.map(fn);
|
|
@@ -264413,7 +264413,7 @@ var require_commonjs7 = __commonJS({
|
|
|
264413
264413
|
*
|
|
264414
264414
|
* @internal
|
|
264415
264415
|
*/
|
|
264416
|
-
constructor(cwd = process.cwd(), pathImpl,
|
|
264416
|
+
constructor(cwd = process.cwd(), pathImpl, sep3, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS } = {}) {
|
|
264417
264417
|
this.#fs = fsFromOption(fs);
|
|
264418
264418
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
264419
264419
|
cwd = (0, node_url_1.fileURLToPath)(cwd);
|
|
@@ -264424,7 +264424,7 @@ var require_commonjs7 = __commonJS({
|
|
|
264424
264424
|
this.#resolveCache = new ResolveCache();
|
|
264425
264425
|
this.#resolvePosixCache = new ResolveCache();
|
|
264426
264426
|
this.#children = new ChildrenCache(childrenCacheSize);
|
|
264427
|
-
const split = cwdPath.substring(this.rootPath.length).split(
|
|
264427
|
+
const split = cwdPath.substring(this.rootPath.length).split(sep3);
|
|
264428
264428
|
if (split.length === 1 && !split[0]) {
|
|
264429
264429
|
split.pop();
|
|
264430
264430
|
}
|
|
@@ -265267,10 +265267,10 @@ var require_ignore = __commonJS({
|
|
|
265267
265267
|
ignored(p) {
|
|
265268
265268
|
const fullpath = p.fullpath();
|
|
265269
265269
|
const fullpaths = `${fullpath}/`;
|
|
265270
|
-
const
|
|
265271
|
-
const relatives = `${
|
|
265270
|
+
const relative5 = p.relative() || ".";
|
|
265271
|
+
const relatives = `${relative5}/`;
|
|
265272
265272
|
for (const m of this.relative) {
|
|
265273
|
-
if (m.match(
|
|
265273
|
+
if (m.match(relative5) || m.match(relatives))
|
|
265274
265274
|
return true;
|
|
265275
265275
|
}
|
|
265276
265276
|
for (const m of this.absolute) {
|
|
@@ -265281,9 +265281,9 @@ var require_ignore = __commonJS({
|
|
|
265281
265281
|
}
|
|
265282
265282
|
childrenIgnored(p) {
|
|
265283
265283
|
const fullpath = p.fullpath() + "/";
|
|
265284
|
-
const
|
|
265284
|
+
const relative5 = (p.relative() || ".") + "/";
|
|
265285
265285
|
for (const m of this.relativeChildren) {
|
|
265286
|
-
if (m.match(
|
|
265286
|
+
if (m.match(relative5))
|
|
265287
265287
|
return true;
|
|
265288
265288
|
}
|
|
265289
265289
|
for (const m of this.absoluteChildren) {
|
|
@@ -282462,8 +282462,8 @@ var require_follow_redirects = __commonJS({
|
|
|
282462
282462
|
}
|
|
282463
282463
|
return parsed;
|
|
282464
282464
|
}
|
|
282465
|
-
function resolveUrl(
|
|
282466
|
-
return useNativeURL ? new URL2(
|
|
282465
|
+
function resolveUrl(relative5, base) {
|
|
282466
|
+
return useNativeURL ? new URL2(relative5, base) : parseUrl(url2.resolve(base, relative5));
|
|
282467
282467
|
}
|
|
282468
282468
|
function validateUrl(input) {
|
|
282469
282469
|
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
|
@@ -283064,7 +283064,7 @@ var {
|
|
|
283064
283064
|
// package.json
|
|
283065
283065
|
var package_default = {
|
|
283066
283066
|
name: "browsermation",
|
|
283067
|
-
version: "0.0.98-beta.
|
|
283067
|
+
version: "0.0.98-beta.3",
|
|
283068
283068
|
description: "The testing platform for Playwright by Browsermation.",
|
|
283069
283069
|
main: "./dist/index.js",
|
|
283070
283070
|
types: "./dist/index.d.ts",
|
|
@@ -283075,7 +283075,7 @@ var package_default = {
|
|
|
283075
283075
|
"dist"
|
|
283076
283076
|
],
|
|
283077
283077
|
scripts: {
|
|
283078
|
-
"build:cli": "esbuild src/bin/cli.ts --bundle --platform=node --external:@browsermation/browser-engine --external:playwright --target=node22 --outfile=dist/bin/cli.js",
|
|
283078
|
+
"build:cli": "esbuild src/bin/cli.ts --bundle --platform=node --external:@browsermation/browser-engine --external:playwright --external:esbuild --target=node22 --outfile=dist/bin/cli.js",
|
|
283079
283079
|
build: "rm -rf dist && npm run build:cli",
|
|
283080
283080
|
start: "node dist/bin/cli.js",
|
|
283081
283081
|
"build:start": "npm run build && npm start",
|
|
@@ -283096,11 +283096,11 @@ var package_default = {
|
|
|
283096
283096
|
devDependencies: {
|
|
283097
283097
|
"@types/archiver": "^7.0.0",
|
|
283098
283098
|
"@types/node": "^25.0.3",
|
|
283099
|
-
esbuild: "^0.27.2",
|
|
283100
283099
|
typescript: "^5.9.3",
|
|
283101
283100
|
vitest: "^4.0.16"
|
|
283102
283101
|
},
|
|
283103
283102
|
dependencies: {
|
|
283103
|
+
esbuild: "^0.27.2",
|
|
283104
283104
|
"@browsermation/browser-engine": "^0.0.44",
|
|
283105
283105
|
archiver: "^7.0.1",
|
|
283106
283106
|
axios: "^1.13.2",
|
|
@@ -285760,100 +285760,55 @@ var ASSET_EXTENSIONS = [
|
|
|
285760
285760
|
".mp3",
|
|
285761
285761
|
".wav"
|
|
285762
285762
|
];
|
|
285763
|
-
var
|
|
285764
|
-
|
|
285765
|
-
|
|
285766
|
-
|
|
285767
|
-
|
|
285768
|
-
|
|
285769
|
-
|
|
285770
|
-
|
|
285771
|
-
|
|
285772
|
-
|
|
285773
|
-
|
|
285774
|
-
}
|
|
285763
|
+
var FastImportExtractor = class _FastImportExtractor {
|
|
285764
|
+
static IMPORT_PATTERNS = [
|
|
285765
|
+
// ESM imports: import ... from 'module'
|
|
285766
|
+
/import\s+(?:(?:[\w*{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g,
|
|
285767
|
+
// ESM exports: export ... from 'module'
|
|
285768
|
+
/export\s+(?:(?:[\w*{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g,
|
|
285769
|
+
// Dynamic imports: import('module')
|
|
285770
|
+
/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
285771
|
+
// Require: require('module')
|
|
285772
|
+
/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g
|
|
285773
|
+
];
|
|
285775
285774
|
extractImports(filePath) {
|
|
285776
|
-
|
|
285775
|
+
const { readFileSync: readFileSync3 } = require("fs");
|
|
285776
|
+
let content;
|
|
285777
285777
|
try {
|
|
285778
|
-
|
|
285778
|
+
content = readFileSync3(filePath, "utf-8");
|
|
285779
285779
|
} catch {
|
|
285780
|
-
|
|
285780
|
+
return { staticImports: [], dynamicImports: [], requireCalls: [], assetImports: [] };
|
|
285781
|
+
}
|
|
285782
|
+
content = this.removeComments(content);
|
|
285783
|
+
const staticImports = [];
|
|
285784
|
+
const dynamicImports = [];
|
|
285785
|
+
const requireCalls = [];
|
|
285786
|
+
for (const match of content.matchAll(_FastImportExtractor.IMPORT_PATTERNS[0])) {
|
|
285787
|
+
if (match[1]) staticImports.push(match[1]);
|
|
285788
|
+
}
|
|
285789
|
+
for (const match of content.matchAll(_FastImportExtractor.IMPORT_PATTERNS[1])) {
|
|
285790
|
+
if (match[1]) staticImports.push(match[1]);
|
|
285791
|
+
}
|
|
285792
|
+
for (const match of content.matchAll(_FastImportExtractor.IMPORT_PATTERNS[2])) {
|
|
285793
|
+
if (match[1]) dynamicImports.push(match[1]);
|
|
285794
|
+
}
|
|
285795
|
+
for (const match of content.matchAll(_FastImportExtractor.IMPORT_PATTERNS[3])) {
|
|
285796
|
+
if (match[1]) requireCalls.push(match[1]);
|
|
285781
285797
|
}
|
|
285782
|
-
const staticImports = this.getStaticImports(sourceFile);
|
|
285783
|
-
const dynamicImports = this.getDynamicImports(sourceFile);
|
|
285784
|
-
const requireCalls = this.getRequireCalls(sourceFile);
|
|
285785
285798
|
const allImports = [...staticImports, ...dynamicImports, ...requireCalls];
|
|
285786
285799
|
return {
|
|
285787
285800
|
staticImports,
|
|
285788
285801
|
dynamicImports,
|
|
285789
285802
|
requireCalls,
|
|
285790
|
-
assetImports:
|
|
285803
|
+
assetImports: allImports.filter(
|
|
285804
|
+
(imp) => ASSET_EXTENSIONS.some((ext) => imp.toLowerCase().endsWith(ext))
|
|
285805
|
+
)
|
|
285791
285806
|
};
|
|
285792
285807
|
}
|
|
285793
|
-
|
|
285794
|
-
|
|
285795
|
-
|
|
285796
|
-
|
|
285797
|
-
}
|
|
285798
|
-
for (const exp of sourceFile.getExportDeclarations()) {
|
|
285799
|
-
const moduleSpecifier = exp.getModuleSpecifierValue();
|
|
285800
|
-
if (moduleSpecifier) {
|
|
285801
|
-
imports.push(moduleSpecifier);
|
|
285802
|
-
}
|
|
285803
|
-
}
|
|
285804
|
-
return imports;
|
|
285805
|
-
}
|
|
285806
|
-
getDynamicImports(sourceFile) {
|
|
285807
|
-
const imports = [];
|
|
285808
|
-
const callExpressions = sourceFile.getDescendantsOfKind(
|
|
285809
|
-
import_ts_morph.SyntaxKind.CallExpression
|
|
285810
|
-
);
|
|
285811
|
-
for (const call of callExpressions) {
|
|
285812
|
-
const expression = call.getExpression();
|
|
285813
|
-
if (expression.getKind() === import_ts_morph.SyntaxKind.ImportKeyword) {
|
|
285814
|
-
const args = call.getArguments();
|
|
285815
|
-
if (args.length > 0) {
|
|
285816
|
-
const firstArg = args[0];
|
|
285817
|
-
if (firstArg.isKind(import_ts_morph.SyntaxKind.StringLiteral)) {
|
|
285818
|
-
imports.push(firstArg.getLiteralValue());
|
|
285819
|
-
} else if (firstArg.isKind(import_ts_morph.SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
|
285820
|
-
imports.push(firstArg.getLiteralValue());
|
|
285821
|
-
} else if (firstArg.isKind(import_ts_morph.SyntaxKind.TemplateExpression)) {
|
|
285822
|
-
const head = firstArg.getHead().getLiteralValue();
|
|
285823
|
-
if (head) {
|
|
285824
|
-
console.warn(
|
|
285825
|
-
`Dynamic import with template expression found: ${head}... - may not be fully resolved`
|
|
285826
|
-
);
|
|
285827
|
-
}
|
|
285828
|
-
}
|
|
285829
|
-
}
|
|
285830
|
-
}
|
|
285831
|
-
}
|
|
285832
|
-
return imports;
|
|
285833
|
-
}
|
|
285834
|
-
getRequireCalls(sourceFile) {
|
|
285835
|
-
const imports = [];
|
|
285836
|
-
const callExpressions = sourceFile.getDescendantsOfKind(
|
|
285837
|
-
import_ts_morph.SyntaxKind.CallExpression
|
|
285838
|
-
);
|
|
285839
|
-
for (const call of callExpressions) {
|
|
285840
|
-
const expression = call.getExpression();
|
|
285841
|
-
if (expression.isKind(import_ts_morph.SyntaxKind.Identifier) && expression.getText() === "require") {
|
|
285842
|
-
const args = call.getArguments();
|
|
285843
|
-
if (args.length > 0) {
|
|
285844
|
-
const firstArg = args[0];
|
|
285845
|
-
if (firstArg.isKind(import_ts_morph.SyntaxKind.StringLiteral)) {
|
|
285846
|
-
imports.push(firstArg.getLiteralValue());
|
|
285847
|
-
}
|
|
285848
|
-
}
|
|
285849
|
-
}
|
|
285850
|
-
}
|
|
285851
|
-
return imports;
|
|
285852
|
-
}
|
|
285853
|
-
filterAssetImports(imports) {
|
|
285854
|
-
return imports.filter(
|
|
285855
|
-
(imp) => ASSET_EXTENSIONS.some((ext) => imp.toLowerCase().endsWith(ext))
|
|
285856
|
-
);
|
|
285808
|
+
removeComments(content) {
|
|
285809
|
+
content = content.replace(/\/\/.*$/gm, "");
|
|
285810
|
+
content = content.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
285811
|
+
return content;
|
|
285857
285812
|
}
|
|
285858
285813
|
};
|
|
285859
285814
|
|
|
@@ -286044,11 +285999,8 @@ var PathResolver = class {
|
|
|
286044
285999
|
};
|
|
286045
286000
|
|
|
286046
286001
|
// src/analyzer/dependency-graph.ts
|
|
286047
|
-
var
|
|
286048
|
-
|
|
286049
|
-
"playwright",
|
|
286050
|
-
"playwright-core",
|
|
286051
|
-
// Node.js built-in modules
|
|
286002
|
+
var PLAYWRIGHT_PACKAGES = ["@playwright/test", "playwright", "playwright-core"];
|
|
286003
|
+
var NODE_BUILTINS = /* @__PURE__ */ new Set([
|
|
286052
286004
|
"assert",
|
|
286053
286005
|
"buffer",
|
|
286054
286006
|
"child_process",
|
|
@@ -286085,30 +286037,57 @@ var EXCLUDED_PACKAGES = [
|
|
|
286085
286037
|
"vm",
|
|
286086
286038
|
"worker_threads",
|
|
286087
286039
|
"zlib"
|
|
286088
|
-
];
|
|
286040
|
+
]);
|
|
286089
286041
|
var DependencyGraphBuilder = class {
|
|
286090
286042
|
graph = /* @__PURE__ */ new Map();
|
|
286091
286043
|
visited = /* @__PURE__ */ new Set();
|
|
286044
|
+
skipped = /* @__PURE__ */ new Set();
|
|
286092
286045
|
nodeModuleDeps = /* @__PURE__ */ new Set();
|
|
286093
286046
|
assets = /* @__PURE__ */ new Set();
|
|
286094
286047
|
extractor;
|
|
286095
286048
|
resolver;
|
|
286096
286049
|
projectRoot;
|
|
286050
|
+
testDir = "";
|
|
286097
286051
|
constructor(options) {
|
|
286098
286052
|
this.projectRoot = options.projectRoot;
|
|
286099
|
-
|
|
286100
|
-
this.extractor = new ImportExtractor(
|
|
286101
|
-
require("fs").existsSync(tsconfigPath) ? tsconfigPath : void 0
|
|
286102
|
-
);
|
|
286053
|
+
this.extractor = new FastImportExtractor();
|
|
286103
286054
|
this.resolver = new PathResolver(options.projectRoot);
|
|
286104
286055
|
}
|
|
286105
|
-
|
|
286056
|
+
/**
|
|
286057
|
+
* Check if a file is within the test directory (or is a config file)
|
|
286058
|
+
* Files in node_modules are never test-related (they're npm dependencies)
|
|
286059
|
+
*/
|
|
286060
|
+
isTestRelatedFile(filePath) {
|
|
286061
|
+
const relativePath = path2.relative(this.projectRoot, filePath);
|
|
286062
|
+
if (relativePath.startsWith("node_modules")) {
|
|
286063
|
+
return false;
|
|
286064
|
+
}
|
|
286065
|
+
if (relativePath.includes("playwright.config") || relativePath === "tsconfig.json") {
|
|
286066
|
+
return true;
|
|
286067
|
+
}
|
|
286068
|
+
const testDirRelative = path2.relative(this.projectRoot, this.testDir);
|
|
286069
|
+
if (testDirRelative === "") {
|
|
286070
|
+
return true;
|
|
286071
|
+
}
|
|
286072
|
+
if (relativePath.startsWith(testDirRelative + path2.sep) || relativePath === testDirRelative) {
|
|
286073
|
+
return true;
|
|
286074
|
+
}
|
|
286075
|
+
return false;
|
|
286076
|
+
}
|
|
286077
|
+
async build(entryPoints, testDir) {
|
|
286078
|
+
this.testDir = testDir;
|
|
286079
|
+
const testDirRelative = path2.relative(this.projectRoot, testDir);
|
|
286080
|
+
console.log(`Test directory: ${testDirRelative || "(project root)"}`);
|
|
286106
286081
|
const queue = [...entryPoints];
|
|
286107
286082
|
while (queue.length > 0) {
|
|
286108
286083
|
const filePath = queue.shift();
|
|
286109
286084
|
const normalizedPath = path2.resolve(filePath);
|
|
286110
286085
|
if (this.visited.has(normalizedPath)) continue;
|
|
286111
286086
|
this.visited.add(normalizedPath);
|
|
286087
|
+
if (!this.isTestRelatedFile(normalizedPath)) {
|
|
286088
|
+
this.skipped.add(path2.relative(this.projectRoot, normalizedPath));
|
|
286089
|
+
continue;
|
|
286090
|
+
}
|
|
286112
286091
|
const node = this.processFile(normalizedPath);
|
|
286113
286092
|
if (!node) continue;
|
|
286114
286093
|
this.graph.set(normalizedPath, node);
|
|
@@ -286118,6 +286097,9 @@ var DependencyGraphBuilder = class {
|
|
|
286118
286097
|
}
|
|
286119
286098
|
}
|
|
286120
286099
|
}
|
|
286100
|
+
if (this.skipped.size > 0) {
|
|
286101
|
+
console.log(`Skipped ${this.skipped.size} app source files (not needed for tests)`);
|
|
286102
|
+
}
|
|
286121
286103
|
return {
|
|
286122
286104
|
nodes: this.graph,
|
|
286123
286105
|
entryPoints,
|
|
@@ -286168,6 +286150,9 @@ var DependencyGraphBuilder = class {
|
|
|
286168
286150
|
if (moduleSpecifier.startsWith("node:")) {
|
|
286169
286151
|
return null;
|
|
286170
286152
|
}
|
|
286153
|
+
if (moduleSpecifier.startsWith(".") || moduleSpecifier.startsWith("/")) {
|
|
286154
|
+
return null;
|
|
286155
|
+
}
|
|
286171
286156
|
if (moduleSpecifier.startsWith("@")) {
|
|
286172
286157
|
const parts2 = moduleSpecifier.split("/");
|
|
286173
286158
|
if (parts2.length >= 2) {
|
|
@@ -286176,10 +286161,36 @@ var DependencyGraphBuilder = class {
|
|
|
286176
286161
|
return null;
|
|
286177
286162
|
}
|
|
286178
286163
|
const parts = moduleSpecifier.split("/");
|
|
286179
|
-
|
|
286164
|
+
const packageName = parts[0] || null;
|
|
286165
|
+
const invalidPackageNames = [
|
|
286166
|
+
"src",
|
|
286167
|
+
"lib",
|
|
286168
|
+
"dist",
|
|
286169
|
+
"build",
|
|
286170
|
+
"app",
|
|
286171
|
+
"pages",
|
|
286172
|
+
"components",
|
|
286173
|
+
"utils",
|
|
286174
|
+
"helpers",
|
|
286175
|
+
"services",
|
|
286176
|
+
"types",
|
|
286177
|
+
"models",
|
|
286178
|
+
"config",
|
|
286179
|
+
"public",
|
|
286180
|
+
"assets",
|
|
286181
|
+
"styles",
|
|
286182
|
+
"tests",
|
|
286183
|
+
"test",
|
|
286184
|
+
"spec",
|
|
286185
|
+
"e2e"
|
|
286186
|
+
];
|
|
286187
|
+
if (packageName && invalidPackageNames.includes(packageName)) {
|
|
286188
|
+
return null;
|
|
286189
|
+
}
|
|
286190
|
+
return packageName;
|
|
286180
286191
|
}
|
|
286181
286192
|
isExcludedPackage(packageName) {
|
|
286182
|
-
return
|
|
286193
|
+
return PLAYWRIGHT_PACKAGES.includes(packageName) || NODE_BUILTINS.has(packageName);
|
|
286183
286194
|
}
|
|
286184
286195
|
determineType(filePath) {
|
|
286185
286196
|
const lowerPath = filePath.toLowerCase();
|
|
@@ -286229,8 +286240,19 @@ var PackageGenerator = class {
|
|
|
286229
286240
|
if (dep === "@playwright/test" || dep === "playwright" || dep === "playwright-core") {
|
|
286230
286241
|
continue;
|
|
286231
286242
|
}
|
|
286232
|
-
|
|
286233
|
-
|
|
286243
|
+
const declaredVersion = allDeps[dep];
|
|
286244
|
+
if (declaredVersion?.startsWith("workspace:")) {
|
|
286245
|
+
const version = this.getVersionFromNodeModules(dep);
|
|
286246
|
+
if (version) {
|
|
286247
|
+
dependencies[dep] = `^${version}`;
|
|
286248
|
+
} else {
|
|
286249
|
+
console.warn(
|
|
286250
|
+
`Warning: Could not resolve workspace dependency ${dep}, using "latest"`
|
|
286251
|
+
);
|
|
286252
|
+
dependencies[dep] = "latest";
|
|
286253
|
+
}
|
|
286254
|
+
} else if (declaredVersion) {
|
|
286255
|
+
dependencies[dep] = declaredVersion;
|
|
286234
286256
|
} else {
|
|
286235
286257
|
const version = this.getVersionFromNodeModules(dep);
|
|
286236
286258
|
if (version) {
|
|
@@ -286277,6 +286299,19 @@ var PlaywrightConfigParser = class {
|
|
|
286277
286299
|
constructor(projectRoot) {
|
|
286278
286300
|
this.projectRoot = projectRoot;
|
|
286279
286301
|
}
|
|
286302
|
+
/**
|
|
286303
|
+
* Detect package manager based on lock files
|
|
286304
|
+
* Returns the command prefix to run playwright (e.g., 'yarn', 'pnpm', 'npx')
|
|
286305
|
+
*/
|
|
286306
|
+
detectPackageManager() {
|
|
286307
|
+
if ((0, import_node_fs3.existsSync)(path4.join(this.projectRoot, "yarn.lock"))) {
|
|
286308
|
+
return "yarn";
|
|
286309
|
+
}
|
|
286310
|
+
if ((0, import_node_fs3.existsSync)(path4.join(this.projectRoot, "pnpm-lock.yaml"))) {
|
|
286311
|
+
return "pnpm";
|
|
286312
|
+
}
|
|
286313
|
+
return "npx";
|
|
286314
|
+
}
|
|
286280
286315
|
async findConfig() {
|
|
286281
286316
|
const candidates = [
|
|
286282
286317
|
"playwright.config.ts",
|
|
@@ -286293,12 +286328,15 @@ var PlaywrightConfigParser = class {
|
|
|
286293
286328
|
return null;
|
|
286294
286329
|
}
|
|
286295
286330
|
/**
|
|
286296
|
-
* Use
|
|
286331
|
+
* Use playwright test --list --reporter=json to discover test files
|
|
286297
286332
|
* This respects all Playwright config settings (testDir, testMatch, projects, etc.)
|
|
286333
|
+
* Detects package manager (yarn/pnpm/npm) to run the correct command
|
|
286334
|
+
* Returns both test files and the detected testDir from Playwright's config
|
|
286298
286335
|
*/
|
|
286299
286336
|
async getTestFilesFromPlaywright(project) {
|
|
286300
286337
|
try {
|
|
286301
|
-
|
|
286338
|
+
const pm = this.detectPackageManager();
|
|
286339
|
+
let command = `${pm} playwright test --list --reporter=json`;
|
|
286302
286340
|
if (project) {
|
|
286303
286341
|
command += ` --project="${project}"`;
|
|
286304
286342
|
}
|
|
@@ -286311,9 +286349,10 @@ var PlaywrightConfigParser = class {
|
|
|
286311
286349
|
const parsed = JSON.parse(output);
|
|
286312
286350
|
const rootDir = parsed.config?.rootDir || this.projectRoot;
|
|
286313
286351
|
const files = this.extractFilesFromSuites(parsed.suites);
|
|
286314
|
-
|
|
286352
|
+
const absoluteFiles = [...new Set(files)].map(
|
|
286315
286353
|
(file) => path4.isAbsolute(file) ? file : path4.join(rootDir, file)
|
|
286316
286354
|
);
|
|
286355
|
+
return { files: absoluteFiles, testDir: rootDir };
|
|
286317
286356
|
} catch (error2) {
|
|
286318
286357
|
console.warn(
|
|
286319
286358
|
"Warning: Could not run playwright test --list, falling back to file scan"
|
|
@@ -286321,9 +286360,35 @@ var PlaywrightConfigParser = class {
|
|
|
286321
286360
|
if (error2 instanceof Error && error2.message) {
|
|
286322
286361
|
console.warn(` ${error2.message.split("\n")[0]}`);
|
|
286323
286362
|
}
|
|
286324
|
-
|
|
286363
|
+
const files = await this.fallbackGetTestFiles();
|
|
286364
|
+
const testDir = this.findCommonParentDir(files);
|
|
286365
|
+
return { files, testDir };
|
|
286325
286366
|
}
|
|
286326
286367
|
}
|
|
286368
|
+
/**
|
|
286369
|
+
* Find the common parent directory of all given file paths
|
|
286370
|
+
* Excludes node_modules paths since those are npm dependencies
|
|
286371
|
+
*/
|
|
286372
|
+
findCommonParentDir(files) {
|
|
286373
|
+
const projectFiles = files.filter((f) => {
|
|
286374
|
+
const rel = path4.relative(this.projectRoot, f);
|
|
286375
|
+
return !rel.startsWith("node_modules");
|
|
286376
|
+
});
|
|
286377
|
+
if (projectFiles.length === 0) return this.projectRoot;
|
|
286378
|
+
if (projectFiles.length === 1) return path4.dirname(projectFiles[0]);
|
|
286379
|
+
const dirs = projectFiles.map((f) => path4.dirname(f));
|
|
286380
|
+
const parts = dirs.map((d) => d.split(path4.sep));
|
|
286381
|
+
const commonParts = [];
|
|
286382
|
+
for (let i = 0; i < parts[0].length; i++) {
|
|
286383
|
+
const part = parts[0][i];
|
|
286384
|
+
if (parts.every((p) => p[i] === part)) {
|
|
286385
|
+
commonParts.push(part);
|
|
286386
|
+
} else {
|
|
286387
|
+
break;
|
|
286388
|
+
}
|
|
286389
|
+
}
|
|
286390
|
+
return commonParts.join(path4.sep) || this.projectRoot;
|
|
286391
|
+
}
|
|
286327
286392
|
/**
|
|
286328
286393
|
* Recursively extract file paths from Playwright's suite structure
|
|
286329
286394
|
*/
|
|
@@ -286348,10 +286413,19 @@ var PlaywrightConfigParser = class {
|
|
|
286348
286413
|
}
|
|
286349
286414
|
/**
|
|
286350
286415
|
* Fallback: scan for test files if playwright --list fails
|
|
286416
|
+
* Only scans e2e-specific directories to avoid picking up unit tests
|
|
286351
286417
|
*/
|
|
286352
286418
|
async fallbackGetTestFiles() {
|
|
286353
|
-
const { readdirSync, statSync } = await import("node:fs");
|
|
286354
|
-
const testDirs = [
|
|
286419
|
+
const { readdirSync, statSync, readFileSync: readFileSync3 } = await import("node:fs");
|
|
286420
|
+
const testDirs = [
|
|
286421
|
+
"e2e",
|
|
286422
|
+
"e2e-playwright",
|
|
286423
|
+
"playwright",
|
|
286424
|
+
"tests/e2e",
|
|
286425
|
+
"test/e2e",
|
|
286426
|
+
"tests",
|
|
286427
|
+
"test"
|
|
286428
|
+
];
|
|
286355
286429
|
const files = [];
|
|
286356
286430
|
const testPatterns = [
|
|
286357
286431
|
/\.spec\.(ts|js|tsx|jsx)$/,
|
|
@@ -286369,7 +286443,9 @@ var PlaywrightConfigParser = class {
|
|
|
286369
286443
|
if (stat.isDirectory()) {
|
|
286370
286444
|
scanDir(fullPath);
|
|
286371
286445
|
} else if (testPatterns.some((p) => p.test(entry))) {
|
|
286372
|
-
|
|
286446
|
+
if (this.isPlaywrightTest(fullPath, readFileSync3)) {
|
|
286447
|
+
files.push(fullPath);
|
|
286448
|
+
}
|
|
286373
286449
|
}
|
|
286374
286450
|
} catch {
|
|
286375
286451
|
}
|
|
@@ -286385,6 +286461,22 @@ var PlaywrightConfigParser = class {
|
|
|
286385
286461
|
}
|
|
286386
286462
|
return [...new Set(files)];
|
|
286387
286463
|
}
|
|
286464
|
+
/**
|
|
286465
|
+
* Check if a file is likely a Playwright test
|
|
286466
|
+
* Either imports from @playwright/test or is in an e2e-specific directory
|
|
286467
|
+
*/
|
|
286468
|
+
isPlaywrightTest(filePath, readFileSync3) {
|
|
286469
|
+
const lowerPath = filePath.toLowerCase();
|
|
286470
|
+
if (lowerPath.includes("/e2e-playwright/") || lowerPath.includes("/e2e/") || lowerPath.includes("/playwright/")) {
|
|
286471
|
+
return true;
|
|
286472
|
+
}
|
|
286473
|
+
try {
|
|
286474
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
286475
|
+
return content.includes("@playwright/test") || content.includes('from "playwright"') || content.includes("from 'playwright'");
|
|
286476
|
+
} catch {
|
|
286477
|
+
return false;
|
|
286478
|
+
}
|
|
286479
|
+
}
|
|
286388
286480
|
};
|
|
286389
286481
|
|
|
286390
286482
|
// src/analyzer/index.ts
|
|
@@ -286398,7 +286490,7 @@ async function analyze(options) {
|
|
|
286398
286490
|
);
|
|
286399
286491
|
}
|
|
286400
286492
|
console.log(`Found config: ${path5.relative(projectRoot, configPath)}`);
|
|
286401
|
-
const testFiles = await configParser.getTestFilesFromPlaywright(options.project);
|
|
286493
|
+
const { files: testFiles, testDir } = await configParser.getTestFilesFromPlaywright(options.project);
|
|
286402
286494
|
console.log(`Found ${testFiles.length} test files via Playwright`);
|
|
286403
286495
|
const entryPoints = [configPath, ...testFiles].filter(
|
|
286404
286496
|
(file, index, self2) => self2.indexOf(file) === index
|
|
@@ -286408,7 +286500,7 @@ async function analyze(options) {
|
|
|
286408
286500
|
console.warn("Warning: No test files found. Check your Playwright config.");
|
|
286409
286501
|
}
|
|
286410
286502
|
const graphBuilder = new DependencyGraphBuilder(options);
|
|
286411
|
-
const graph = await graphBuilder.build(entryPoints);
|
|
286503
|
+
const graph = await graphBuilder.build(entryPoints, testDir);
|
|
286412
286504
|
console.log(`Analyzed ${graph.nodes.size} source files`);
|
|
286413
286505
|
console.log(`Found ${graph.nodeModuleDeps.size} npm dependencies`);
|
|
286414
286506
|
console.log(`Found ${graph.assets.size} assets`);
|
|
@@ -286443,16 +286535,70 @@ var import_archiver = __toESM(require_archiver());
|
|
|
286443
286535
|
var import_fs = require("fs");
|
|
286444
286536
|
var import_path = require("path");
|
|
286445
286537
|
var import_stream = require("stream");
|
|
286446
|
-
async function zipFilesToBuffer(projectRoot, files, packageJson) {
|
|
286538
|
+
async function zipFilesToBuffer(projectRoot, files, packageJson, npmDeps) {
|
|
286447
286539
|
const passthrough = new import_stream.PassThrough();
|
|
286448
286540
|
const archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } });
|
|
286541
|
+
const includedPackages = /* @__PURE__ */ new Set();
|
|
286542
|
+
const skippedPackages = /* @__PURE__ */ new Set();
|
|
286543
|
+
const workspacePackages = /* @__PURE__ */ new Set();
|
|
286544
|
+
const warnings = [];
|
|
286449
286545
|
for (const file of files) {
|
|
286450
286546
|
const filePath = (0, import_path.join)(projectRoot, file);
|
|
286451
286547
|
if ((0, import_fs.existsSync)(filePath)) {
|
|
286452
286548
|
archive.file(filePath, { name: file });
|
|
286453
286549
|
}
|
|
286454
286550
|
}
|
|
286455
|
-
archive.append(JSON.stringify(packageJson, null, 2), {
|
|
286551
|
+
archive.append(JSON.stringify(packageJson, null, 2), {
|
|
286552
|
+
name: "package.json"
|
|
286553
|
+
});
|
|
286554
|
+
const skipPackages = /* @__PURE__ */ new Set([
|
|
286555
|
+
// Playwright - pre-installed on runner
|
|
286556
|
+
"@playwright/test",
|
|
286557
|
+
"playwright",
|
|
286558
|
+
"playwright-core",
|
|
286559
|
+
// Frameworks - not needed for remote test execution (app already running)
|
|
286560
|
+
"next",
|
|
286561
|
+
"nuxt",
|
|
286562
|
+
"gatsby",
|
|
286563
|
+
"vite",
|
|
286564
|
+
"webpack",
|
|
286565
|
+
"turbopack",
|
|
286566
|
+
// Dev tools - not needed at runtime
|
|
286567
|
+
"eslint",
|
|
286568
|
+
"prettier",
|
|
286569
|
+
"typescript",
|
|
286570
|
+
"ts-node",
|
|
286571
|
+
"tsx",
|
|
286572
|
+
"esbuild",
|
|
286573
|
+
"rollup",
|
|
286574
|
+
"parcel",
|
|
286575
|
+
// Test runners (we use Playwright)
|
|
286576
|
+
"jest",
|
|
286577
|
+
"vitest",
|
|
286578
|
+
"mocha",
|
|
286579
|
+
"jasmine"
|
|
286580
|
+
]);
|
|
286581
|
+
if (npmDeps && npmDeps.size > 0) {
|
|
286582
|
+
const nodeModulesPath = (0, import_path.join)(projectRoot, "node_modules");
|
|
286583
|
+
if ((0, import_fs.existsSync)(nodeModulesPath)) {
|
|
286584
|
+
for (const dep of npmDeps) {
|
|
286585
|
+
if (skipPackages.has(dep)) {
|
|
286586
|
+
skippedPackages.add(dep);
|
|
286587
|
+
continue;
|
|
286588
|
+
}
|
|
286589
|
+
await addPackageWithDeps(
|
|
286590
|
+
archive,
|
|
286591
|
+
nodeModulesPath,
|
|
286592
|
+
dep,
|
|
286593
|
+
includedPackages,
|
|
286594
|
+
skipPackages,
|
|
286595
|
+
skippedPackages,
|
|
286596
|
+
warnings,
|
|
286597
|
+
workspacePackages
|
|
286598
|
+
);
|
|
286599
|
+
}
|
|
286600
|
+
}
|
|
286601
|
+
}
|
|
286456
286602
|
archive.finalize();
|
|
286457
286603
|
archive.pipe(passthrough);
|
|
286458
286604
|
const chunks = [];
|
|
@@ -286466,7 +286612,451 @@ async function zipFilesToBuffer(projectRoot, files, packageJson) {
|
|
|
286466
286612
|
}
|
|
286467
286613
|
writeStream.end();
|
|
286468
286614
|
console.log(`Created test bundle at ${tmpZipPath}`);
|
|
286469
|
-
return
|
|
286615
|
+
return {
|
|
286616
|
+
buffer: Buffer.concat(chunks),
|
|
286617
|
+
includedPackages,
|
|
286618
|
+
skippedPackages,
|
|
286619
|
+
workspacePackages,
|
|
286620
|
+
warnings
|
|
286621
|
+
};
|
|
286622
|
+
}
|
|
286623
|
+
function isWorkspacePackage(packagePath, packageName) {
|
|
286624
|
+
try {
|
|
286625
|
+
const { lstatSync, readFileSync: readFileSync3 } = require("fs");
|
|
286626
|
+
const stats = lstatSync(packagePath);
|
|
286627
|
+
if (stats.isSymbolicLink()) {
|
|
286628
|
+
return true;
|
|
286629
|
+
}
|
|
286630
|
+
const pkgJsonPath = (0, import_path.join)(packagePath, "package.json");
|
|
286631
|
+
if ((0, import_fs.existsSync)(pkgJsonPath)) {
|
|
286632
|
+
const pkgJson = JSON.parse(readFileSync3(pkgJsonPath, "utf-8"));
|
|
286633
|
+
const version = pkgJson.version || "";
|
|
286634
|
+
if (version === "0.0.0" || version === "^0.0.0" || version.startsWith("0.0.")) {
|
|
286635
|
+
return true;
|
|
286636
|
+
}
|
|
286637
|
+
const main = pkgJson.main || "";
|
|
286638
|
+
if (main.startsWith("src/") && main.endsWith(".ts")) {
|
|
286639
|
+
return true;
|
|
286640
|
+
}
|
|
286641
|
+
if (pkgJson.private === true && !pkgJson.publishConfig) {
|
|
286642
|
+
return true;
|
|
286643
|
+
}
|
|
286644
|
+
}
|
|
286645
|
+
if (packageName.startsWith("@") && packageName.includes("/")) {
|
|
286646
|
+
const scope = packageName.split("/")[0];
|
|
286647
|
+
const nodeModulesPath = (0, import_path.join)(packagePath, "..");
|
|
286648
|
+
const scopePath = (0, import_path.join)(nodeModulesPath, scope);
|
|
286649
|
+
if ((0, import_fs.existsSync)(scopePath)) {
|
|
286650
|
+
try {
|
|
286651
|
+
const { readdirSync } = require("fs");
|
|
286652
|
+
const scopePackages = readdirSync(scopePath);
|
|
286653
|
+
if (scopePackages.length > 5) {
|
|
286654
|
+
const symlinkCount = scopePackages.filter((pkg) => {
|
|
286655
|
+
try {
|
|
286656
|
+
return lstatSync((0, import_path.join)(scopePath, pkg)).isSymbolicLink();
|
|
286657
|
+
} catch {
|
|
286658
|
+
return false;
|
|
286659
|
+
}
|
|
286660
|
+
}).length;
|
|
286661
|
+
if (symlinkCount > 3) {
|
|
286662
|
+
return true;
|
|
286663
|
+
}
|
|
286664
|
+
}
|
|
286665
|
+
} catch {
|
|
286666
|
+
}
|
|
286667
|
+
}
|
|
286668
|
+
}
|
|
286669
|
+
return false;
|
|
286670
|
+
} catch {
|
|
286671
|
+
return false;
|
|
286672
|
+
}
|
|
286673
|
+
}
|
|
286674
|
+
function checkUnbuiltPackage(packagePath, packageName) {
|
|
286675
|
+
const pkgJsonPath = (0, import_path.join)(packagePath, "package.json");
|
|
286676
|
+
if (!(0, import_fs.existsSync)(pkgJsonPath)) {
|
|
286677
|
+
return null;
|
|
286678
|
+
}
|
|
286679
|
+
try {
|
|
286680
|
+
const { readFileSync: readFileSync3, lstatSync } = require("fs");
|
|
286681
|
+
const pkgJson = JSON.parse(readFileSync3(pkgJsonPath, "utf-8"));
|
|
286682
|
+
const main = pkgJson.main || "";
|
|
286683
|
+
const isSourceMain = main.startsWith("src/") && main.endsWith(".ts");
|
|
286684
|
+
if (!isSourceMain) {
|
|
286685
|
+
return null;
|
|
286686
|
+
}
|
|
286687
|
+
const stats = lstatSync(packagePath);
|
|
286688
|
+
const isSymlink = stats.isSymbolicLink();
|
|
286689
|
+
const distPath = (0, import_path.join)(packagePath, "dist");
|
|
286690
|
+
const hasDistFolder = (0, import_fs.existsSync)(distPath);
|
|
286691
|
+
if (isSourceMain && !hasDistFolder) {
|
|
286692
|
+
const symlinkNote = isSymlink ? " (symlinked monorepo package)" : "";
|
|
286693
|
+
return `Package "${packageName}" has main="${main}" but no dist/ folder${symlinkNote}. This package needs to be built before bundling, or install the published version from npm.`;
|
|
286694
|
+
}
|
|
286695
|
+
} catch {
|
|
286696
|
+
}
|
|
286697
|
+
return null;
|
|
286698
|
+
}
|
|
286699
|
+
async function addWorkspacePackageFiltered(archive, packagePath, packageName) {
|
|
286700
|
+
const { readdirSync, statSync, lstatSync, realpathSync } = require("fs");
|
|
286701
|
+
const excludeDirs = /* @__PURE__ */ new Set([
|
|
286702
|
+
"node_modules",
|
|
286703
|
+
"src",
|
|
286704
|
+
"test",
|
|
286705
|
+
"tests",
|
|
286706
|
+
"__tests__",
|
|
286707
|
+
"__mocks__",
|
|
286708
|
+
"coverage",
|
|
286709
|
+
".git",
|
|
286710
|
+
".turbo",
|
|
286711
|
+
".next",
|
|
286712
|
+
"playwright",
|
|
286713
|
+
"e2e",
|
|
286714
|
+
"cypress"
|
|
286715
|
+
]);
|
|
286716
|
+
const excludePatterns = [
|
|
286717
|
+
/\.test\.(ts|js|tsx|jsx)$/,
|
|
286718
|
+
/\.spec\.(ts|js|tsx|jsx)$/,
|
|
286719
|
+
/\.stories\.(ts|js|tsx|jsx)$/,
|
|
286720
|
+
/^tsconfig.*\.json$/,
|
|
286721
|
+
/^jest\.config/,
|
|
286722
|
+
/^vitest\.config/,
|
|
286723
|
+
/^\.eslint/,
|
|
286724
|
+
/^\.prettier/
|
|
286725
|
+
];
|
|
286726
|
+
let realPath = packagePath;
|
|
286727
|
+
try {
|
|
286728
|
+
const stats = lstatSync(packagePath);
|
|
286729
|
+
if (stats.isSymbolicLink()) {
|
|
286730
|
+
realPath = realpathSync(packagePath);
|
|
286731
|
+
}
|
|
286732
|
+
} catch {
|
|
286733
|
+
}
|
|
286734
|
+
const addFilesRecursively = (dir, relativeTo, archivePath) => {
|
|
286735
|
+
try {
|
|
286736
|
+
const entries = readdirSync(dir);
|
|
286737
|
+
for (const entry of entries) {
|
|
286738
|
+
const fullPath = (0, import_path.join)(dir, entry);
|
|
286739
|
+
const relPath = (0, import_path.join)(archivePath, entry);
|
|
286740
|
+
if (excludeDirs.has(entry)) continue;
|
|
286741
|
+
if (excludePatterns.some((p) => p.test(entry))) continue;
|
|
286742
|
+
try {
|
|
286743
|
+
const stat = statSync(fullPath);
|
|
286744
|
+
if (stat.isDirectory()) {
|
|
286745
|
+
addFilesRecursively(fullPath, relativeTo, relPath);
|
|
286746
|
+
} else {
|
|
286747
|
+
archive.file(fullPath, { name: relPath });
|
|
286748
|
+
}
|
|
286749
|
+
} catch {
|
|
286750
|
+
}
|
|
286751
|
+
}
|
|
286752
|
+
} catch {
|
|
286753
|
+
}
|
|
286754
|
+
};
|
|
286755
|
+
addFilesRecursively(realPath, realPath, `node_modules/${packageName}`);
|
|
286756
|
+
}
|
|
286757
|
+
async function addPackageFiltered(archive, packagePath, packageName) {
|
|
286758
|
+
const { readdirSync, statSync } = require("fs");
|
|
286759
|
+
const includeExtensions = /* @__PURE__ */ new Set([
|
|
286760
|
+
".js",
|
|
286761
|
+
".cjs",
|
|
286762
|
+
".mjs",
|
|
286763
|
+
".json",
|
|
286764
|
+
".node",
|
|
286765
|
+
".wasm"
|
|
286766
|
+
]);
|
|
286767
|
+
const skipDirs = /* @__PURE__ */ new Set([
|
|
286768
|
+
"node_modules",
|
|
286769
|
+
"test",
|
|
286770
|
+
"tests",
|
|
286771
|
+
"__tests__",
|
|
286772
|
+
"__mocks__",
|
|
286773
|
+
"src",
|
|
286774
|
+
"source",
|
|
286775
|
+
"docs",
|
|
286776
|
+
"doc",
|
|
286777
|
+
"documentation",
|
|
286778
|
+
"example",
|
|
286779
|
+
"examples",
|
|
286780
|
+
"benchmark",
|
|
286781
|
+
"benchmarks",
|
|
286782
|
+
".git",
|
|
286783
|
+
".github",
|
|
286784
|
+
".vscode",
|
|
286785
|
+
"coverage",
|
|
286786
|
+
".nyc_output",
|
|
286787
|
+
"android",
|
|
286788
|
+
"ios"
|
|
286789
|
+
// Native mobile dirs
|
|
286790
|
+
]);
|
|
286791
|
+
const skipPatterns = [
|
|
286792
|
+
/\.d\.ts$/,
|
|
286793
|
+
/\.d\.mts$/,
|
|
286794
|
+
/\.d\.cts$/,
|
|
286795
|
+
// Type definitions
|
|
286796
|
+
/\.map$/,
|
|
286797
|
+
/\.min\.js\.map$/,
|
|
286798
|
+
// Source maps
|
|
286799
|
+
/\.ts$/,
|
|
286800
|
+
/\.tsx$/,
|
|
286801
|
+
/\.mts$/,
|
|
286802
|
+
/\.cts$/,
|
|
286803
|
+
// TypeScript source
|
|
286804
|
+
/\.md$/,
|
|
286805
|
+
/\.txt$/,
|
|
286806
|
+
/\.rst$/,
|
|
286807
|
+
// Documentation
|
|
286808
|
+
/^LICENSE/,
|
|
286809
|
+
/^LICENCE/,
|
|
286810
|
+
/^README/,
|
|
286811
|
+
/^CHANGELOG/,
|
|
286812
|
+
/^HISTORY/,
|
|
286813
|
+
/^\.eslint/,
|
|
286814
|
+
/^\.prettier/,
|
|
286815
|
+
/^tsconfig/,
|
|
286816
|
+
/^jest\.config/,
|
|
286817
|
+
/^vitest\.config/,
|
|
286818
|
+
/\.test\.js$/,
|
|
286819
|
+
/\.spec\.js$/,
|
|
286820
|
+
/\.test\.cjs$/,
|
|
286821
|
+
/\.spec\.cjs$/,
|
|
286822
|
+
/^Makefile$/,
|
|
286823
|
+
/^Gruntfile/,
|
|
286824
|
+
/^Gulpfile/
|
|
286825
|
+
];
|
|
286826
|
+
const addFilesRecursively = (dir, archivePath) => {
|
|
286827
|
+
try {
|
|
286828
|
+
const entries = readdirSync(dir);
|
|
286829
|
+
for (const entry of entries) {
|
|
286830
|
+
if (entry.startsWith(".") && entry !== ".bin") continue;
|
|
286831
|
+
if (skipDirs.has(entry)) continue;
|
|
286832
|
+
if (skipPatterns.some((p) => p.test(entry))) continue;
|
|
286833
|
+
const fullPath = (0, import_path.join)(dir, entry);
|
|
286834
|
+
const relPath = (0, import_path.join)(archivePath, entry);
|
|
286835
|
+
try {
|
|
286836
|
+
const stat = statSync(fullPath);
|
|
286837
|
+
if (stat.isDirectory()) {
|
|
286838
|
+
addFilesRecursively(fullPath, relPath);
|
|
286839
|
+
} else {
|
|
286840
|
+
const ext = entry.substring(entry.lastIndexOf("."));
|
|
286841
|
+
if (includeExtensions.has(ext) || entry === "package.json") {
|
|
286842
|
+
archive.file(fullPath, { name: relPath });
|
|
286843
|
+
}
|
|
286844
|
+
}
|
|
286845
|
+
} catch {
|
|
286846
|
+
}
|
|
286847
|
+
}
|
|
286848
|
+
} catch {
|
|
286849
|
+
}
|
|
286850
|
+
};
|
|
286851
|
+
addFilesRecursively(packagePath, `node_modules/${packageName}`);
|
|
286852
|
+
}
|
|
286853
|
+
async function addPackageWithDeps(archive, nodeModulesPath, packageName, includedPackages, skipPackages, skippedPackages, warnings, workspacePackages) {
|
|
286854
|
+
if (skipPackages.has(packageName)) {
|
|
286855
|
+
skippedPackages.add(packageName);
|
|
286856
|
+
return;
|
|
286857
|
+
}
|
|
286858
|
+
if (includedPackages.has(packageName)) {
|
|
286859
|
+
return;
|
|
286860
|
+
}
|
|
286861
|
+
const packagePath = (0, import_path.join)(nodeModulesPath, packageName);
|
|
286862
|
+
if (!(0, import_fs.existsSync)(packagePath)) {
|
|
286863
|
+
return;
|
|
286864
|
+
}
|
|
286865
|
+
const isWorkspace = isWorkspacePackage(packagePath, packageName);
|
|
286866
|
+
if (isWorkspace) {
|
|
286867
|
+
workspacePackages.add(packageName);
|
|
286868
|
+
}
|
|
286869
|
+
const unbuiltWarning = checkUnbuiltPackage(packagePath, packageName);
|
|
286870
|
+
if (unbuiltWarning) {
|
|
286871
|
+
warnings.push(unbuiltWarning);
|
|
286872
|
+
}
|
|
286873
|
+
includedPackages.add(packageName);
|
|
286874
|
+
if (isWorkspace) {
|
|
286875
|
+
await addWorkspacePackageFiltered(archive, packagePath, packageName);
|
|
286876
|
+
} else {
|
|
286877
|
+
archive.directory(packagePath, `node_modules/${packageName}`);
|
|
286878
|
+
}
|
|
286879
|
+
if (isWorkspace) {
|
|
286880
|
+
return;
|
|
286881
|
+
}
|
|
286882
|
+
const pkgJsonPath = (0, import_path.join)(packagePath, "package.json");
|
|
286883
|
+
if ((0, import_fs.existsSync)(pkgJsonPath)) {
|
|
286884
|
+
try {
|
|
286885
|
+
const { readFileSync: readFileSync3 } = await import("fs");
|
|
286886
|
+
const pkgJson = JSON.parse(readFileSync3(pkgJsonPath, "utf-8"));
|
|
286887
|
+
const deps = pkgJson.dependencies || {};
|
|
286888
|
+
for (const dep of Object.keys(deps)) {
|
|
286889
|
+
await addPackageWithDeps(archive, nodeModulesPath, dep, includedPackages, skipPackages, skippedPackages, warnings, workspacePackages);
|
|
286890
|
+
}
|
|
286891
|
+
} catch {
|
|
286892
|
+
}
|
|
286893
|
+
}
|
|
286894
|
+
}
|
|
286895
|
+
async function zipWithEsbuild(projectRoot, files, packageJson, _npmDeps) {
|
|
286896
|
+
const esbuild = await import("esbuild");
|
|
286897
|
+
const os2 = await import("os");
|
|
286898
|
+
const result = {
|
|
286899
|
+
buffer: Buffer.alloc(0),
|
|
286900
|
+
bundledFiles: 0,
|
|
286901
|
+
originalFiles: files.length,
|
|
286902
|
+
errors: [],
|
|
286903
|
+
warnings: []
|
|
286904
|
+
};
|
|
286905
|
+
const tmpDir = (0, import_path.join)(os2.tmpdir(), `browsermation-esbuild-${Date.now()}`);
|
|
286906
|
+
(0, import_fs.mkdirSync)(tmpDir, { recursive: true });
|
|
286907
|
+
try {
|
|
286908
|
+
const tsFiles = files.filter((f) => /\.tsx?$/.test(f) && !/\.d\.ts$/.test(f));
|
|
286909
|
+
const jsFiles = files.filter((f) => /\.(js|jsx|mjs)$/.test(f));
|
|
286910
|
+
const otherFiles = files.filter((f) => !/\.(ts|tsx|js|jsx|mjs)$/.test(f) || /\.d\.ts$/.test(f));
|
|
286911
|
+
const testFiles = tsFiles.filter(
|
|
286912
|
+
(f) => /\.(spec|test|e2e)\.(ts|tsx|js|jsx)$/.test(f)
|
|
286913
|
+
);
|
|
286914
|
+
const testEntryPoints = testFiles.map((f) => (0, import_path.join)(projectRoot, f));
|
|
286915
|
+
const allEntryPoints = tsFiles.map((f) => (0, import_path.join)(projectRoot, f));
|
|
286916
|
+
const preInstalled = ["@playwright/test", "playwright", "playwright-core"];
|
|
286917
|
+
console.log(`Analyzing dependencies from ${testFiles.length} test files...`);
|
|
286918
|
+
const actualDeps = /* @__PURE__ */ new Set();
|
|
286919
|
+
if (testEntryPoints.length > 0) {
|
|
286920
|
+
try {
|
|
286921
|
+
await esbuild.build({
|
|
286922
|
+
entryPoints: testEntryPoints,
|
|
286923
|
+
bundle: true,
|
|
286924
|
+
write: false,
|
|
286925
|
+
outdir: tmpDir,
|
|
286926
|
+
outbase: projectRoot,
|
|
286927
|
+
platform: "node",
|
|
286928
|
+
target: "node18",
|
|
286929
|
+
format: "cjs",
|
|
286930
|
+
metafile: true,
|
|
286931
|
+
logLevel: "silent",
|
|
286932
|
+
external: preInstalled,
|
|
286933
|
+
// Mark all npm packages as external and collect them
|
|
286934
|
+
plugins: [{
|
|
286935
|
+
name: "collect-deps",
|
|
286936
|
+
setup(build) {
|
|
286937
|
+
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
|
286938
|
+
if (args.path.startsWith("node:")) return null;
|
|
286939
|
+
const parts = args.path.split("/");
|
|
286940
|
+
const pkgName = args.path.startsWith("@") ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
286941
|
+
if (!preInstalled.includes(pkgName)) {
|
|
286942
|
+
actualDeps.add(pkgName);
|
|
286943
|
+
}
|
|
286944
|
+
return { path: args.path, external: true };
|
|
286945
|
+
});
|
|
286946
|
+
}
|
|
286947
|
+
}]
|
|
286948
|
+
});
|
|
286949
|
+
} catch (e) {
|
|
286950
|
+
if (e instanceof Error) {
|
|
286951
|
+
result.warnings.push(`esbuild analysis failed, using fallback: ${e.message.slice(0, 80)}`);
|
|
286952
|
+
}
|
|
286953
|
+
const { readFileSync: readFileSync3 } = require("fs");
|
|
286954
|
+
const importRegex = /(?:import|require)\s*\(?['"]([^'"./][^'"]*)['"]/g;
|
|
286955
|
+
for (const file of testEntryPoints) {
|
|
286956
|
+
try {
|
|
286957
|
+
const content = readFileSync3(file, "utf-8");
|
|
286958
|
+
for (const match of content.matchAll(importRegex)) {
|
|
286959
|
+
const parts = match[1].split("/");
|
|
286960
|
+
const pkgName = match[1].startsWith("@") ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
286961
|
+
if (!preInstalled.includes(pkgName) && !pkgName.startsWith("node:")) {
|
|
286962
|
+
actualDeps.add(pkgName);
|
|
286963
|
+
}
|
|
286964
|
+
}
|
|
286965
|
+
} catch {
|
|
286966
|
+
}
|
|
286967
|
+
}
|
|
286968
|
+
}
|
|
286969
|
+
}
|
|
286970
|
+
console.log(`Found ${actualDeps.size} npm dependencies used by tests`);
|
|
286971
|
+
console.log(`Transpiling ${tsFiles.length} TypeScript files...`);
|
|
286972
|
+
if (allEntryPoints.length > 0) {
|
|
286973
|
+
const buildResult = await esbuild.build({
|
|
286974
|
+
entryPoints: allEntryPoints,
|
|
286975
|
+
bundle: false,
|
|
286976
|
+
// Just transpile
|
|
286977
|
+
platform: "node",
|
|
286978
|
+
target: "node18",
|
|
286979
|
+
format: "cjs",
|
|
286980
|
+
outdir: tmpDir,
|
|
286981
|
+
outbase: projectRoot,
|
|
286982
|
+
sourcemap: false,
|
|
286983
|
+
logLevel: "warning"
|
|
286984
|
+
});
|
|
286985
|
+
for (const warning2 of buildResult.warnings) {
|
|
286986
|
+
result.warnings.push(warning2.text);
|
|
286987
|
+
}
|
|
286988
|
+
for (const error2 of buildResult.errors) {
|
|
286989
|
+
result.errors.push(error2.text);
|
|
286990
|
+
}
|
|
286991
|
+
}
|
|
286992
|
+
result.bundledFiles = tsFiles.length;
|
|
286993
|
+
const passthrough = new import_stream.PassThrough();
|
|
286994
|
+
const archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } });
|
|
286995
|
+
for (const file of tsFiles) {
|
|
286996
|
+
const jsFile = file.replace(/\.tsx?$/, ".js");
|
|
286997
|
+
const transpiledPath = (0, import_path.join)(tmpDir, jsFile);
|
|
286998
|
+
if ((0, import_fs.existsSync)(transpiledPath)) {
|
|
286999
|
+
archive.file(transpiledPath, { name: jsFile });
|
|
287000
|
+
}
|
|
287001
|
+
}
|
|
287002
|
+
for (const file of jsFiles) {
|
|
287003
|
+
const filePath = (0, import_path.join)(projectRoot, file);
|
|
287004
|
+
if ((0, import_fs.existsSync)(filePath)) {
|
|
287005
|
+
archive.file(filePath, { name: file });
|
|
287006
|
+
}
|
|
287007
|
+
}
|
|
287008
|
+
for (const file of otherFiles) {
|
|
287009
|
+
const filePath = (0, import_path.join)(projectRoot, file);
|
|
287010
|
+
if ((0, import_fs.existsSync)(filePath)) {
|
|
287011
|
+
archive.file(filePath, { name: file });
|
|
287012
|
+
}
|
|
287013
|
+
}
|
|
287014
|
+
const nodeModulesPath = (0, import_path.join)(projectRoot, "node_modules");
|
|
287015
|
+
const includedPackages = /* @__PURE__ */ new Set();
|
|
287016
|
+
const skippedWorkspacePackages = /* @__PURE__ */ new Set();
|
|
287017
|
+
const depsToInclude = [...actualDeps].filter((d) => !d.startsWith("@types/"));
|
|
287018
|
+
for (const dep of depsToInclude) {
|
|
287019
|
+
const packagePath = (0, import_path.join)(nodeModulesPath, dep);
|
|
287020
|
+
if (!(0, import_fs.existsSync)(packagePath)) continue;
|
|
287021
|
+
if (isWorkspacePackage(packagePath, dep)) {
|
|
287022
|
+
skippedWorkspacePackages.add(dep);
|
|
287023
|
+
} else {
|
|
287024
|
+
includedPackages.add(dep);
|
|
287025
|
+
await addPackageFiltered(archive, packagePath, dep);
|
|
287026
|
+
}
|
|
287027
|
+
}
|
|
287028
|
+
console.log(`Including ${includedPackages.size} npm packages (skipped ${skippedWorkspacePackages.size} workspace packages)`);
|
|
287029
|
+
if (skippedWorkspacePackages.size > 0) {
|
|
287030
|
+
console.log(` Workspace packages (resolved from source): ${[...skippedWorkspacePackages].join(", ")}`);
|
|
287031
|
+
}
|
|
287032
|
+
const minimalPackageJson = {
|
|
287033
|
+
name: packageJson.name,
|
|
287034
|
+
version: packageJson.version,
|
|
287035
|
+
dependencies: Object.fromEntries(
|
|
287036
|
+
[...includedPackages].filter((pkg) => packageJson.dependencies[pkg]).map((pkg) => [pkg, packageJson.dependencies[pkg]])
|
|
287037
|
+
)
|
|
287038
|
+
};
|
|
287039
|
+
archive.append(JSON.stringify(minimalPackageJson, null, 2), { name: "package.json" });
|
|
287040
|
+
archive.finalize();
|
|
287041
|
+
archive.pipe(passthrough);
|
|
287042
|
+
const chunks = [];
|
|
287043
|
+
for await (const chunk of passthrough) {
|
|
287044
|
+
chunks.push(chunk);
|
|
287045
|
+
}
|
|
287046
|
+
result.buffer = Buffer.concat(chunks);
|
|
287047
|
+
} catch (error2) {
|
|
287048
|
+
if (error2 instanceof Error) {
|
|
287049
|
+
result.errors.push(error2.message);
|
|
287050
|
+
} else {
|
|
287051
|
+
result.errors.push(String(error2));
|
|
287052
|
+
}
|
|
287053
|
+
} finally {
|
|
287054
|
+
try {
|
|
287055
|
+
(0, import_fs.rmSync)(tmpDir, { recursive: true, force: true });
|
|
287056
|
+
} catch {
|
|
287057
|
+
}
|
|
287058
|
+
}
|
|
287059
|
+
return result;
|
|
286470
287060
|
}
|
|
286471
287061
|
|
|
286472
287062
|
// node_modules/axios/lib/helpers/bind.js
|
|
@@ -290285,79 +290875,120 @@ async function upload(zipBuffer, shardNumber, totalShards, playwrightConfig, opt
|
|
|
290285
290875
|
|
|
290286
290876
|
// src/tunnel.ts
|
|
290287
290877
|
var import_node_child_process2 = require("node:child_process");
|
|
290288
|
-
function startTunnel(
|
|
290289
|
-
|
|
290290
|
-
|
|
290291
|
-
|
|
290292
|
-
|
|
290293
|
-
|
|
290294
|
-
|
|
290295
|
-
|
|
290296
|
-
|
|
290297
|
-
|
|
290298
|
-
|
|
290299
|
-
console.error(
|
|
290300
|
-
source_default.red.bold(
|
|
290301
|
-
"\u274C Error: Please provide a port to expose via the tunnel using the --port option."
|
|
290302
|
-
)
|
|
290303
|
-
);
|
|
290304
|
-
process.exit(1);
|
|
290305
|
-
}
|
|
290306
|
-
const defaultDomain = "browsermationtunnel.com";
|
|
290307
|
-
const args = [
|
|
290308
|
-
"-o",
|
|
290309
|
-
"StrictHostKeyChecking=no",
|
|
290310
|
-
"-o",
|
|
290311
|
-
"UserKnownHostsFile=/dev/null",
|
|
290312
|
-
"-R",
|
|
290313
|
-
`:80:localhost:${options.port}`,
|
|
290314
|
-
`v0@${defaultDomain}`,
|
|
290315
|
-
"-p",
|
|
290316
|
-
"2200",
|
|
290317
|
-
"http",
|
|
290318
|
-
"--user",
|
|
290319
|
-
token
|
|
290320
|
-
];
|
|
290321
|
-
if (options.host) {
|
|
290322
|
-
args.push("--host-header-rewrite", options.host);
|
|
290323
|
-
}
|
|
290324
|
-
tunnelProcess = (0, import_node_child_process2.spawn)("ssh", args);
|
|
290325
|
-
process.on("SIGINT", function() {
|
|
290326
|
-
console.log("\nGracefully shutting down from SIGINT (Ctrl+C)");
|
|
290327
|
-
if (tunnelProcess) {
|
|
290328
|
-
console.log("Killing proxy process...");
|
|
290329
|
-
tunnelProcess.kill();
|
|
290330
|
-
}
|
|
290331
|
-
process.exit();
|
|
290332
|
-
});
|
|
290333
|
-
tunnelProcess?.stdout?.on("data", (data) => {
|
|
290334
|
-
if (process.env.BM_DEBUG) {
|
|
290335
|
-
console.log(`stdout: ${data}`);
|
|
290336
|
-
}
|
|
290337
|
-
if (data.toString().includes("RemoteAddress:")) {
|
|
290338
|
-
const domain = data.toString().split("\n").map((line) => line.trim()).find((line) => line.startsWith("RemoteAddress:")).replace("RemoteAddress: ", "");
|
|
290339
|
-
if (domain) {
|
|
290340
|
-
console.log(
|
|
290341
|
-
source_default.green.bold(
|
|
290342
|
-
`\u2705 Tunnel is running! Access your application at: https://${domain}`
|
|
290343
|
-
)
|
|
290344
|
-
);
|
|
290878
|
+
function startTunnel(_tunnelProcess, options) {
|
|
290879
|
+
return new Promise((resolve3, reject) => {
|
|
290880
|
+
const token = getToken();
|
|
290881
|
+
if (!token) {
|
|
290882
|
+
const errorMsg = "Not authenticated. Run 'browsermation login' or set BM_API_TOKEN environment variable.";
|
|
290883
|
+
if (options.onError) {
|
|
290884
|
+
options.onError(errorMsg);
|
|
290885
|
+
}
|
|
290886
|
+
if (options.exitOnError !== false) {
|
|
290887
|
+
console.error(source_default.red.bold(`\u274C Error: ${errorMsg}`));
|
|
290888
|
+
process.exit(1);
|
|
290345
290889
|
}
|
|
290890
|
+
reject(new Error(errorMsg));
|
|
290891
|
+
return;
|
|
290346
290892
|
}
|
|
290347
|
-
|
|
290348
|
-
|
|
290349
|
-
|
|
290893
|
+
if (!options?.port) {
|
|
290894
|
+
const errorMsg = "Please provide a port to expose via the tunnel using the --port option.";
|
|
290895
|
+
if (options.onError) {
|
|
290896
|
+
options.onError(errorMsg);
|
|
290897
|
+
}
|
|
290898
|
+
if (options.exitOnError !== false) {
|
|
290899
|
+
console.error(source_default.red.bold(`\u274C Error: ${errorMsg}`));
|
|
290900
|
+
process.exit(1);
|
|
290901
|
+
}
|
|
290902
|
+
reject(new Error(errorMsg));
|
|
290350
290903
|
return;
|
|
290351
290904
|
}
|
|
290352
|
-
|
|
290353
|
-
|
|
290354
|
-
|
|
290355
|
-
|
|
290356
|
-
|
|
290357
|
-
|
|
290358
|
-
|
|
290905
|
+
const defaultDomain = "browsermationtunnel.com";
|
|
290906
|
+
const args = [
|
|
290907
|
+
"-o",
|
|
290908
|
+
"StrictHostKeyChecking=no",
|
|
290909
|
+
"-o",
|
|
290910
|
+
"UserKnownHostsFile=/dev/null",
|
|
290911
|
+
"-R",
|
|
290912
|
+
`:80:localhost:${options.port}`,
|
|
290913
|
+
`v0@${defaultDomain}`,
|
|
290914
|
+
"-p",
|
|
290915
|
+
"2200",
|
|
290916
|
+
"http",
|
|
290917
|
+
"--user",
|
|
290918
|
+
token
|
|
290919
|
+
];
|
|
290920
|
+
if (options.host) {
|
|
290921
|
+
args.push("--host-header-rewrite", options.host);
|
|
290359
290922
|
}
|
|
290360
|
-
|
|
290923
|
+
const tunnelProcess = (0, import_node_child_process2.spawn)("ssh", args);
|
|
290924
|
+
process.on("SIGINT", function() {
|
|
290925
|
+
console.log("\nGracefully shutting down from SIGINT (Ctrl+C)");
|
|
290926
|
+
if (tunnelProcess) {
|
|
290927
|
+
console.log("Killing proxy process...");
|
|
290928
|
+
tunnelProcess.kill();
|
|
290929
|
+
}
|
|
290930
|
+
process.exit();
|
|
290931
|
+
});
|
|
290932
|
+
tunnelProcess?.stdout?.on("data", async (data) => {
|
|
290933
|
+
if (process.env.BM_DEBUG) {
|
|
290934
|
+
console.log(`stdout: ${data}`);
|
|
290935
|
+
}
|
|
290936
|
+
if (data.toString().includes("RemoteAddress:")) {
|
|
290937
|
+
const domain = data.toString().split("\n").map((line) => line.trim()).find((line) => line.startsWith("RemoteAddress:"))?.replace("RemoteAddress: ", "");
|
|
290938
|
+
if (domain) {
|
|
290939
|
+
const tunnelUrl = `https://${domain}`;
|
|
290940
|
+
if (options.onStart) {
|
|
290941
|
+
await options.onStart(tunnelUrl);
|
|
290942
|
+
}
|
|
290943
|
+
if (process.env.BM_DEBUG) {
|
|
290944
|
+
console.log(`Tunnel ready: ${tunnelUrl}`);
|
|
290945
|
+
}
|
|
290946
|
+
resolve3({
|
|
290947
|
+
tunnelProcess,
|
|
290948
|
+
tunnelUrl
|
|
290949
|
+
});
|
|
290950
|
+
}
|
|
290951
|
+
}
|
|
290952
|
+
});
|
|
290953
|
+
tunnelProcess?.stderr?.on("data", (data) => {
|
|
290954
|
+
const message = data.toString();
|
|
290955
|
+
if (message.includes("Permanently added")) {
|
|
290956
|
+
return;
|
|
290957
|
+
}
|
|
290958
|
+
if (message.includes("closed by remote host.")) {
|
|
290959
|
+
const errorMsg = "Please check that your BM_API_TOKEN is correct and has permissions to create tunnels.";
|
|
290960
|
+
if (options.onError) {
|
|
290961
|
+
options.onError(errorMsg);
|
|
290962
|
+
}
|
|
290963
|
+
if (options.exitOnError !== false) {
|
|
290964
|
+
console.error(source_default.red.bold(`\u274C Error: ${errorMsg}`));
|
|
290965
|
+
process.exit(1);
|
|
290966
|
+
}
|
|
290967
|
+
reject(new Error(errorMsg));
|
|
290968
|
+
return;
|
|
290969
|
+
}
|
|
290970
|
+
if (options.onError) {
|
|
290971
|
+
options.onError(message);
|
|
290972
|
+
} else {
|
|
290973
|
+
console.error(`stderr: ${data}`);
|
|
290974
|
+
}
|
|
290975
|
+
});
|
|
290976
|
+
tunnelProcess?.on("error", (error2) => {
|
|
290977
|
+
const errorMsg = `Failed to start tunnel: ${error2.message}`;
|
|
290978
|
+
if (options.onError) {
|
|
290979
|
+
options.onError(errorMsg);
|
|
290980
|
+
}
|
|
290981
|
+
reject(new Error(errorMsg));
|
|
290982
|
+
});
|
|
290983
|
+
tunnelProcess?.on("close", (code) => {
|
|
290984
|
+
if (code !== 0 && code !== null) {
|
|
290985
|
+
const errorMsg = `Tunnel process exited with code ${code}`;
|
|
290986
|
+
if (options.onError) {
|
|
290987
|
+
options.onError(errorMsg);
|
|
290988
|
+
}
|
|
290989
|
+
reject(new Error(errorMsg));
|
|
290990
|
+
}
|
|
290991
|
+
});
|
|
290361
290992
|
});
|
|
290362
290993
|
}
|
|
290363
290994
|
|
|
@@ -290375,8 +291006,12 @@ async function runTestCommand(options) {
|
|
|
290375
291006
|
}
|
|
290376
291007
|
let tunnelProcess = null;
|
|
290377
291008
|
let tunnelUrl;
|
|
291009
|
+
const appUrl = process.env.APP_URL;
|
|
290378
291010
|
try {
|
|
290379
|
-
if (
|
|
291011
|
+
if (appUrl) {
|
|
291012
|
+
console.log(source_default.green(`Using APP_URL: ${appUrl}`));
|
|
291013
|
+
tunnelUrl = appUrl;
|
|
291014
|
+
} else if (options.tunnel) {
|
|
290380
291015
|
const tunnelSpinner = ora("Starting tunnel...").start();
|
|
290381
291016
|
try {
|
|
290382
291017
|
const result2 = await startTunnel(null, {
|
|
@@ -290402,14 +291037,17 @@ async function runTestCommand(options) {
|
|
|
290402
291037
|
console.log(source_default.dim("\u2500".repeat(50)));
|
|
290403
291038
|
console.log(source_default.bold(`
|
|
290404
291039
|
\u{1F4C1} Files to bundle (${result.files.length}):`));
|
|
291040
|
+
const isConfigFile = (f) => /^(playwright\.config|tsconfig|jest\.config|vitest\.config)\.(ts|js|mjs|cjs|json)$/.test(
|
|
291041
|
+
f.split("/").pop() || ""
|
|
291042
|
+
);
|
|
290405
291043
|
const filesByType = {
|
|
290406
|
-
config: result.files.filter(
|
|
291044
|
+
config: result.files.filter(isConfigFile),
|
|
290407
291045
|
tests: result.files.filter((f) => /\.(spec|test)\.(ts|js|tsx|jsx)$/.test(f)),
|
|
290408
291046
|
source: result.files.filter(
|
|
290409
|
-
(f) => !f
|
|
291047
|
+
(f) => !isConfigFile(f) && !/\.(spec|test)\.(ts|js|tsx|jsx)$/.test(f) && /\.(ts|js|tsx|jsx)$/.test(f)
|
|
290410
291048
|
),
|
|
290411
291049
|
other: result.files.filter(
|
|
290412
|
-
(f) => !f
|
|
291050
|
+
(f) => !isConfigFile(f) && !/\.(spec|test)\.(ts|js|tsx|jsx)$/.test(f) && !/\.(ts|js|tsx|jsx)$/.test(f)
|
|
290413
291051
|
)
|
|
290414
291052
|
};
|
|
290415
291053
|
if (filesByType.config.length > 0) {
|
|
@@ -290455,16 +291093,80 @@ async function runTestCommand(options) {
|
|
|
290455
291093
|
return;
|
|
290456
291094
|
}
|
|
290457
291095
|
const zipSpinner = ora("Creating test bundle...").start();
|
|
290458
|
-
|
|
290459
|
-
|
|
290460
|
-
|
|
290461
|
-
|
|
290462
|
-
|
|
290463
|
-
|
|
290464
|
-
|
|
290465
|
-
|
|
290466
|
-
|
|
290467
|
-
|
|
291096
|
+
let zipBuffer;
|
|
291097
|
+
let bundleInfo = {};
|
|
291098
|
+
if (options.esbuild) {
|
|
291099
|
+
zipSpinner.text = "Transpiling with esbuild...";
|
|
291100
|
+
const esbuildResult = await zipWithEsbuild(
|
|
291101
|
+
projectRoot,
|
|
291102
|
+
result.files,
|
|
291103
|
+
result.packageJson,
|
|
291104
|
+
result.graph.nodeModuleDeps
|
|
291105
|
+
);
|
|
291106
|
+
zipBuffer = esbuildResult.buffer;
|
|
291107
|
+
bundleInfo.warnings = esbuildResult.warnings;
|
|
291108
|
+
bundleInfo.errors = esbuildResult.errors;
|
|
291109
|
+
if (esbuildResult.errors.length > 0) {
|
|
291110
|
+
zipSpinner.warn(source_default.yellow(`Bundle created with ${esbuildResult.errors.length} errors`));
|
|
291111
|
+
console.log(source_default.red("\nEsbuild errors:"));
|
|
291112
|
+
esbuildResult.errors.forEach((err) => console.log(source_default.red(` ${err}`)));
|
|
291113
|
+
}
|
|
291114
|
+
} else {
|
|
291115
|
+
const zipResult = await zipFilesToBuffer(
|
|
291116
|
+
projectRoot,
|
|
291117
|
+
result.files,
|
|
291118
|
+
result.packageJson,
|
|
291119
|
+
result.graph.nodeModuleDeps
|
|
291120
|
+
);
|
|
291121
|
+
zipBuffer = zipResult.buffer;
|
|
291122
|
+
bundleInfo.workspacePackages = zipResult.workspacePackages;
|
|
291123
|
+
bundleInfo.includedPackages = zipResult.includedPackages;
|
|
291124
|
+
bundleInfo.warnings = zipResult.warnings;
|
|
291125
|
+
}
|
|
291126
|
+
if (process.env.KEEP_ZIP === "true") {
|
|
291127
|
+
const zipPath = path6.join(projectRoot, "browsermation-bundle.zip");
|
|
291128
|
+
(0, import_node_fs5.writeFileSync)(zipPath, zipBuffer);
|
|
291129
|
+
zipSpinner.succeed(
|
|
291130
|
+
source_default.green(
|
|
291131
|
+
`Bundle created (${(zipBuffer.length / 1024 / 1024).toFixed(2)} MB) \u2192 ${zipPath}`
|
|
291132
|
+
)
|
|
291133
|
+
);
|
|
291134
|
+
} else {
|
|
291135
|
+
zipSpinner.succeed(
|
|
291136
|
+
source_default.green(
|
|
291137
|
+
`Bundle created (${(zipBuffer.length / 1024 / 1024).toFixed(2)} MB)${options.esbuild ? " [esbuild]" : ""}`
|
|
291138
|
+
)
|
|
291139
|
+
);
|
|
291140
|
+
}
|
|
291141
|
+
if (!options.esbuild && bundleInfo.includedPackages) {
|
|
291142
|
+
const regularPackages = new Set(
|
|
291143
|
+
[...bundleInfo.includedPackages].filter((p) => !bundleInfo.workspacePackages?.has(p))
|
|
291144
|
+
);
|
|
291145
|
+
if (bundleInfo.workspacePackages && bundleInfo.workspacePackages.size > 0) {
|
|
291146
|
+
console.log(source_default.bold(`
|
|
291147
|
+
\u{1F517} Workspace packages (${bundleInfo.workspacePackages.size}) - bundled without transitive deps:`));
|
|
291148
|
+
const sortedWorkspace = Array.from(bundleInfo.workspacePackages).sort();
|
|
291149
|
+
sortedWorkspace.forEach((pkg) => console.log(source_default.yellow(` ${pkg}`)));
|
|
291150
|
+
}
|
|
291151
|
+
if (regularPackages.size > 0) {
|
|
291152
|
+
console.log(source_default.bold(`
|
|
291153
|
+
\u{1F4E6} Bundled node_modules (${regularPackages.size}):`));
|
|
291154
|
+
const sortedPackages = Array.from(regularPackages).sort();
|
|
291155
|
+
sortedPackages.forEach((pkg) => console.log(source_default.dim(` ${pkg}`)));
|
|
291156
|
+
}
|
|
291157
|
+
}
|
|
291158
|
+
if (bundleInfo.warnings && bundleInfo.warnings.length > 0) {
|
|
291159
|
+
console.log(source_default.bold.yellow(`
|
|
291160
|
+
\u26A0\uFE0F Warnings (${bundleInfo.warnings.length}):`));
|
|
291161
|
+
bundleInfo.warnings.forEach((warning2) => {
|
|
291162
|
+
console.log(source_default.yellow(` ${warning2}`));
|
|
291163
|
+
});
|
|
291164
|
+
if (!options.esbuild) {
|
|
291165
|
+
console.log(source_default.yellow("\n Tests may fail due to unbuilt packages. Consider:"));
|
|
291166
|
+
console.log(source_default.yellow(" 1. Building the packages first (e.g., npm run build in the package directory)"));
|
|
291167
|
+
console.log(source_default.yellow(" 2. Installing published versions from npm instead of monorepo symlinks"));
|
|
291168
|
+
}
|
|
291169
|
+
}
|
|
290468
291170
|
const uploadSpinner = ora("Uploading to BrowserMation...").start();
|
|
290469
291171
|
const eventStream = new (await import("stream")).Readable({
|
|
290470
291172
|
read() {
|
|
@@ -290513,8 +291215,18 @@ Error: ${error2.message}`));
|
|
|
290513
291215
|
// src/commands/tunnel.ts
|
|
290514
291216
|
async function runTunnelCommand(options) {
|
|
290515
291217
|
console.log(source_default.blue(`Starting BrowserMation Tunnel...`));
|
|
290516
|
-
|
|
290517
|
-
|
|
291218
|
+
const tunnelOptions = {
|
|
291219
|
+
port: options.port || "",
|
|
291220
|
+
host: options.host,
|
|
291221
|
+
onStart: (tunnelUrl) => {
|
|
291222
|
+
console.log(
|
|
291223
|
+
source_default.green.bold(
|
|
291224
|
+
`\u2705 Tunnel is running! Access your application at: ${tunnelUrl}`
|
|
291225
|
+
)
|
|
291226
|
+
);
|
|
291227
|
+
}
|
|
291228
|
+
};
|
|
291229
|
+
await startTunnel(null, tunnelOptions);
|
|
290518
291230
|
}
|
|
290519
291231
|
|
|
290520
291232
|
// src/commands/runner.ts
|
|
@@ -290621,7 +291333,7 @@ program2.command("tunnel").description("Start a BrowserMation tunnel").option("-
|
|
|
290621
291333
|
program2.command("runner").description("Start the browser engine server").option("-p, --port <port>").option("-t, --tunnel").action(async (options) => {
|
|
290622
291334
|
await runRunnerCommand(options);
|
|
290623
291335
|
});
|
|
290624
|
-
program2.command("test").description("Analyze and run Playwright tests on BrowserMation").option("--project <project>", "Run a specific Playwright project").option("-t, --tunnel <port>", "Expose local port via tunnel").option("-p, --proxy", "Use proxy for test execution").option("--dry-run", "Analyze dependencies without uploading").action(async (options) => {
|
|
291336
|
+
program2.command("test").description("Analyze and run Playwright tests on BrowserMation").option("--project <project>", "Run a specific Playwright project").option("-t, --tunnel <port>", "Expose local port via tunnel").option("-p, --proxy", "Use proxy for test execution").option("--dry-run", "Analyze dependencies without uploading").option("--esbuild", "Use esbuild tree-shaking for minimal bundle size (experimental)").action(async (options) => {
|
|
290625
291337
|
console.log(source_default.blue("Starting BrowserMation Test Runner..."));
|
|
290626
291338
|
await runTestCommand(options);
|
|
290627
291339
|
});
|