@unrulysystems/rn-playwright-driver-runner 0.1.0 → 0.1.1

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/cli.mjs CHANGED
@@ -209,9 +209,10 @@ function planAndroid(input) {
209
209
  }
210
210
  }
211
211
  });
212
- const launchCommand = launchCommandFor(android, serial);
213
- push(launchStep("android.launch-1", android, serial));
214
- push(hermesStep("android.hermes-1", android, metro, resolved, hermesDeviceName, launchCommand));
212
+ const launch1Command = launchCommandFor(android, resolved, serial, { forceStopBefore: true });
213
+ const launch2Command = launchCommandFor(android, resolved, serial, { forceStopBefore: false });
214
+ push(launchStep("android.launch-1", android, launch1Command));
215
+ push(hermesStep("android.hermes-1", android, metro, resolved, hermesDeviceName, launch1Command));
215
216
  push({
216
217
  id: "android.forward-clean",
217
218
  stage: "companion",
@@ -268,8 +269,8 @@ function planAndroid(input) {
268
269
  }
269
270
  }
270
271
  });
271
- push(launchStep("android.launch-2", android, serial));
272
- push(hermesStep("android.hermes-2", android, metro, resolved, hermesDeviceName, launchCommand));
272
+ push(launchStep("android.launch-2", android, launch2Command));
273
+ push(hermesStep("android.hermes-2", android, metro, resolved, hermesDeviceName, launch2Command));
273
274
  const cleanup = [
274
275
  {
275
276
  type: "kill-process",
@@ -324,22 +325,34 @@ function planAndroid(input) {
324
325
  playwright: playwrightCommand(playwright, specs, passthrough)
325
326
  };
326
327
  }
327
- function launchCommandFor(android, serial) {
328
- return adb(serial, [
329
- "shell",
330
- "am",
331
- "start",
332
- "-W",
333
- "-n",
334
- `${android.packageName}/${android.activity}`
335
- ]);
336
- }
337
- function launchStep(id, android, serial) {
328
+ function launchCommandFor(android, resolved, serial, opts) {
329
+ if (android.launch.kind === "plain") {
330
+ return adb(serial, [
331
+ "shell",
332
+ "am",
333
+ "start",
334
+ "-W",
335
+ "-n",
336
+ `${android.packageName}/${android.activity}`
337
+ ]);
338
+ }
339
+ if (!android.scheme) {
340
+ throw new Error('android.scheme is required when android.launch.kind is "expo-dev-client"');
341
+ }
342
+ const launchScript = `am start -a android.intent.action.VIEW -d ${shellSingleQuote(
343
+ devClientUrl(android.scheme, resolved.initialUrl)
344
+ )}`;
345
+ return adbShellScript(
346
+ serial,
347
+ opts.forceStopBefore ? `am force-stop ${android.packageName} && ${launchScript}` : launchScript
348
+ );
349
+ }
350
+ function launchStep(id, android, command) {
338
351
  return {
339
352
  id,
340
353
  stage: "app-launch",
341
354
  description: `Launch ${android.packageName}/${android.activity}`,
342
- action: { type: "command", command: launchCommandFor(android, serial) }
355
+ action: { type: "command", command }
343
356
  };
344
357
  }
345
358
  function hermesStep(id, android, metro, resolved, deviceNameMatch, launchCommand) {
@@ -373,6 +386,12 @@ function debugHostXml(host) {
373
386
  function adb(serial, args) {
374
387
  return { command: "adb", args: ["-s", serial, ...args] };
375
388
  }
389
+ function devClientUrl(scheme, initialUrl) {
390
+ return `${scheme}://expo-development-client/?url=${initialUrl}`;
391
+ }
392
+ function shellSingleQuote(value) {
393
+ return `'${value.replaceAll("'", "'\\''")}'`;
394
+ }
376
395
  function adbShellScript(serial, remote) {
377
396
  return { command: "adb", args: ["-s", serial, "shell", remote] };
378
397
  }
@@ -418,8 +437,7 @@ function planIos(input) {
418
437
  // Pass the resolved UI-test scheme so a custom `ios.uitestScheme` scaffolds
419
438
  // the SAME target that companion startup later builds (default is
420
439
  // `${appScheme}UITests`).
421
- command: npx([
422
- "rn-driver-xctest-scaffold",
440
+ command: cmd("node_modules/.bin/rn-driver-xctest-scaffold", [
423
441
  "--ios-dir",
424
442
  "ios",
425
443
  "--project-name",
@@ -713,7 +731,7 @@ function placeholderIos(ios, metro) {
713
731
  initialUrl: ios.launch.initialUrl ?? metro.url
714
732
  };
715
733
  }
716
- function placeholderAndroid(android, _metro) {
734
+ function placeholderAndroid(android, metro) {
717
735
  return {
718
736
  serial: "<android-serial>",
719
737
  touchPort: android.companion?.port ?? DEFAULTS.companionPort,
@@ -721,7 +739,8 @@ function placeholderAndroid(android, _metro) {
721
739
  hermesTimeoutMs: DEFAULTS.hermesTargetTimeoutMs,
722
740
  tokenFile: SECRET_PLACEHOLDER,
723
741
  deviceTokenFileName: DEFAULTS.androidTokenFileName,
724
- instrumentationTarget: instrumentationTarget(android)
742
+ instrumentationTarget: instrumentationTarget(android),
743
+ initialUrl: android.launch.initialUrl ?? metro.url
725
744
  };
726
745
  }
727
746
 
@@ -748,7 +767,7 @@ function buildDryRunPlan(config, platform, opts = {}) {
748
767
  return planAndroid({
749
768
  android,
750
769
  metro,
751
- resolved: placeholderAndroid(android),
770
+ resolved: placeholderAndroid(android, metro),
752
771
  playwright: config.playwright,
753
772
  timeoutMs: config.timeoutMs,
754
773
  specs,
@@ -1288,7 +1307,7 @@ async function resolveIosTarget(ios, metro, opts) {
1288
1307
  initialUrl: ios.launch.initialUrl ?? metro.url
1289
1308
  };
1290
1309
  }
1291
- async function resolveAndroidTarget(android, _metro, opts) {
1310
+ async function resolveAndroidTarget(android, metro, opts) {
1292
1311
  const serial = await selectSerial(opts.device);
1293
1312
  await requireBooted(serial);
1294
1313
  const deviceName = (await capture("adb", ["-s", serial, "shell", "getprop", "ro.product.model"])).trim();
@@ -1301,7 +1320,8 @@ async function resolveAndroidTarget(android, _metro, opts) {
1301
1320
  hermesTimeoutMs: DEFAULTS.hermesTargetTimeoutMs,
1302
1321
  tokenFile,
1303
1322
  deviceTokenFileName: DEFAULTS.androidTokenFileName,
1304
- instrumentationTarget: instrumentationTarget(android)
1323
+ instrumentationTarget: instrumentationTarget(android),
1324
+ initialUrl: android.launch.initialUrl ?? metro.url
1305
1325
  },
1306
1326
  deviceName
1307
1327
  };
@@ -1406,6 +1426,7 @@ var IOS_KEYS = /* @__PURE__ */ new Set([
1406
1426
  var ANDROID_KEYS = /* @__PURE__ */ new Set([
1407
1427
  "packageName",
1408
1428
  "activity",
1429
+ "scheme",
1409
1430
  "gradleTasks",
1410
1431
  "appApkPath",
1411
1432
  "testApkPath",
@@ -1507,6 +1528,8 @@ function validateAndroid(android, errors) {
1507
1528
  reportUnknownKeys("config.android", android, ANDROID_KEYS, errors);
1508
1529
  requireAndroidPackage("config.android.packageName", android.packageName, errors);
1509
1530
  requireAndroidActivity("config.android.activity", android.activity, errors);
1531
+ if (android.scheme !== void 0)
1532
+ requireAppScheme("config.android.scheme", android.scheme, errors);
1510
1533
  optionalString("config.android.appApkPath", android.appApkPath, errors);
1511
1534
  optionalString("config.android.testApkPath", android.testApkPath, errors);
1512
1535
  if (android.instrumentationTarget !== void 0)
@@ -1519,7 +1542,10 @@ function validateAndroid(android, errors) {
1519
1542
  errors.push("config.android.gradleTasks: expected an array of strings");
1520
1543
  }
1521
1544
  validateCompanion("config.android.companion", android.companion, errors);
1522
- validateLaunch("config.android.launch", android.launch, errors);
1545
+ const launch = validateLaunch("config.android.launch", android.launch, errors);
1546
+ if (launch?.kind === "expo-dev-client" && android.scheme === void 0) {
1547
+ errors.push('config.android.scheme: required when android.launch.kind is "expo-dev-client"');
1548
+ }
1523
1549
  }
1524
1550
  function validateCompanion(path4, companion, errors) {
1525
1551
  if (companion === void 0) return;
@@ -1565,6 +1591,7 @@ function requireString(path4, value, errors) {
1565
1591
  }
1566
1592
  var ANDROID_PACKAGE_RE = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$/;
1567
1593
  var ANDROID_ACTIVITY_RE = /^\.?[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)*$/;
1594
+ var APP_SCHEME_RE = /^[a-z][a-z0-9+.-]*$/;
1568
1595
  function requireAndroidPackage(path4, value, errors) {
1569
1596
  if (typeof value !== "string" || value.trim() === "") {
1570
1597
  errors.push(`${path4}: required non-empty string`);
@@ -1581,6 +1608,17 @@ function requireAndroidActivity(path4, value, errors) {
1581
1608
  if (!ANDROID_ACTIVITY_RE.test(value))
1582
1609
  errors.push(`${path4}: expected an activity name (e.g. .MainActivity)`);
1583
1610
  }
1611
+ function requireAppScheme(path4, value, errors) {
1612
+ if (typeof value !== "string" || value.trim() === "") {
1613
+ errors.push(`${path4}: required non-empty string`);
1614
+ return;
1615
+ }
1616
+ if (!APP_SCHEME_RE.test(value)) {
1617
+ errors.push(
1618
+ `${path4}: expected a valid URL scheme (lowercase letter, then lowercase letters, digits, +, ., or -)`
1619
+ );
1620
+ }
1621
+ }
1584
1622
  var ANDROID_INSTRUMENTATION_RE = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)*\/[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)*$/;
1585
1623
  function requireInstrumentationTarget(path4, value, errors) {
1586
1624
  if (typeof value !== "string" || value.trim() === "") {