@unrulysystems/rn-playwright-driver-runner 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/cli.js +77 -20
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +77 -20
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @unrulysystems/rn-playwright-driver-runner
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#30](https://github.com/unrulysystems/rn-playwright-driver/pull/30) [`4bdbe20`](https://github.com/unrulysystems/rn-playwright-driver/commit/4bdbe2073f7b613f6bfb8d5a13db5e0ca000e1c5) Thanks [@alleneubank](https://github.com/alleneubank)! - Upgrade the dogfood example and native module tooling to Expo SDK 56.
|
|
8
|
+
|
|
9
|
+
The driver now sends a React Native inspector-compatible WebSocket Origin when
|
|
10
|
+
attaching to Hermes CDP, which keeps Expo SDK 56 dev-client debugging connected
|
|
11
|
+
on localhost Metro servers. The runner also fast-fails companion readiness when
|
|
12
|
+
captured iOS or Android companion logs contain terminal build, test, or
|
|
13
|
+
instrumentation failure markers instead of waiting for the full probe timeout.
|
|
14
|
+
|
|
3
15
|
## 0.1.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -54,6 +54,10 @@ var DEFAULTS = {
|
|
|
54
54
|
androidTokenFileName: "rn-driver-touch-token"
|
|
55
55
|
};
|
|
56
56
|
var SECRET_PLACEHOLDER = "<token-file>";
|
|
57
|
+
var COMPANION_FAILURE_MARKERS = {
|
|
58
|
+
ios: ["** BUILD FAILED **", "** TEST FAILED **"],
|
|
59
|
+
android: ["INSTRUMENTATION_FAILED", "Process crashed"]
|
|
60
|
+
};
|
|
57
61
|
|
|
58
62
|
// src/plan/env.ts
|
|
59
63
|
function buildIosDriverEnv(resolved, metro, timeoutMs) {
|
|
@@ -273,7 +277,10 @@ function planAndroid(input) {
|
|
|
273
277
|
port: resolved.touchPort,
|
|
274
278
|
tokenFile: resolved.tokenFile,
|
|
275
279
|
timeoutMs: resolved.companionReadyTimeoutMs
|
|
276
|
-
}
|
|
280
|
+
},
|
|
281
|
+
// Abort early if `am instrument` reports the companion failed to start (crash / missing
|
|
282
|
+
// androidTest target) instead of waiting out the readiness budget.
|
|
283
|
+
failureMarkers: COMPANION_FAILURE_MARKERS.android
|
|
277
284
|
}
|
|
278
285
|
});
|
|
279
286
|
push(launchStep("android.launch-2", android, launch2Command));
|
|
@@ -604,7 +611,10 @@ function planIos(input) {
|
|
|
604
611
|
port: resolved.touchPort,
|
|
605
612
|
tokenFile: resolved.tokenFile,
|
|
606
613
|
timeoutMs: resolved.companionReadyTimeoutMs
|
|
607
|
-
}
|
|
614
|
+
},
|
|
615
|
+
// Abort early if `xcodebuild test` reports a build/test failure (it lingers "alive" after, so
|
|
616
|
+
// the 300s readiness budget would otherwise be burnt waiting for a companion that cannot bind).
|
|
617
|
+
failureMarkers: COMPANION_FAILURE_MARKERS.ios
|
|
608
618
|
}
|
|
609
619
|
});
|
|
610
620
|
if (isDevClient) {
|
|
@@ -860,8 +870,10 @@ function renderAction(action) {
|
|
|
860
870
|
return `write ${action.path}${action.mode ? ` (mode ${action.mode.toString(8)})` : ""}`;
|
|
861
871
|
case "free-port":
|
|
862
872
|
return `free-port ${action.port}`;
|
|
863
|
-
case "probe":
|
|
864
|
-
|
|
873
|
+
case "probe": {
|
|
874
|
+
const fastFail = action.failureMarkers?.length ? ` [fast-fail on: ${action.failureMarkers.join(", ")}]` : "";
|
|
875
|
+
return `probe ${renderProbe(action.probe)}${fastFail}`;
|
|
876
|
+
}
|
|
865
877
|
default: {
|
|
866
878
|
const _exhaustive = action;
|
|
867
879
|
throw new Error(`unhandled action: ${JSON.stringify(_exhaustive)}`);
|
|
@@ -907,6 +919,25 @@ function renderProbe(probe) {
|
|
|
907
919
|
}
|
|
908
920
|
}
|
|
909
921
|
|
|
922
|
+
// src/runner/probe-failure.ts
|
|
923
|
+
var ProbeFailure = class extends Error {
|
|
924
|
+
marker;
|
|
925
|
+
constructor(marker, detail) {
|
|
926
|
+
super(
|
|
927
|
+
`companion process reported a terminal failure ("${marker}") \u2014 aborting the readiness wait. The build/test failed; it will not become ready.${detail ? `
|
|
928
|
+
${detail}` : ""}`
|
|
929
|
+
);
|
|
930
|
+
this.name = "ProbeFailure";
|
|
931
|
+
this.marker = marker;
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
function findFailureMarker(log, markers) {
|
|
935
|
+
for (const marker of markers) {
|
|
936
|
+
if (log.includes(marker)) return marker;
|
|
937
|
+
}
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
|
|
910
941
|
// src/runner/execute.ts
|
|
911
942
|
var StageError = class extends Error {
|
|
912
943
|
stage;
|
|
@@ -974,22 +1005,30 @@ async function runStep(step, runner, opts, processes, isAlive) {
|
|
|
974
1005
|
case "probe": {
|
|
975
1006
|
const key = processKeyForProbe(action.probe);
|
|
976
1007
|
const aliveFn = key === null ? () => true : () => isAlive(key);
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
remaining
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1008
|
+
const watch = key !== null && action.failureMarkers && action.failureMarkers.length > 0 ? { logPath: logPathFor(opts.logDir, key), failureMarkers: action.failureMarkers } : void 0;
|
|
1009
|
+
try {
|
|
1010
|
+
let ready = await runner.probe(action.probe, aliveFn, watch);
|
|
1011
|
+
let remaining = action.retry?.max ?? 0;
|
|
1012
|
+
while (!ready && remaining > 0) {
|
|
1013
|
+
remaining -= 1;
|
|
1014
|
+
if (action.retry) {
|
|
1015
|
+
runner.log(`retry ${step.id}: re-running launch (${remaining} attempt(s) left)`);
|
|
1016
|
+
await runner.exec(action.retry.command);
|
|
1017
|
+
}
|
|
1018
|
+
ready = await runner.probe(action.probe, aliveFn, watch);
|
|
984
1019
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1020
|
+
if (!ready) {
|
|
1021
|
+
throw new StageError(
|
|
1022
|
+
step.stage,
|
|
1023
|
+
step.id,
|
|
1024
|
+
`readiness timed out after ${action.probe.timeoutMs}ms`
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
} catch (error) {
|
|
1028
|
+
if (error instanceof ProbeFailure) {
|
|
1029
|
+
throw new StageError(step.stage, step.id, error.message);
|
|
1030
|
+
}
|
|
1031
|
+
throw error;
|
|
993
1032
|
}
|
|
994
1033
|
return;
|
|
995
1034
|
}
|
|
@@ -1128,10 +1167,15 @@ var NodeProcessRunner = class {
|
|
|
1128
1167
|
}
|
|
1129
1168
|
if (pids.length > 0) await delay(1e3);
|
|
1130
1169
|
}
|
|
1131
|
-
probe(probe, isAlive) {
|
|
1170
|
+
probe(probe, isAlive, watch) {
|
|
1132
1171
|
const deadline = Date.now() + probe.timeoutMs;
|
|
1133
1172
|
const attempt = async () => {
|
|
1134
1173
|
for (; ; ) {
|
|
1174
|
+
if (watch) {
|
|
1175
|
+
const log = await readWatchedLog(watch.logPath);
|
|
1176
|
+
const marker = findFailureMarker(log, watch.failureMarkers);
|
|
1177
|
+
if (marker) throw new ProbeFailure(marker, lastLines(log));
|
|
1178
|
+
}
|
|
1135
1179
|
if (!isAlive()) return false;
|
|
1136
1180
|
if (await probeOnce(probe)) return true;
|
|
1137
1181
|
if (Date.now() >= deadline) return false;
|
|
@@ -1176,6 +1220,19 @@ function delay(ms) {
|
|
|
1176
1220
|
setTimeout(resolve, ms);
|
|
1177
1221
|
});
|
|
1178
1222
|
}
|
|
1223
|
+
async function readWatchedLog(path4) {
|
|
1224
|
+
try {
|
|
1225
|
+
return await promises.readFile(path4, "utf8");
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
throw new Error(
|
|
1228
|
+
`cannot read companion log for fast-fail marker detection (${path4}): ${String(error)}`,
|
|
1229
|
+
{ cause: error }
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
function lastLines(text, n) {
|
|
1234
|
+
return text.split("\n").filter((line) => line.trim().length > 0).slice(-12).join("\n");
|
|
1235
|
+
}
|
|
1179
1236
|
async function probeOnce(probe) {
|
|
1180
1237
|
switch (probe.kind) {
|
|
1181
1238
|
case "metro-status":
|