@delacour/warden-e2e 0.9.0 → 0.11.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.
@@ -4351,6 +4351,9 @@ var healthDataSchema = z6.looseObject({
4351
4351
  socket: z6.object({ path: z6.string(), clients: z6.number() }).optional(),
4352
4352
  idb: z6.string().optional(),
4353
4353
  xcode: z6.string().optional(),
4354
+ builtWith: z6.object({ xcode: z6.string().optional(), idb: z6.string().optional() }).optional(),
4355
+ coreSimulatorVersion: z6.string().nullish(),
4356
+ frontmost: z6.object({ unresolvedAgoMs: z6.number(), method: z6.string() }).optional(),
4354
4357
  state: z6.string().optional(),
4355
4358
  uptimeMs: z6.number().optional()
4356
4359
  });
@@ -4362,6 +4365,7 @@ var snapshotDataSchema = z6.looseObject({
4362
4365
  elements: z6.array(z6.custom(isWireElement, { error: (issue) => wireElementProblem(issue.input) })),
4363
4366
  ms: z6.number(),
4364
4367
  fallback: z6.object({ from: z6.string(), to: z6.string(), reason: z6.string() }).optional(),
4368
+ target: z6.object({ pid: z6.number(), source: z6.string() }).optional(),
4365
4369
  readMs: z6.number().optional(),
4366
4370
  nodes: z6.number().optional()
4367
4371
  });
@@ -9170,6 +9174,6 @@ function onlyWasSeen() {
9170
9174
 
9171
9175
  // ../../packages/e2e/src/version.ts
9172
9176
  var WORKSPACE_VERSION = "0.0.0-workspace";
9173
- var WARDEN_E2E_VERSION2 = "0.9.0";
9177
+ var WARDEN_E2E_VERSION2 = "0.11.0";
9174
9178
 
9175
9179
  export { E2eError2, registerA11yTarget, a11yTargetOf, canActOnElements, noteSpanDetail, addSpanDetail, canObserve, canDetectAlerts, settleDetailOf, DEFAULT_SETTLE_QUIET_MS, DEFAULT_SETTLE_TIMEOUT_MS, settleByHash, snapshotHash, ok, err, swipeVector, screenRect, fieldValue, PINCH_MS, ROTATE_MS, PATH_MS, centreOf, pinchRadius, rotateRadius, requireGesture, assertScale, assertDegrees, isInteractiveRole, resolveRole, normalizeText, matchesText, indexSnapshot, testIdQuery, textQuery, roleQuery, selectorExpression, renderSnapshot, renderHeader, resolve, locateByTestIdViaReact, isLocator, Locator, pickOne, textOf, scrollUntilVisible, bunExec, execError, driverError, driverErr, logEventSchema, fatalEventSchema, responseSchema, mapWireError, createLineSplitter, encodeRequest, bunSpawn, stdioTransport, socketTransport, createSimdClient, spawnSimd, connectSimd, isRecoverableLoss, CAMERA_FACINGS, CONDITION_AREAS, resolveNetwork, resolveTextSize, androidFontScale, ENV_NAMES, DEFAULT_ASSERTION_TIMEOUT_MS, readEnv, runStep, setDefaultHidRecovery, setDefaultNativeLog, setDefaultDriverFactory, hasDefaultDriverFactory, setDefaultFixtureFactory, hasDefaultFixtureFactory, attemptSession, getSession, accessibleName, announce, failing, formatIssues, toE2eError, settled, unwrap, parseUiadA11yEvents, parseInjectEvents, withA11yRead, renderA11yScreen, createDeviceA11y, IOS_DEVICE_CAPABILITIES, sniffCameraMedia, cameraFeedDir, clearCameraFeeds, isLeaseAlive, processAlive, describeOwner, isPhysicalIosId, wardenHome, defaultDbPath, ownerKey, openStore, callerFile, formatCoord, DEFAULT_SPEED_MPS, DEFAULT_INTERVAL_S, realTickerClock, startRouteTicker, startFlap, registerConditions, conditionsOf, conditionSinkFor, createDeviceConditions, parseBudgets, createDevicePerf, perfStartFor, spawnWarden, hash6, attemptDir, screenshotPath, specIdOf, realNativeLogDeps, captureNativeLog, BUN_TIMEOUT_MARGIN_MS2, ownHook, currentScope, createScope, runInScope, hooksFor, resolveUse, registrationDefaults, markOnly, onlyWasSeen, WORKSPACE_VERSION, WARDEN_E2E_VERSION2 };
package/index.mjs CHANGED
@@ -41,7 +41,7 @@ import {
41
41
  registrationDefaults,
42
42
  markOnly,
43
43
  WARDEN_E2E_VERSION2
44
- } from "./chunk-y0y7frfz.mjs";
44
+ } from "./chunk-ggcjzrvh.mjs";
45
45
  // ../../packages/e2e/src/expect/expect.ts
46
46
  import { expect as bunExpect } from "bun:test";
47
47
 
package/package.json CHANGED
@@ -1,21 +1,25 @@
1
1
  {
2
2
  "name": "@delacour/warden-e2e",
3
- "version": "0.9.0",
4
- "description": "TypeScript spec API for `warden e2e`: test, expect, screen, device, app",
3
+ "version": "0.11.0",
4
+ "description": "TypeScript e2e testing for React Native and Expo on iOS simulators and Android emulators, run by `warden e2e`: test, expect, screen, device, app",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/delacournz/warden.git"
9
9
  },
10
- "homepage": "https://github.com/delacournz/warden#readme",
10
+ "homepage": "https://warden.co.nz/docs/e2e",
11
11
  "bugs": {
12
12
  "url": "https://github.com/delacournz/warden/issues"
13
13
  },
14
14
  "type": "module",
15
15
  "keywords": [
16
16
  "e2e",
17
+ "e2e-testing",
18
+ "react-native",
19
+ "expo",
17
20
  "ios-simulator",
18
21
  "android-emulator",
22
+ "mobile-testing",
19
23
  "bun",
20
24
  "testing"
21
25
  ],
@@ -37,7 +41,7 @@
37
41
  "LICENSE"
38
42
  ],
39
43
  "peerDependencies": {
40
- "@delacour/warden": "0.9.0"
44
+ "@delacour/warden": "0.11.0"
41
45
  },
42
46
  "dependencies": {
43
47
  "zod": "^4.4.3"
package/preload.mjs CHANGED
@@ -109,7 +109,7 @@ import {
109
109
  onlyWasSeen,
110
110
  WORKSPACE_VERSION,
111
111
  WARDEN_E2E_VERSION2
112
- } from "./chunk-y0y7frfz.mjs";
112
+ } from "./chunk-ggcjzrvh.mjs";
113
113
 
114
114
  // ../../packages/e2e/src/preload.ts
115
115
  import { afterAll, setDefaultTimeout } from "bun:test";
@@ -8331,6 +8331,37 @@ function nativeDetail(data) {
8331
8331
  noteSpanDetail("frontmostPid", frontmostPid);
8332
8332
  return detail;
8333
8333
  }
8334
+ function noteSnapshotError(detail) {
8335
+ if (typeof detail !== "object" || detail === null)
8336
+ return;
8337
+ const fields = {
8338
+ stage: "axStage",
8339
+ reason: "axReason",
8340
+ request: "axRequest",
8341
+ bridgeError: "bridgeError",
8342
+ axError: "axError"
8343
+ };
8344
+ for (const [from, to] of Object.entries(fields)) {
8345
+ const value = detail[from];
8346
+ if (typeof value === "string")
8347
+ noteSpanDetail(to, value);
8348
+ }
8349
+ }
8350
+ function noteHelperHealth(health) {
8351
+ noteSpanDetail("bridge", health.ax.bridge);
8352
+ if (health.ax.lastError)
8353
+ noteSpanDetail("bridgeLastError", health.ax.lastError.message);
8354
+ if (health.ax.error)
8355
+ noteSpanDetail("bridgeLastError", health.ax.error);
8356
+ if (health.xcode)
8357
+ noteSpanDetail("hostXcode", health.xcode);
8358
+ if (health.builtWith?.xcode)
8359
+ noteSpanDetail("helperXcode", health.builtWith.xcode);
8360
+ if (health.coreSimulatorVersion)
8361
+ noteSpanDetail("coreSimulator", health.coreSimulatorVersion);
8362
+ if (health.frontmost)
8363
+ noteSpanDetail("frontmostUnresolvedAgoMs", health.frontmost.unresolvedAgoMs);
8364
+ }
8334
8365
  function noteRebind(data) {
8335
8366
  noteSpanDetail("rebind", data.bound ? "bound" : data.reason ?? "unbound");
8336
8367
  noteSpanDetail("rebindMs", data.waitedMs);
@@ -8401,6 +8432,7 @@ function createIosDriver(swap, simctl, opts) {
8401
8432
  const nativeSettle = ready.ax.default === "axbridge" && ready.ax.bridge === "available";
8402
8433
  const bridgeUp = ready.ax.bridge === "available";
8403
8434
  let settleUnsupported = !nativeSettle;
8435
+ let settleAxFailures = 0;
8404
8436
  let rebindUnsupported = false;
8405
8437
  let gestureUnsupported = false;
8406
8438
  let appOpsOutdated = false;
@@ -8495,16 +8527,30 @@ function createIosDriver(swap, simctl, opts) {
8495
8527
  note(viaHelper.data);
8496
8528
  return okVoid2;
8497
8529
  }
8530
+ let failureDiagnosed = false;
8498
8531
  const fetchSnapshot = async (o) => {
8499
8532
  const result = await request("snapshot", params({ interactiveOnly: o?.interactiveOnly, backend: o?.backend }));
8500
- if (!result.success)
8533
+ if (!result.success) {
8534
+ noteSnapshotError(result.error.detail);
8535
+ if (!failureDiagnosed) {
8536
+ failureDiagnosed = true;
8537
+ const health = await request("health", {});
8538
+ if (health.success)
8539
+ noteHelperHealth(health.data);
8540
+ }
8501
8541
  return result;
8502
- const { fallback } = result.data;
8542
+ }
8543
+ failureDiagnosed = false;
8544
+ const { fallback, target } = result.data;
8545
+ noteSpanDetail("backend", result.data.backend);
8503
8546
  if (fallback) {
8504
8547
  opts.log?.(`[ios] snapshot fell back ${fallback.from} -> ${fallback.to}: ${fallback.reason}`);
8505
- noteSpanDetail("backend", fallback.to);
8506
8548
  noteSpanDetail("fallback", fallback.reason);
8507
8549
  }
8550
+ if (target) {
8551
+ noteSpanDetail("targetPid", target.pid);
8552
+ noteSpanDetail("targetSource", target.source);
8553
+ }
8508
8554
  return { success: true, data: toSnapshot(result.data, now()) };
8509
8555
  };
8510
8556
  async function snapshot(o) {
@@ -8577,10 +8623,20 @@ function createIosDriver(swap, simctl, opts) {
8577
8623
  noteRebind(reply.data);
8578
8624
  return reply.data.bound;
8579
8625
  }
8626
+ function noteSettleAxFailure(message) {
8627
+ settleAxFailures += 1;
8628
+ noteSpanDetail("nativeError", "E_AX_UNAVAILABLE");
8629
+ if (settleAxFailures >= 2) {
8630
+ settleUnsupported = true;
8631
+ opts.log?.(`[ios] native settle could not bind the AX observer twice in a row, polling snapshot hashes: ${message}`);
8632
+ }
8633
+ return;
8634
+ }
8580
8635
  async function settleViaHelper(quietMs, timeoutMs) {
8581
8636
  const expected = launchedBundle;
8582
8637
  const native = await request("settle", { quietMs, settleTimeoutMs: timeoutMs, ...expected === undefined ? {} : { bundleId: expected } }, { timeoutMs: timeoutMs + SETTLE_MARGIN_MS });
8583
8638
  if (native.success) {
8639
+ settleAxFailures = 0;
8584
8640
  if (expected !== undefined && native.data.reason !== "frontmost_mismatch")
8585
8641
  launchedBundle = undefined;
8586
8642
  return { success: true, data: nativeDetail(native.data) };
@@ -8592,6 +8648,8 @@ function createIosDriver(swap, simctl, opts) {
8592
8648
  data: { quiet: false, waitedMs: timeoutMs + SETTLE_MARGIN_MS, reason: "helper_timeout" }
8593
8649
  };
8594
8650
  }
8651
+ if (native.error.code === "E_AX_UNAVAILABLE")
8652
+ return noteSettleAxFailure(native.error.message);
8595
8653
  if (native.error.code !== "E_UNSUPPORTED")
8596
8654
  return native;
8597
8655
  settleUnsupported = true;
@@ -16,6 +16,7 @@ import { type SwappableClient } from "./ios-session";
16
16
  import { type IosSettings, type StagedSettings } from "./ios-settings";
17
17
  import { type Simctl } from "./simctl";
18
18
  import { type SimdClient } from "./simd-client";
19
+ import type { HealthData } from "./simd-protocol";
19
20
  import type { SimdSpawn } from "./simd-transport";
20
21
  /**
21
22
  * The iOS `Driver`: input, AX and app launch / terminate / openUrl through `warden-simd` (socket when
@@ -83,6 +84,10 @@ export type OpenIosDriverOptions = {
83
84
  };
84
85
  /** USB HID keyboard-page usage ids for the keys `Driver.key` offers. */
85
86
  export declare const KEY_USAGE: Readonly<Record<KeyName, number>>;
87
+ /** The fields of a failed snapshot's `detail` the helper sets (which reader, why, both readers' errors), on its span. */
88
+ export declare function noteSnapshotError(detail: unknown): void;
89
+ /** What the helper says about itself after a failed read: bridge state, host vs build Xcode, CoreSimulator. */
90
+ export declare function noteHelperHealth(health: HealthData): void;
86
91
  export declare function createIosDriver(swap: SwappableClient, simctl: Simctl, opts: {
87
92
  udid: string;
88
93
  now: () => number;
@@ -183,6 +183,15 @@ export declare const healthDataSchema: z.ZodObject<{
183
183
  }, z.core.$strip>>;
184
184
  idb: z.ZodOptional<z.ZodString>;
185
185
  xcode: z.ZodOptional<z.ZodString>;
186
+ builtWith: z.ZodOptional<z.ZodObject<{
187
+ xcode: z.ZodOptional<z.ZodString>;
188
+ idb: z.ZodOptional<z.ZodString>;
189
+ }, z.core.$strip>>;
190
+ coreSimulatorVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
191
+ frontmost: z.ZodOptional<z.ZodObject<{
192
+ unresolvedAgoMs: z.ZodNumber;
193
+ method: z.ZodString;
194
+ }, z.core.$strip>>;
186
195
  state: z.ZodOptional<z.ZodString>;
187
196
  uptimeMs: z.ZodOptional<z.ZodNumber>;
188
197
  }, z.core.$loose>;
@@ -206,6 +215,10 @@ export declare const snapshotDataSchema: z.ZodObject<{
206
215
  to: z.ZodString;
207
216
  reason: z.ZodString;
208
217
  }, z.core.$strip>>;
218
+ target: z.ZodOptional<z.ZodObject<{
219
+ pid: z.ZodNumber;
220
+ source: z.ZodString;
221
+ }, z.core.$strip>>;
209
222
  readMs: z.ZodOptional<z.ZodNumber>;
210
223
  nodes: z.ZodOptional<z.ZodNumber>;
211
224
  }, z.core.$loose>;
@@ -340,6 +353,15 @@ export declare const opSchemas: {
340
353
  }, z.core.$strip>>;
341
354
  idb: z.ZodOptional<z.ZodString>;
342
355
  xcode: z.ZodOptional<z.ZodString>;
356
+ builtWith: z.ZodOptional<z.ZodObject<{
357
+ xcode: z.ZodOptional<z.ZodString>;
358
+ idb: z.ZodOptional<z.ZodString>;
359
+ }, z.core.$strip>>;
360
+ coreSimulatorVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
361
+ frontmost: z.ZodOptional<z.ZodObject<{
362
+ unresolvedAgoMs: z.ZodNumber;
363
+ method: z.ZodString;
364
+ }, z.core.$strip>>;
343
365
  state: z.ZodOptional<z.ZodString>;
344
366
  uptimeMs: z.ZodOptional<z.ZodNumber>;
345
367
  }, z.core.$loose>;
@@ -362,6 +384,10 @@ export declare const opSchemas: {
362
384
  to: z.ZodString;
363
385
  reason: z.ZodString;
364
386
  }, z.core.$strip>>;
387
+ target: z.ZodOptional<z.ZodObject<{
388
+ pid: z.ZodNumber;
389
+ source: z.ZodString;
390
+ }, z.core.$strip>>;
365
391
  readMs: z.ZodOptional<z.ZodNumber>;
366
392
  nodes: z.ZodOptional<z.ZodNumber>;
367
393
  }, z.core.$loose>;