@react-native-harness/runtime 1.1.0 → 1.2.0-rc.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.
Files changed (191) hide show
  1. package/dist/NativeHarness.d.ts +41 -0
  2. package/dist/NativeHarness.d.ts.map +1 -0
  3. package/dist/NativeHarness.js +2 -0
  4. package/dist/constants.d.ts +2 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/constants.js +1 -0
  7. package/dist/expect/context.d.ts +20 -0
  8. package/dist/expect/context.d.ts.map +1 -0
  9. package/dist/expect/context.js +6 -0
  10. package/dist/expect/errors.d.ts +3 -0
  11. package/dist/expect/errors.d.ts.map +1 -0
  12. package/dist/expect/errors.js +45 -0
  13. package/dist/expect/expect.d.ts.map +1 -1
  14. package/dist/expect/expect.js +6 -1
  15. package/dist/render/queries.d.ts +7 -0
  16. package/dist/render/queries.d.ts.map +1 -0
  17. package/dist/render/queries.js +99 -0
  18. package/dist/runHarnessTestsInModule.d.ts +9 -0
  19. package/dist/runHarnessTestsInModule.d.ts.map +1 -0
  20. package/dist/runHarnessTestsInModule.js +57 -0
  21. package/dist/runner/runSuite.d.ts.map +1 -1
  22. package/dist/runner/runSuite.js +16 -6
  23. package/dist/screen/index.d.ts +50 -0
  24. package/dist/screen/index.d.ts.map +1 -0
  25. package/dist/screen/index.js +46 -0
  26. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  27. package/dist/userEvent/index.d.ts +16 -0
  28. package/dist/userEvent/index.d.ts.map +1 -0
  29. package/dist/userEvent/index.js +31 -0
  30. package/dist/utils/hmr.d.ts +2 -0
  31. package/dist/utils/hmr.d.ts.map +1 -0
  32. package/dist/utils/hmr.js +3 -0
  33. package/dist/utils/parse-error-stack.d.ts +9 -0
  34. package/dist/utils/parse-error-stack.d.ts.map +1 -0
  35. package/dist/utils/parse-error-stack.js +56 -0
  36. package/out-tsc/vitest/src/__tests__/collector.test.d.ts +2 -0
  37. package/out-tsc/vitest/src/__tests__/collector.test.d.ts.map +1 -0
  38. package/out-tsc/vitest/src/__tests__/error-handling.test.d.ts +2 -0
  39. package/out-tsc/vitest/src/__tests__/error-handling.test.d.ts.map +1 -0
  40. package/out-tsc/vitest/src/__tests__/expect.test.d.ts +2 -0
  41. package/out-tsc/vitest/src/__tests__/expect.test.d.ts.map +1 -0
  42. package/out-tsc/vitest/src/__tests__/initialize.test.d.ts +2 -0
  43. package/out-tsc/vitest/src/__tests__/initialize.test.d.ts.map +1 -0
  44. package/out-tsc/vitest/src/__tests__/spy.test.d.ts +2 -0
  45. package/out-tsc/vitest/src/__tests__/spy.test.d.ts.map +1 -0
  46. package/out-tsc/vitest/src/bundler/bundle.d.ts +2 -0
  47. package/out-tsc/vitest/src/bundler/bundle.d.ts.map +1 -0
  48. package/out-tsc/vitest/src/bundler/errors.d.ts +15 -0
  49. package/out-tsc/vitest/src/bundler/errors.d.ts.map +1 -0
  50. package/out-tsc/vitest/src/bundler/evaluate.d.ts +2 -0
  51. package/out-tsc/vitest/src/bundler/evaluate.d.ts.map +1 -0
  52. package/out-tsc/vitest/src/bundler/factory.d.ts +3 -0
  53. package/out-tsc/vitest/src/bundler/factory.d.ts.map +1 -0
  54. package/out-tsc/vitest/src/bundler/index.d.ts +4 -0
  55. package/out-tsc/vitest/src/bundler/index.d.ts.map +1 -0
  56. package/out-tsc/vitest/src/bundler/types.d.ts +7 -0
  57. package/out-tsc/vitest/src/bundler/types.d.ts.map +1 -0
  58. package/out-tsc/vitest/src/client/factory.d.ts +2 -0
  59. package/out-tsc/vitest/src/client/factory.d.ts.map +1 -0
  60. package/out-tsc/vitest/src/client/getDeviceDescriptor.d.ts +8 -0
  61. package/out-tsc/vitest/src/client/getDeviceDescriptor.d.ts.map +1 -0
  62. package/out-tsc/vitest/src/client/getWSServer.d.ts +2 -0
  63. package/out-tsc/vitest/src/client/getWSServer.d.ts.map +1 -0
  64. package/out-tsc/vitest/src/client/getWSServer.test.d.ts +2 -0
  65. package/out-tsc/vitest/src/client/getWSServer.test.d.ts.map +1 -0
  66. package/out-tsc/vitest/src/client/index.d.ts +2 -0
  67. package/out-tsc/vitest/src/client/index.d.ts.map +1 -0
  68. package/out-tsc/vitest/src/client/setup-files.d.ts +12 -0
  69. package/out-tsc/vitest/src/client/setup-files.d.ts.map +1 -0
  70. package/out-tsc/vitest/src/client/store.d.ts +4 -0
  71. package/out-tsc/vitest/src/client/store.d.ts.map +1 -0
  72. package/out-tsc/vitest/src/collector/errors.d.ts +8 -0
  73. package/out-tsc/vitest/src/collector/errors.d.ts.map +1 -0
  74. package/out-tsc/vitest/src/collector/factory.d.ts +3 -0
  75. package/out-tsc/vitest/src/collector/factory.d.ts.map +1 -0
  76. package/out-tsc/vitest/src/collector/functions.d.ts +22 -0
  77. package/out-tsc/vitest/src/collector/functions.d.ts.map +1 -0
  78. package/out-tsc/vitest/src/collector/index.d.ts +5 -0
  79. package/out-tsc/vitest/src/collector/index.d.ts.map +1 -0
  80. package/out-tsc/vitest/src/collector/types.d.ts +10 -0
  81. package/out-tsc/vitest/src/collector/types.d.ts.map +1 -0
  82. package/out-tsc/vitest/src/collector/validation.d.ts +4 -0
  83. package/out-tsc/vitest/src/collector/validation.d.ts.map +1 -0
  84. package/out-tsc/vitest/src/constants.d.ts +2 -0
  85. package/out-tsc/vitest/src/constants.d.ts.map +1 -0
  86. package/out-tsc/vitest/src/disableHMRWhenReady.d.ts +2 -0
  87. package/out-tsc/vitest/src/disableHMRWhenReady.d.ts.map +1 -0
  88. package/out-tsc/vitest/src/disableHMRWhenReady.test.d.ts +2 -0
  89. package/out-tsc/vitest/src/disableHMRWhenReady.test.d.ts.map +1 -0
  90. package/out-tsc/vitest/src/entry-point.d.ts +2 -0
  91. package/out-tsc/vitest/src/entry-point.d.ts.map +1 -0
  92. package/out-tsc/vitest/src/errors.d.ts +6 -0
  93. package/out-tsc/vitest/src/errors.d.ts.map +1 -0
  94. package/out-tsc/vitest/src/expect/context.d.ts +20 -0
  95. package/out-tsc/vitest/src/expect/context.d.ts.map +1 -0
  96. package/out-tsc/vitest/src/expect/errors.d.ts +3 -0
  97. package/out-tsc/vitest/src/expect/errors.d.ts.map +1 -0
  98. package/out-tsc/vitest/src/expect/expect.d.ts +9 -0
  99. package/out-tsc/vitest/src/expect/expect.d.ts.map +1 -0
  100. package/out-tsc/vitest/src/expect/index.d.ts +2 -0
  101. package/out-tsc/vitest/src/expect/index.d.ts.map +1 -0
  102. package/out-tsc/vitest/src/expect/matchers/toMatchImageSnapshot.d.ts +13 -0
  103. package/out-tsc/vitest/src/expect/matchers/toMatchImageSnapshot.d.ts.map +1 -0
  104. package/out-tsc/vitest/src/expect/setup.d.ts +2 -0
  105. package/out-tsc/vitest/src/expect/setup.d.ts.map +1 -0
  106. package/out-tsc/vitest/src/filtering/index.d.ts +2 -0
  107. package/out-tsc/vitest/src/filtering/index.d.ts.map +1 -0
  108. package/out-tsc/vitest/src/filtering/testNameFilter.d.ts +12 -0
  109. package/out-tsc/vitest/src/filtering/testNameFilter.d.ts.map +1 -0
  110. package/out-tsc/vitest/src/globals.d.ts +19 -0
  111. package/out-tsc/vitest/src/globals.d.ts.map +1 -0
  112. package/out-tsc/vitest/src/index.d.ts +12 -0
  113. package/out-tsc/vitest/src/index.d.ts.map +1 -0
  114. package/out-tsc/vitest/src/initialize.d.ts +2 -0
  115. package/out-tsc/vitest/src/initialize.d.ts.map +1 -0
  116. package/out-tsc/vitest/src/jest-mock.d.ts +2 -0
  117. package/out-tsc/vitest/src/jest-mock.d.ts.map +1 -0
  118. package/out-tsc/vitest/src/jsx/jsx-dev-runtime.d.ts +3 -0
  119. package/out-tsc/vitest/src/jsx/jsx-dev-runtime.d.ts.map +1 -0
  120. package/out-tsc/vitest/src/jsx/jsx-runtime.d.ts +6 -0
  121. package/out-tsc/vitest/src/jsx/jsx-runtime.d.ts.map +1 -0
  122. package/out-tsc/vitest/src/mocker/index.d.ts +2 -0
  123. package/out-tsc/vitest/src/mocker/index.d.ts.map +1 -0
  124. package/out-tsc/vitest/src/mocker/registry.d.ts +6 -0
  125. package/out-tsc/vitest/src/mocker/registry.d.ts.map +1 -0
  126. package/out-tsc/vitest/src/mocker/types.d.ts +6 -0
  127. package/out-tsc/vitest/src/mocker/types.d.ts.map +1 -0
  128. package/out-tsc/vitest/src/namespace.d.ts +18 -0
  129. package/out-tsc/vitest/src/namespace.d.ts.map +1 -0
  130. package/out-tsc/vitest/src/polyfills.d.ts +11 -0
  131. package/out-tsc/vitest/src/polyfills.d.ts.map +1 -0
  132. package/out-tsc/vitest/src/render/ErrorBoundary.d.ts +17 -0
  133. package/out-tsc/vitest/src/render/ErrorBoundary.d.ts.map +1 -0
  134. package/out-tsc/vitest/src/render/TestComponentOverlay.d.ts +3 -0
  135. package/out-tsc/vitest/src/render/TestComponentOverlay.d.ts.map +1 -0
  136. package/out-tsc/vitest/src/render/cleanup.d.ts +2 -0
  137. package/out-tsc/vitest/src/render/cleanup.d.ts.map +1 -0
  138. package/out-tsc/vitest/src/render/index.d.ts +6 -0
  139. package/out-tsc/vitest/src/render/index.d.ts.map +1 -0
  140. package/out-tsc/vitest/src/render/setup.d.ts +2 -0
  141. package/out-tsc/vitest/src/render/setup.d.ts.map +1 -0
  142. package/out-tsc/vitest/src/render/types.d.ts +12 -0
  143. package/out-tsc/vitest/src/render/types.d.ts.map +1 -0
  144. package/out-tsc/vitest/src/runner/context.d.ts +10 -0
  145. package/out-tsc/vitest/src/runner/context.d.ts.map +1 -0
  146. package/out-tsc/vitest/src/runner/errors.d.ts +11 -0
  147. package/out-tsc/vitest/src/runner/errors.d.ts.map +1 -0
  148. package/out-tsc/vitest/src/runner/factory.d.ts +3 -0
  149. package/out-tsc/vitest/src/runner/factory.d.ts.map +1 -0
  150. package/out-tsc/vitest/src/runner/hooks.d.ts +4 -0
  151. package/out-tsc/vitest/src/runner/hooks.d.ts.map +1 -0
  152. package/out-tsc/vitest/src/runner/index.d.ts +5 -0
  153. package/out-tsc/vitest/src/runner/index.d.ts.map +1 -0
  154. package/out-tsc/vitest/src/runner/runSuite.d.ts +7 -0
  155. package/out-tsc/vitest/src/runner/runSuite.d.ts.map +1 -0
  156. package/out-tsc/vitest/src/runner/types.d.ts +18 -0
  157. package/out-tsc/vitest/src/runner/types.d.ts.map +1 -0
  158. package/out-tsc/vitest/src/screen/index.d.ts +8 -0
  159. package/out-tsc/vitest/src/screen/index.d.ts.map +1 -0
  160. package/out-tsc/vitest/src/spy/index.d.ts +2 -0
  161. package/out-tsc/vitest/src/spy/index.d.ts.map +1 -0
  162. package/out-tsc/vitest/src/symbolicate.d.ts +17 -0
  163. package/out-tsc/vitest/src/symbolicate.d.ts.map +1 -0
  164. package/out-tsc/vitest/src/ui/ReadyScreen.d.ts +2 -0
  165. package/out-tsc/vitest/src/ui/ReadyScreen.d.ts.map +1 -0
  166. package/out-tsc/vitest/src/ui/RunnerScreen.d.ts +8 -0
  167. package/out-tsc/vitest/src/ui/RunnerScreen.d.ts.map +1 -0
  168. package/out-tsc/vitest/src/ui/WrongEnvironmentScreen.d.ts +2 -0
  169. package/out-tsc/vitest/src/ui/WrongEnvironmentScreen.d.ts.map +1 -0
  170. package/out-tsc/vitest/src/ui/images.d.ts +3 -0
  171. package/out-tsc/vitest/src/ui/images.d.ts.map +1 -0
  172. package/out-tsc/vitest/src/ui/index.d.ts +2 -0
  173. package/out-tsc/vitest/src/ui/index.d.ts.map +1 -0
  174. package/out-tsc/vitest/src/ui/state.d.ts +20 -0
  175. package/out-tsc/vitest/src/ui/state.d.ts.map +1 -0
  176. package/out-tsc/vitest/src/userEvent/index.d.ts +6 -0
  177. package/out-tsc/vitest/src/userEvent/index.d.ts.map +1 -0
  178. package/out-tsc/vitest/src/utils/dev-server.d.ts +2 -0
  179. package/out-tsc/vitest/src/utils/dev-server.d.ts.map +1 -0
  180. package/out-tsc/vitest/src/utils/emitter.d.ts +16 -0
  181. package/out-tsc/vitest/src/utils/emitter.d.ts.map +1 -0
  182. package/out-tsc/vitest/src/waitFor.d.ts +21 -0
  183. package/out-tsc/vitest/src/waitFor.d.ts.map +1 -0
  184. package/out-tsc/vitest/tsconfig.spec.tsbuildinfo +1 -0
  185. package/out-tsc/vitest/vite.config.d.ts +3 -0
  186. package/out-tsc/vitest/vite.config.d.ts.map +1 -0
  187. package/package.json +2 -2
  188. package/src/expect/context.ts +30 -0
  189. package/src/expect/errors.ts +76 -0
  190. package/src/expect/expect.ts +16 -5
  191. package/src/runner/runSuite.ts +25 -11
@@ -0,0 +1,41 @@
1
+ import { type TurboModule } from 'react-native';
2
+ /**
3
+ * Represents the position and dimensions of a view in screen coordinates (points/dp).
4
+ */
5
+ export interface ViewInfo {
6
+ x: number;
7
+ y: number;
8
+ width: number;
9
+ height: number;
10
+ }
11
+ interface Spec extends TurboModule {
12
+ /**
13
+ * Simulates a native tap at the specified screen coordinates.
14
+ * Returns a promise that resolves when the tap action is complete.
15
+ */
16
+ simulateTap(x: number, y: number): Promise<void>;
17
+ /**
18
+ * Finds a view by its testID (accessibilityIdentifier on iOS, tag on Android).
19
+ * Returns null if no view is found.
20
+ */
21
+ queryByTestId(testId: string): ViewInfo | null;
22
+ /**
23
+ * Finds all views by testID (accessibilityIdentifier on iOS, tag on Android).
24
+ * Returns an empty array if no views are found.
25
+ */
26
+ queryAllByTestId(testId: string): ViewInfo[];
27
+ /**
28
+ * Finds a view by its accessibility label.
29
+ * Returns null if no view is found.
30
+ */
31
+ queryByAccessibilityLabel(label: string): ViewInfo | null;
32
+ /**
33
+ * Finds all views by accessibility label.
34
+ * Returns an empty array if no views are found.
35
+ */
36
+ queryAllByAccessibilityLabel(label: string): ViewInfo[];
37
+ }
38
+ export type HarnessModule = Spec;
39
+ declare const _default: Spec;
40
+ export default _default;
41
+ //# sourceMappingURL=NativeHarness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeHarness.d.ts","sourceRoot":"","sources":["../src/NativeHarness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,IAAK,SAAQ,WAAW;IAChC;;;OAGG;IACH,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAE/C;;;OAGG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;IAE7C;;;OAGG;IACH,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAE1D;;;OAGG;IACH,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;CACzD;AAED,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC;;AAEjC,wBAAiE"}
@@ -0,0 +1,2 @@
1
+ import { TurboModuleRegistry } from 'react-native';
2
+ export default TurboModuleRegistry.getEnforcing('Harness');
@@ -0,0 +1,2 @@
1
+ export declare const WS_SERVER_PORT = 3001;
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,OAAO,CAAC"}
@@ -0,0 +1 @@
1
+ export const WS_SERVER_PORT = 3001;
@@ -0,0 +1,20 @@
1
+ type HarnessExpectError = {
2
+ name?: string;
3
+ message?: string;
4
+ stack?: string;
5
+ };
6
+ export type HarnessExpectTestState = {
7
+ result?: {
8
+ state: 'pass' | 'fail';
9
+ errors?: HarnessExpectError[];
10
+ };
11
+ promises?: Promise<unknown>[];
12
+ onFinished?: Array<() => void | Promise<void>>;
13
+ };
14
+ declare global {
15
+ var HARNESS_EXPECT_TEST_STATE: HarnessExpectTestState | undefined;
16
+ }
17
+ export declare const getCurrentExpectTestState: () => HarnessExpectTestState | undefined;
18
+ export declare const setCurrentExpectTestState: (state: HarnessExpectTestState | undefined) => void;
19
+ export {};
20
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/expect/context.ts"],"names":[],"mappings":"AAAA,KAAK,kBAAkB,GAAG;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;KAC/B,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAChD,CAAC;AAEF,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,yBAAyB,EAAE,sBAAsB,GAAG,SAAS,CAAC;CACnE;AAED,eAAO,MAAM,yBAAyB,QAClC,sBAAsB,GACtB,SAEH,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,OAAO,sBAAsB,GAAG,SAAS,KACxC,IAEF,CAAC"}
@@ -0,0 +1,6 @@
1
+ export const getCurrentExpectTestState = () => {
2
+ return globalThis.HARNESS_EXPECT_TEST_STATE;
3
+ };
4
+ export const setCurrentExpectTestState = (state) => {
5
+ globalThis.HARNESS_EXPECT_TEST_STATE = state;
6
+ };
@@ -0,0 +1,3 @@
1
+ import type { HarnessExpectTestState } from './context.js';
2
+ export declare const flushExpectTestState: (state: HarnessExpectTestState) => Promise<void>;
3
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/expect/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAgD3D,eAAO,MAAM,oBAAoB,GAC/B,OAAO,sBAAsB,KAC5B,OAAO,CAAC,IAAI,CAyBd,CAAC"}
@@ -0,0 +1,45 @@
1
+ const formatErrorMessage = (error) => {
2
+ if (error instanceof Error) {
3
+ return `${error.name}: ${error.message}`;
4
+ }
5
+ if (error && typeof error === 'object') {
6
+ const maybeError = error;
7
+ if (maybeError.name || maybeError.message) {
8
+ return [maybeError.name, maybeError.message].filter(Boolean).join(': ');
9
+ }
10
+ }
11
+ return String(error);
12
+ };
13
+ const createExpectError = (errors, title) => {
14
+ const message = [title, ...errors.map(formatErrorMessage)]
15
+ .filter(Boolean)
16
+ .join('\n\n');
17
+ const error = new Error(message);
18
+ const firstError = errors.find((value) => !!value && typeof value === 'object');
19
+ if (firstError?.name) {
20
+ error.name = firstError.name;
21
+ }
22
+ if (firstError?.stack) {
23
+ error.stack = firstError.stack.replace(/^([^\n]+)(\n|$)/, `${error.name}: ${message}$2`);
24
+ }
25
+ return error;
26
+ };
27
+ export const flushExpectTestState = async (state) => {
28
+ if (state.promises?.length) {
29
+ const results = await Promise.allSettled(state.promises);
30
+ const rejected = results
31
+ .filter((result) => result.status === 'rejected')
32
+ .map((result) => result.reason);
33
+ if (rejected.length > 0) {
34
+ throw createExpectError(rejected);
35
+ }
36
+ }
37
+ for (const hook of state.onFinished ?? []) {
38
+ await hook();
39
+ }
40
+ const softErrors = state.result?.errors ?? [];
41
+ if (softErrors.length === 0) {
42
+ return;
43
+ }
44
+ throw createExpectError(softErrors, 'Soft assertion failures:');
45
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect/expect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAa,YAAY,EAAgB,MAAM,gBAAgB,CAAC;AAS5E,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,YAAY,CAAC;AAGpB,wBAAgB,YAAY,IAAI,YAAY,CAwF3C;AAED,QAAA,MAAM,YAAY,EAAE,YAA6B,CAAC;AAQlD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,YAAY,IAAI,MAAM,EAAE,CAAC;AAExC,YAAY,EACV,SAAS,EACT,4BAA4B,EAC5B,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect/expect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAa,YAAY,EAAgB,MAAM,gBAAgB,CAAC;AAS5E,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B,OAAO,YAAY,CAAC;AAGpB,wBAAgB,YAAY,IAAI,YAAY,CAkG3C;AAED,QAAA,MAAM,YAAY,EAAE,YAA6B,CAAC;AAQlD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,YAAY,IAAI,MAAM,EAAE,CAAC;AAExC,YAAY,EACV,SAAS,EACT,4BAA4B,EAC5B,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,QAAQ,GACT,MAAM,gBAAgB,CAAC"}
@@ -3,13 +3,18 @@
3
3
  import { addCustomEqualityTesters, ASYMMETRIC_MATCHERS_OBJECT, customMatchers, getState, GLOBAL_EXPECT, setState, } from '@vitest/expect';
4
4
  import * as chai from 'chai';
5
5
  // Setup additional matchers
6
+ import { getCurrentExpectTestState } from './context.js';
6
7
  import './setup.js';
7
8
  import { toMatchImageSnapshot } from './matchers/toMatchImageSnapshot.js';
8
9
  export function createExpect() {
9
10
  const expect = ((value, message) => {
10
11
  const { assertionCalls } = getState(expect);
11
12
  setState({ assertionCalls: assertionCalls + 1 }, expect);
12
- return chai.expect(value, message);
13
+ const assertion = chai.expect(value, message);
14
+ const currentTest = getCurrentExpectTestState();
15
+ return currentTest && assertion.withTest
16
+ ? assertion.withTest(currentTest)
17
+ : assertion;
13
18
  });
14
19
  Object.assign(expect, chai.expect);
15
20
  Object.assign(expect, globalThis[ASYMMETRIC_MATCHERS_OBJECT]);
@@ -0,0 +1,7 @@
1
+ import { HostInstance } from 'react-native';
2
+ export declare const setRoot: (rootInstance: HostInstance) => void;
3
+ declare const queryByTestId: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default | null, queryAllByTestId: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default[], getByTestId: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default | null, getAllByTestId: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default[], findByTestId: (params: string) => Promise<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>, findAllByTestId: (params: string) => Promise<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default[]>;
4
+ declare const queryById: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default | null, queryAllById: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default[], getId: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default | null, getAllById: (params: string) => import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default[], findById: (params: string) => Promise<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>, findAllById: (params: string) => Promise<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default[]>;
5
+ export { queryByTestId, queryAllByTestId, getByTestId, getAllByTestId, findByTestId, findAllByTestId, };
6
+ export { queryById, queryAllById, getId, getAllById, findById, findAllById };
7
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/render/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAM5C,eAAO,MAAM,OAAO,GAAI,cAAc,YAAY,SAEjD,CAAC;AA6IF,QAAA,MACW,aAAa,8HACV,gBAAgB,yHACrB,WAAW,8HACR,cAAc,yHAChB,YAAY,gIACT,eAAe,gIAG3B,CAAC;AACF,QAAA,MACW,SAAS,8HACN,YAAY,yHACjB,KAAK,8HACF,UAAU,yHACZ,QAAQ,gIACL,WAAW,gIAC+B,CAAC;AAExD,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,eAAe,GAChB,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,99 @@
1
+ // import { store } from '../ui/state.js';
2
+ import { waitUntil } from '../waitFor.js';
3
+ let root = null;
4
+ export const setRoot = (rootInstance) => {
5
+ root = rootInstance;
6
+ };
7
+ const getRoot = () => {
8
+ const container = root;
9
+ if (!container) {
10
+ throw new Error('You need to render a component first!');
11
+ }
12
+ const ownerDocument = container.ownerDocument;
13
+ if (!ownerDocument) {
14
+ throw new Error('This feature is supported in React Native 0.82 and later!');
15
+ }
16
+ return ownerDocument.getRootNode();
17
+ };
18
+ const findNodeByPredicate = (predicate) => {
19
+ const queue = [getRoot()];
20
+ while (queue.length > 0) {
21
+ const node = queue.shift();
22
+ if (predicate(node)) {
23
+ return node;
24
+ }
25
+ for (const child of node.children) {
26
+ queue.push(child);
27
+ }
28
+ }
29
+ return null;
30
+ };
31
+ const findNodesByPredicate = (predicate) => {
32
+ const nodes = [];
33
+ const queue = [getRoot()];
34
+ while (queue.length > 0) {
35
+ const node = queue.shift();
36
+ if (predicate(node)) {
37
+ nodes.push(node);
38
+ }
39
+ for (const child of node.children) {
40
+ queue.push(child);
41
+ }
42
+ }
43
+ return nodes;
44
+ };
45
+ const getFiberOfHostInstance = (hostInstance) => {
46
+ // This should be considered as 'reaching into the implementation details' of React Native.
47
+ // Not perfect, but it's the only way to get the props of the host instance.
48
+ return (hostInstance
49
+ .__internalInstanceHandle || null);
50
+ };
51
+ const getPropsOfHostInstance = (hostInstance) => {
52
+ return getFiberOfHostInstance(hostInstance)?.memoizedProps || {};
53
+ };
54
+ const findBy = (predicate, options) => {
55
+ return waitUntil(() => findNodeByPredicate(predicate), options);
56
+ };
57
+ const findAllBy = (predicate, options) => {
58
+ return waitUntil(() => {
59
+ const nodes = findNodesByPredicate(predicate);
60
+ if (nodes.length === 0) {
61
+ return null;
62
+ }
63
+ return nodes;
64
+ }, options);
65
+ };
66
+ const queryBy = (predicate) => {
67
+ return findNodeByPredicate(predicate);
68
+ };
69
+ const queryAllBy = (predicate) => {
70
+ return findNodesByPredicate(predicate);
71
+ };
72
+ const getBy = (predicate) => {
73
+ const node = queryBy(predicate);
74
+ if (!node) {
75
+ throw new Error(`No node found with predicate ${predicate}`);
76
+ }
77
+ return node;
78
+ };
79
+ const getAllBy = (predicate) => {
80
+ const nodes = queryAllBy(predicate);
81
+ if (nodes.length === 0) {
82
+ throw new Error(`No nodes found with predicate ${predicate}`);
83
+ }
84
+ return nodes;
85
+ };
86
+ const createQueries = (predicate) => {
87
+ return {
88
+ findBy: (params) => findBy((node) => predicate(node, params)),
89
+ findAllBy: (params) => findAllBy((node) => predicate(node, params)),
90
+ queryBy: (params) => queryBy((node) => predicate(node, params)),
91
+ queryAllBy: (params) => queryAllBy((node) => predicate(node, params)),
92
+ getBy: (params) => getBy((node) => predicate(node, params)),
93
+ getAllBy: (params) => getAllBy((node) => predicate(node, params)),
94
+ };
95
+ };
96
+ const { queryBy: queryByTestId, queryAllBy: queryAllByTestId, getBy: getByTestId, getAllBy: getAllByTestId, findBy: findByTestId, findAllBy: findAllByTestId, } = createQueries((node, testId) => getPropsOfHostInstance(node).testID === testId);
97
+ const { queryBy: queryById, queryAllBy: queryAllById, getBy: getId, getAllBy: getAllById, findBy: findById, findAllBy: findAllById, } = createQueries((node, id) => node.id === id);
98
+ export { queryByTestId, queryAllByTestId, getByTestId, getAllByTestId, findByTestId, findAllByTestId, };
99
+ export { queryById, queryAllById, getId, getAllById, findById, findAllById };
@@ -0,0 +1,9 @@
1
+ import type { TestSuiteResult } from '@react-native-harness/bridge';
2
+ /**
3
+ * Runs tests from a specific module programmatically and returns the results.
4
+ *
5
+ * @param moduleId The require.resolveWeak call to the module, returning the module ID
6
+ * @returns The result of the test suite execution
7
+ */
8
+ export declare const runHarnessTestsInModule: (loader: () => unknown) => Promise<TestSuiteResult>;
9
+ //# sourceMappingURL=runHarnessTestsInModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runHarnessTestsInModule.d.ts","sourceRoot":"","sources":["../src/runHarnessTestsInModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,8BAA8B,CAAC;AAoCtC;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAClC,QAAQ,MAAM,OAAO,KACpB,OAAO,CAAC,eAAe,CAuBzB,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { collectTests } from './collector/functions.js';
2
+ import { runSuite } from './runner/runSuite.js';
3
+ import { getEmitter } from './utils/emitter.js';
4
+ const metroRequire = global.__r;
5
+ /**
6
+ * Patches the require function to clear the module cache for the first module that's going to be required after patching.
7
+ * @returns A function to unpatch the require function.
8
+ */
9
+ const patchRequire = () => {
10
+ let wasRootModuleRequired = false;
11
+ global.__r = (moduleId) => {
12
+ if (!wasRootModuleRequired) {
13
+ // The first module that's going to be required after patching will be the module with tests.
14
+ // We need to clear the module cache for this module, so it ends up re-evaluated.
15
+ const module = metroRequire.getModules().get(moduleId);
16
+ if (module) {
17
+ module.hasError = false;
18
+ module.error = undefined;
19
+ module.isInitialized = false;
20
+ }
21
+ }
22
+ wasRootModuleRequired = true;
23
+ return metroRequire(moduleId);
24
+ };
25
+ return () => {
26
+ global.__r = metroRequire;
27
+ };
28
+ };
29
+ /**
30
+ * Runs tests from a specific module programmatically and returns the results.
31
+ *
32
+ * @param moduleId The require.resolveWeak call to the module, returning the module ID
33
+ * @returns The result of the test suite execution
34
+ */
35
+ export const runHarnessTestsInModule = async (loader) => {
36
+ // 1. Collect tests by executing the loader
37
+ // This expects the loader to call describe/it/test functions which register to the global collector
38
+ const { testSuite } = await collectTests(async () => {
39
+ const unpatchRequire = patchRequire();
40
+ try {
41
+ await loader();
42
+ }
43
+ finally {
44
+ unpatchRequire();
45
+ }
46
+ });
47
+ // 2. Prepare the runner context
48
+ // We use a local emitter as we are not reporting to the CLI bridge,
49
+ // but the runner internals expect an emitter.
50
+ const events = getEmitter();
51
+ const context = {
52
+ events,
53
+ testFilePath: 'unknown',
54
+ };
55
+ // 3. Run the collected suite
56
+ return runSuite(testSuite, context);
57
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"runSuite.d.ts","sourceRoot":"","sources":["../../src/runner/runSuite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,SAAS,EACT,eAAe,EAChB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,iBAAiB,EAAE,MAAM,CAAC;CAC/B;AAsHD,eAAO,MAAM,QAAQ,GACnB,OAAO,SAAS,EAChB,SAAS,iBAAiB,KACzB,OAAO,CAAC,eAAe,CAoIzB,CAAC"}
1
+ {"version":3,"file":"runSuite.d.ts","sourceRoot":"","sources":["../../src/runner/runSuite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,SAAS,EACT,eAAe,EAChB,MAAM,8BAA8B,CAAC;AAQtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,iBAAiB,EAAE,MAAM,CAAC;CAC/B;AA+HD,eAAO,MAAM,QAAQ,GACnB,OAAO,SAAS,EAChB,SAAS,iBAAiB,KACzB,OAAO,CAAC,eAAe,CAoIzB,CAAC"}
@@ -1,3 +1,5 @@
1
+ import { setCurrentExpectTestState, } from '../expect/context.js';
2
+ import { flushExpectTestState } from '../expect/errors.js';
1
3
  import { runHooks } from './hooks.js';
2
4
  import { getTestExecutionError } from './errors.js';
3
5
  const runTest = async (test, suite, context) => {
@@ -45,12 +47,20 @@ const runTest = async (test, suite, context) => {
45
47
  });
46
48
  return result;
47
49
  }
48
- // Run all beforeEach hooks from the current suite and its parents
49
- await runHooks(suite, 'beforeEach');
50
- // Run the actual test
51
- await test.fn();
52
- // Run all afterEach hooks from the current suite and its parents
53
- await runHooks(suite, 'afterEach');
50
+ const expectTestState = {};
51
+ setCurrentExpectTestState(expectTestState);
52
+ try {
53
+ // Run all beforeEach hooks from the current suite and its parents
54
+ await runHooks(suite, 'beforeEach');
55
+ // Run the actual test
56
+ await test.fn();
57
+ // Run all afterEach hooks from the current suite and its parents
58
+ await runHooks(suite, 'afterEach');
59
+ await flushExpectTestState(expectTestState);
60
+ }
61
+ finally {
62
+ setCurrentExpectTestState(undefined);
63
+ }
54
64
  const duration = Date.now() - startTime;
55
65
  const result = {
56
66
  name: test.name,
@@ -0,0 +1,50 @@
1
+ import { type ViewInfo } from '../NativeHarness.js';
2
+ /**
3
+ * Represents an element found on screen with its position and dimensions.
4
+ * This can be used with userEvent.tap() to interact with the element.
5
+ */
6
+ export type ElementReference = ViewInfo;
7
+ export type Screen = {
8
+ /**
9
+ * Finds an element by its testID (accessibilityIdentifier on iOS, tag on Android).
10
+ * @throws Error if no element is found with the given testID.
11
+ */
12
+ findByTestId: (testId: string) => ElementReference;
13
+ /**
14
+ * Finds all elements by testID (accessibilityIdentifier on iOS, tag on Android).
15
+ * @throws Error if no elements are found with the given testID.
16
+ */
17
+ findAllByTestId: (testId: string) => ElementReference[];
18
+ /**
19
+ * Queries for an element by its testID without throwing.
20
+ * Returns null if no element is found.
21
+ */
22
+ queryByTestId: (testId: string) => ElementReference | null;
23
+ /**
24
+ * Queries for all elements by testID without throwing.
25
+ * Returns an empty array if no elements are found.
26
+ */
27
+ queryAllByTestId: (testId: string) => ElementReference[];
28
+ /**
29
+ * Finds an element by its accessibility label.
30
+ * @throws Error if no element is found with the given label.
31
+ */
32
+ findByAccessibilityLabel: (label: string) => ElementReference;
33
+ /**
34
+ * Finds all elements by accessibility label.
35
+ * @throws Error if no elements are found with the given label.
36
+ */
37
+ findAllByAccessibilityLabel: (label: string) => ElementReference[];
38
+ /**
39
+ * Queries for an element by its accessibility label without throwing.
40
+ * Returns null if no element is found.
41
+ */
42
+ queryByAccessibilityLabel: (label: string) => ElementReference | null;
43
+ /**
44
+ * Queries for all elements by accessibility label without throwing.
45
+ * Returns an empty array if no elements are found.
46
+ */
47
+ queryAllByAccessibilityLabel: (label: string) => ElementReference[];
48
+ };
49
+ export declare const screen: Screen;
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/screen/index.ts"],"names":[],"mappings":"AAAA,OAAsB,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAExC,MAAM,MAAM,MAAM,GAAG;IACnB;;;OAGG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,CAAC;IAEnD;;;OAGG;IACH,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAExD;;;OAGG;IACH,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAE3D;;;OAGG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAEzD;;;OAGG;IACH,wBAAwB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,CAAC;IAE9D;;;OAGG;IACH,2BAA2B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAEnE;;;OAGG;IACH,yBAAyB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAEtE;;;OAGG;IACH,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;CACrE,CAAC;AA0DF,eAAO,MAAM,MAAM,QAAiB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import NativeHarness from '../NativeHarness.js';
2
+ const createScreen = () => {
3
+ return {
4
+ findByTestId: (testId) => {
5
+ const result = NativeHarness.queryByTestId(testId);
6
+ if (!result) {
7
+ throw new Error(`Unable to find element with testID: ${testId}`);
8
+ }
9
+ return result;
10
+ },
11
+ findAllByTestId: (testId) => {
12
+ const results = NativeHarness.queryAllByTestId(testId);
13
+ if (results.length === 0) {
14
+ throw new Error(`Unable to find any elements with testID: ${testId}`);
15
+ }
16
+ return results;
17
+ },
18
+ queryByTestId: (testId) => {
19
+ return NativeHarness.queryByTestId(testId);
20
+ },
21
+ queryAllByTestId: (testId) => {
22
+ return NativeHarness.queryAllByTestId(testId);
23
+ },
24
+ findByAccessibilityLabel: (label) => {
25
+ const result = NativeHarness.queryByAccessibilityLabel(label);
26
+ if (!result) {
27
+ throw new Error(`Unable to find element with accessibility label: ${label}`);
28
+ }
29
+ return result;
30
+ },
31
+ findAllByAccessibilityLabel: (label) => {
32
+ const results = NativeHarness.queryAllByAccessibilityLabel(label);
33
+ if (results.length === 0) {
34
+ throw new Error(`Unable to find any elements with accessibility label: ${label}`);
35
+ }
36
+ return results;
37
+ },
38
+ queryByAccessibilityLabel: (label) => {
39
+ return NativeHarness.queryByAccessibilityLabel(label);
40
+ },
41
+ queryAllByAccessibilityLabel: (label) => {
42
+ return NativeHarness.queryAllByAccessibilityLabel(label);
43
+ },
44
+ };
45
+ };
46
+ export const screen = createScreen();