rnxsim 0.1.447 → 0.1.449

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.
Files changed (53) hide show
  1. package/cli/bridge-flow-runner.ts +43 -59
  2. package/detox/expectations.ts +4 -11
  3. package/dist-lib/agent-daemon-client.cjs +1 -1
  4. package/dist-lib/agent-events.cjs +1 -1
  5. package/dist-lib/agent-identity.cjs +1 -1
  6. package/dist-lib/agent-sessions.cjs +1 -1
  7. package/dist-lib/attached-projects.cjs +1 -1
  8. package/dist-lib/auth/shared-session.cjs +1 -1
  9. package/dist-lib/backend-origin.cjs +1 -1
  10. package/dist-lib/beta.cjs +1 -1
  11. package/dist-lib/beta.mjs +1 -1
  12. package/dist-lib/bridge-constants.cjs +1 -1
  13. package/dist-lib/bridge-contract-input.cjs +1 -1
  14. package/dist-lib/bridge-contract-input.mjs +1 -1
  15. package/dist-lib/bridge-contract.cjs +1 -1
  16. package/dist-lib/bridge-contract.mjs +1 -1
  17. package/dist-lib/capture-contract.cjs +1 -1
  18. package/dist-lib/capture-contract.mjs +1 -1
  19. package/dist-lib/cli-constants.cjs +1 -1
  20. package/dist-lib/cloud-contract.cjs +1 -1
  21. package/dist-lib/cloud-contract.mjs +1 -1
  22. package/dist-lib/cloud.cjs +1 -1
  23. package/dist-lib/cloud.mjs +1 -1
  24. package/dist-lib/config.cjs +1 -1
  25. package/dist-lib/detox/index.cjs +3 -4
  26. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  27. package/dist-lib/home-paths.cjs +1 -1
  28. package/dist-lib/host/bridge-host.cjs +1 -1
  29. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  30. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  31. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  32. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  33. package/dist-lib/host/websocket-proxy.cjs +1 -1
  34. package/dist-lib/index.cjs +1 -1
  35. package/dist-lib/jump-to-source-babel.cjs +1 -1
  36. package/dist-lib/menu.cjs +1 -1
  37. package/dist-lib/menu.mjs +1 -1
  38. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  39. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  40. package/dist-lib/metro-production-bundle.cjs +1 -1
  41. package/dist-lib/metro-production-bundle.mjs +1 -1
  42. package/dist-lib/metro.cjs +1 -1
  43. package/dist-lib/profiles.cjs +1 -1
  44. package/dist-lib/public-brand.cjs +1 -1
  45. package/dist-lib/react-native-host-modules.cjs +1 -1
  46. package/dist-lib/react-native-host-modules.mjs +1 -1
  47. package/dist-lib/render-mode.cjs +1 -1
  48. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  49. package/dist-lib/sdk.cjs +1 -1
  50. package/dist-lib/sdk.mjs +1 -1
  51. package/dist-lib/skills.cjs +33 -35
  52. package/dist-lib/vite.cjs +1 -1
  53. package/package.json +1 -1
@@ -719,25 +719,17 @@ export class SootSimBridgeFlowRunner {
719
719
  )
720
720
  }
721
721
 
722
- private async findElement(opts: {
723
- text?: string
724
- id?: string
725
- index?: number
726
- childOf?: { id?: string; text?: string }
727
- }) {
728
- // scoped matchers (maestro `index:` / `childOf:`) need the FULL candidate
729
- // set, not the single best match findByText/findByTestId return. route them
730
- // through queryAll: collect every match, optionally keep only those inside
731
- // the childOf container's bounds (geometric containment mirrors "the X
732
- // inside post Y" for vertically-stacked lists), then pick the nth.
733
- if (opts.childOf != null || typeof opts.index === 'number') {
722
+ private async findElement(opts: FlowTargetSelector) {
723
+ // patterns and combined selectors need the full candidate set so id and
724
+ // text constrain the same node. literal single selectors keep the direct lookup.
725
+ if (
726
+ opts.childOf != null ||
727
+ typeof opts.index === 'number' ||
728
+ (opts.id && opts.text) ||
729
+ [opts.id, opts.text].some((value) => value && /[.*+?^$()[\]{}|\\]/.test(value))
730
+ ) {
734
731
  return this.findElementScoped(opts)
735
732
  }
736
- // maestro text selectors are REGEXPs (e.g. "users[,]? or feeds",
737
- // ".*Reply 1.*"). only treat a selector as a pattern when it carries regex
738
- // metacharacters AND the literal/a11y-label lookups miss, so ordinary copy
739
- // ("Repost") never accidentally over-matches via regex.
740
- const wantRegex = !!opts.text && /[.*+?^$()[\]{}|\\]/.test(opts.text)
741
733
  return this.evaluate<any>(`(async () => {
742
734
  const test = window.__sootsimTest
743
735
  if (!test) return null
@@ -762,23 +754,6 @@ export class SootSimBridgeFlowRunner {
762
754
  labelled
763
755
  }
764
756
  }
765
- if (!node && ${JSON.stringify(wantRegex)} && test.queryAll) {
766
- // regex selector fallback: match the pattern against each visible
767
- // node's text; prefer the narrowest matching node so a tight <text>
768
- // wins over a wide container that merely contains it.
769
- let re = null
770
- try { re = new RegExp(${JSON.stringify(opts.text || '')}) } catch (e) { re = null }
771
- if (re) {
772
- const all = (await test.queryAll({ pruneHidden: true })) || []
773
- const hits = all.filter(
774
- (n) =>
775
- n && n.absolutePosition && n.layout &&
776
- typeof n.text === 'string' && re.test(n.text),
777
- )
778
- hits.sort((a, b) => (a.text || '').length - (b.text || '').length)
779
- if (hits[0]) node = hits[0]
780
- }
781
- }
782
757
  }
783
758
  if (!node && ${JSON.stringify(!!opts.id)}) {
784
759
  node = (await test.findByTestId(${JSON.stringify(opts.id || '')})) || (await test.findById(${JSON.stringify(opts.id || '')}))
@@ -799,30 +774,32 @@ export class SootSimBridgeFlowRunner {
799
774
  // maestro `index:` (nth match) and `childOf:` (match scoped to a container)
800
775
  // resolver. queryAll returns every matching node in tree order; childOf keeps
801
776
  // only candidates whose center sits inside the container's bounds.
802
- private async findElementScoped(opts: {
803
- text?: string
804
- id?: string
805
- index?: number
806
- childOf?: { id?: string; text?: string }
807
- }) {
777
+ private async findElementScoped(opts: FlowTargetSelector) {
808
778
  const index = typeof opts.index === 'number' ? opts.index : 0
809
779
  return this.evaluate<any>(`(async () => {
810
780
  const test = window.__sootsimTest
811
781
  if (!test || !test.queryAll) return null
812
- // NOT pruneHidden: that over-filters (it dropped every postDropdownBtn in a
813
- // feed and made index:0 resolve to nothing — worse than findByTestId). reach
814
- // for the same set findByTestId sees, then PREFER on-screen ones below.
815
- const filter = {}
816
- if (${JSON.stringify(!!opts.id)}) filter.hasId = ${JSON.stringify(opts.id || '')}
817
- if (${JSON.stringify(!!opts.text)}) filter.hasText = ${JSON.stringify(opts.text || '')}
818
- let candidates = (await test.queryAll(filter)) || []
819
- // a11y-label fallback (icon-only buttons) for text matchers, mirroring
820
- // findElement's simple path.
821
- if (${JSON.stringify(!!opts.text)} && candidates.length === 0) {
822
- const all = (await test.queryAll({})) || []
823
- candidates = all.filter((n) => (n.accessibilityLabel || '') === ${JSON.stringify(opts.text || '')})
824
- }
825
- candidates = candidates.filter((n) => n && n.absolutePosition && n.layout)
782
+ const compile = (value) => {
783
+ if (!value) return null
784
+ let pattern = null
785
+ try { pattern = new RegExp(value) } catch {}
786
+ return (candidate) => typeof candidate === 'string' &&
787
+ (candidate === value || !!pattern?.test(candidate))
788
+ }
789
+ const matchesId = compile(${JSON.stringify(opts.id)})
790
+ const matchesText = compile(${JSON.stringify(opts.text)})
791
+ const all = ((await test.queryAll({})) || []).filter(
792
+ (n) => n && n.absolutePosition && n.layout,
793
+ )
794
+ let candidates = all.filter((n) =>
795
+ (!matchesId || matchesId(n.testID) || matchesId(n.id)) &&
796
+ (!matchesText || matchesText(n.text) || matchesText(n.accessibilityLabel)),
797
+ )
798
+ const literalText = candidates.filter((n) =>
799
+ n.text === ${JSON.stringify(opts.text)} ||
800
+ n.accessibilityLabel === ${JSON.stringify(opts.text)},
801
+ )
802
+ if (matchesText && literalText.length > 0) candidates = literalText
826
803
  // prefer on-screen matches (findByTestId's visible-first behavior); only
827
804
  // fall back to off-screen ones when nothing is on-screen, so index: still
828
805
  // resolves a target that needs scrolling into view.
@@ -834,11 +811,12 @@ export class SootSimBridgeFlowRunner {
834
811
  ${
835
812
  opts.childOf
836
813
  ? `
837
- const container = ${
838
- opts.childOf.id
839
- ? `(await test.findByTestId(${JSON.stringify(opts.childOf.id)})) || (await test.findById(${JSON.stringify(opts.childOf.id)}))`
840
- : `await test.findByText(${JSON.stringify(opts.childOf.text || '')})`
841
- }
814
+ const matchesContainerId = compile(${JSON.stringify(opts.childOf.id)})
815
+ const matchesContainerText = compile(${JSON.stringify(opts.childOf.text)})
816
+ const container = all.find((n) =>
817
+ (!matchesContainerId || matchesContainerId(n.testID) || matchesContainerId(n.id)) &&
818
+ (!matchesContainerText || matchesContainerText(n.text) || matchesContainerText(n.accessibilityLabel)),
819
+ )
842
820
  if (!container || !container.absolutePosition || !container.layout) return null
843
821
  const x0 = container.absolutePosition.x
844
822
  const y0 = container.absolutePosition.y
@@ -851,6 +829,9 @@ export class SootSimBridgeFlowRunner {
851
829
  })`
852
830
  : ''
853
831
  }
832
+ if (${JSON.stringify(opts.index === undefined && !!opts.text && !opts.id)}) {
833
+ candidates.sort((a, b) => (a.text || '').length - (b.text || '').length)
834
+ }
854
835
  const node = candidates[${index}]
855
836
  if (!node) return null
856
837
  return {
@@ -1922,6 +1903,9 @@ export class SootSimBridgeFlowRunner {
1922
1903
  if (!this.firstLaunchDone) {
1923
1904
  this.firstLaunchDone = true
1924
1905
  if (wantsClear) {
1906
+ // bundle evaluation temporarily installs a reload bridge without the
1907
+ // storage contract. wait for the app before its first data reset.
1908
+ if (!this.appStopped) await this.waitForTree(120000)
1925
1909
  await this.resetGuestAppData({
1926
1910
  launchArguments: hasLaunchArguments ? launchArguments : null,
1927
1911
  initialUrl: null,
@@ -39,20 +39,13 @@ function scrollOffsetOf(node: any): { x: number; y: number } {
39
39
  return { x: node?.scrollOffsetX ?? 0, y: node?.scrollOffsetY ?? 0 }
40
40
  }
41
41
 
42
- // how much of the node is actually on screen, as a fraction of its own area.
43
- // the engine already intersects every node with each clipping ancestor and
44
- // with the device surface when it builds `visibleFrame`, so that rect is the
45
- // on-screen area and needs no further clipping here. intersecting it a second
46
- // time against the interactive viewport (screen minus the home indicator band)
47
- // used to fail views that were 84% and 93% on screen, because iOS draws the
48
- // home indicator over app content rather than hiding it, and Detox's own
49
- // visibility percentage on iOS is computed against the app window.
42
+ // the visible frame is the largest uncovered rectangle used for tapping.
43
+ // visibility includes every exposed region around overlays, not just that rectangle.
50
44
  function visibleFraction(node: SootSimNodeInfo | null | undefined): number {
51
45
  const totalArea = (node?.layout?.width ?? 0) * (node?.layout?.height ?? 0)
52
46
  const frame = node?.visibleFrame
53
- if (totalArea <= 0 || !frame) return 0
54
- const visibleArea = Math.max(0, frame.width) * Math.max(0, frame.height)
55
- return visibleArea / totalArea
47
+ if (totalArea <= 0 || typeof frame?.area !== 'number') return 0
48
+ return frame.area / totalArea
56
49
  }
57
50
 
58
51
  export function isNodeVisible(node: SootSimNodeInfo | null | undefined): boolean {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
package/dist-lib/beta.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
package/dist-lib/beta.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/beta.ts
4
4
  var IS_BETA = true;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_MAX_MS = 5e3;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_DEFAULT_MS = 500;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/capture-contract.ts
4
4
  var RNX_SCREEN_CAPTURE_VERSION = 1;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-contract.ts
4
4
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1181,9 +1181,8 @@ function scrollOffsetOf(node) {
1181
1181
  function visibleFraction(node) {
1182
1182
  const totalArea = (node?.layout?.width ?? 0) * (node?.layout?.height ?? 0);
1183
1183
  const frame = node?.visibleFrame;
1184
- if (totalArea <= 0 || !frame) return 0;
1185
- const visibleArea = Math.max(0, frame.width) * Math.max(0, frame.height);
1186
- return visibleArea / totalArea;
1184
+ if (totalArea <= 0 || typeof frame?.area !== "number") return 0;
1185
+ return frame.area / totalArea;
1187
1186
  }
1188
1187
  function isNodeVisible(node) {
1189
1188
  return visibleFraction(node) >= DEFAULT_VISIBILITY_THRESHOLD;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/host/fetch-proxy-overrides.ts
4
4
  var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
package/dist-lib/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
package/dist-lib/menu.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "rnx";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-fingerprint-registry.ts
4
4
  var RNX_METRO_FINGERPRINT_SCHEMA_VERSION = 2;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/react-native-host-modules.ts
4
4
  var REACT_NATIVE_PASSTHROUGH_SPECIFIERS = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
package/dist-lib/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
package/dist-lib/sdk.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -32174,10 +32174,9 @@ var init_bridge_flow_runner = __esm({
32174
32174
  );
32175
32175
  }
32176
32176
  async findElement(opts) {
32177
- if (opts.childOf != null || typeof opts.index === "number") {
32177
+ if (opts.childOf != null || typeof opts.index === "number" || opts.id && opts.text || [opts.id, opts.text].some((value) => value && /[.*+?^$()[\]{}|\\]/.test(value))) {
32178
32178
  return this.findElementScoped(opts);
32179
32179
  }
32180
- const wantRegex = !!opts.text && /[.*+?^$()[\]{}|\\]/.test(opts.text);
32181
32180
  return this.evaluate(`(async () => {
32182
32181
  const test = window.__sootsimTest
32183
32182
  if (!test) return null
@@ -32202,23 +32201,6 @@ var init_bridge_flow_runner = __esm({
32202
32201
  labelled
32203
32202
  }
32204
32203
  }
32205
- if (!node && ${JSON.stringify(wantRegex)} && test.queryAll) {
32206
- // regex selector fallback: match the pattern against each visible
32207
- // node's text; prefer the narrowest matching node so a tight <text>
32208
- // wins over a wide container that merely contains it.
32209
- let re = null
32210
- try { re = new RegExp(${JSON.stringify(opts.text || "")}) } catch (e) { re = null }
32211
- if (re) {
32212
- const all = (await test.queryAll({ pruneHidden: true })) || []
32213
- const hits = all.filter(
32214
- (n) =>
32215
- n && n.absolutePosition && n.layout &&
32216
- typeof n.text === 'string' && re.test(n.text),
32217
- )
32218
- hits.sort((a, b) => (a.text || '').length - (b.text || '').length)
32219
- if (hits[0]) node = hits[0]
32220
- }
32221
- }
32222
32204
  }
32223
32205
  if (!node && ${JSON.stringify(!!opts.id)}) {
32224
32206
  node = (await test.findByTestId(${JSON.stringify(opts.id || "")})) || (await test.findById(${JSON.stringify(opts.id || "")}))
@@ -32243,20 +32225,27 @@ var init_bridge_flow_runner = __esm({
32243
32225
  return this.evaluate(`(async () => {
32244
32226
  const test = window.__sootsimTest
32245
32227
  if (!test || !test.queryAll) return null
32246
- // NOT pruneHidden: that over-filters (it dropped every postDropdownBtn in a
32247
- // feed and made index:0 resolve to nothing \u2014 worse than findByTestId). reach
32248
- // for the same set findByTestId sees, then PREFER on-screen ones below.
32249
- const filter = {}
32250
- if (${JSON.stringify(!!opts.id)}) filter.hasId = ${JSON.stringify(opts.id || "")}
32251
- if (${JSON.stringify(!!opts.text)}) filter.hasText = ${JSON.stringify(opts.text || "")}
32252
- let candidates = (await test.queryAll(filter)) || []
32253
- // a11y-label fallback (icon-only buttons) for text matchers, mirroring
32254
- // findElement's simple path.
32255
- if (${JSON.stringify(!!opts.text)} && candidates.length === 0) {
32256
- const all = (await test.queryAll({})) || []
32257
- candidates = all.filter((n) => (n.accessibilityLabel || '') === ${JSON.stringify(opts.text || "")})
32258
- }
32259
- candidates = candidates.filter((n) => n && n.absolutePosition && n.layout)
32228
+ const compile = (value) => {
32229
+ if (!value) return null
32230
+ let pattern = null
32231
+ try { pattern = new RegExp(value) } catch {}
32232
+ return (candidate) => typeof candidate === 'string' &&
32233
+ (candidate === value || !!pattern?.test(candidate))
32234
+ }
32235
+ const matchesId = compile(${JSON.stringify(opts.id)})
32236
+ const matchesText = compile(${JSON.stringify(opts.text)})
32237
+ const all = ((await test.queryAll({})) || []).filter(
32238
+ (n) => n && n.absolutePosition && n.layout,
32239
+ )
32240
+ let candidates = all.filter((n) =>
32241
+ (!matchesId || matchesId(n.testID) || matchesId(n.id)) &&
32242
+ (!matchesText || matchesText(n.text) || matchesText(n.accessibilityLabel)),
32243
+ )
32244
+ const literalText = candidates.filter((n) =>
32245
+ n.text === ${JSON.stringify(opts.text)} ||
32246
+ n.accessibilityLabel === ${JSON.stringify(opts.text)},
32247
+ )
32248
+ if (matchesText && literalText.length > 0) candidates = literalText
32260
32249
  // prefer on-screen matches (findByTestId's visible-first behavior); only
32261
32250
  // fall back to off-screen ones when nothing is on-screen, so index: still
32262
32251
  // resolves a target that needs scrolling into view.
@@ -32266,7 +32255,12 @@ var init_bridge_flow_runner = __esm({
32266
32255
  })
32267
32256
  if (onScreen.length > 0) candidates = onScreen
32268
32257
  ${opts.childOf ? `
32269
- const container = ${opts.childOf.id ? `(await test.findByTestId(${JSON.stringify(opts.childOf.id)})) || (await test.findById(${JSON.stringify(opts.childOf.id)}))` : `await test.findByText(${JSON.stringify(opts.childOf.text || "")})`}
32258
+ const matchesContainerId = compile(${JSON.stringify(opts.childOf.id)})
32259
+ const matchesContainerText = compile(${JSON.stringify(opts.childOf.text)})
32260
+ const container = all.find((n) =>
32261
+ (!matchesContainerId || matchesContainerId(n.testID) || matchesContainerId(n.id)) &&
32262
+ (!matchesContainerText || matchesContainerText(n.text) || matchesContainerText(n.accessibilityLabel)),
32263
+ )
32270
32264
  if (!container || !container.absolutePosition || !container.layout) return null
32271
32265
  const x0 = container.absolutePosition.x
32272
32266
  const y0 = container.absolutePosition.y
@@ -32277,6 +32271,9 @@ var init_bridge_flow_runner = __esm({
32277
32271
  const cy = n.absolutePosition.y + n.layout.height / 2
32278
32272
  return cx >= x0 && cx <= x1 && cy >= y0 && cy <= y1
32279
32273
  })` : ""}
32274
+ if (${JSON.stringify(opts.index === void 0 && !!opts.text && !opts.id)}) {
32275
+ candidates.sort((a, b) => (a.text || '').length - (b.text || '').length)
32276
+ }
32280
32277
  const node = candidates[${index}]
32281
32278
  if (!node) return null
32282
32279
  return {
@@ -33071,6 +33068,7 @@ var init_bridge_flow_runner = __esm({
33071
33068
  if (!this.firstLaunchDone) {
33072
33069
  this.firstLaunchDone = true;
33073
33070
  if (wantsClear) {
33071
+ if (!this.appStopped) await this.waitForTree(12e4);
33074
33072
  await this.resetGuestAppData({
33075
33073
  launchArguments: hasLaunchArguments ? launchArguments : null,
33076
33074
  initialUrl: null
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.447 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.449 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnxsim",
3
- "version": "0.1.447",
3
+ "version": "0.1.449",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for rnx.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",