@react-native-harness/runtime 1.0.0-alpha.1 → 1.0.0-alpha.10

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 (93) hide show
  1. package/dist/bundler/bundle.d.ts.map +1 -1
  2. package/dist/bundler/bundle.js +7 -1
  3. package/dist/bundler/errors.d.ts +5 -0
  4. package/dist/bundler/errors.d.ts.map +1 -1
  5. package/dist/bundler/errors.js +10 -0
  6. package/dist/client/factory.d.ts.map +1 -1
  7. package/dist/client/factory.js +8 -1
  8. package/dist/initialize.js +8 -6
  9. package/dist/mocker/registry.d.ts +2 -2
  10. package/dist/mocker/registry.d.ts.map +1 -1
  11. package/dist/runner/errors.d.ts +4 -2
  12. package/dist/runner/errors.d.ts.map +1 -1
  13. package/dist/runner/errors.js +21 -3
  14. package/dist/runner/runSuite.d.ts.map +1 -1
  15. package/dist/runner/runSuite.js +22 -7
  16. package/dist/symbolicate.d.ts +3 -0
  17. package/dist/symbolicate.d.ts.map +1 -0
  18. package/dist/symbolicate.js +18 -0
  19. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  20. package/dist/utils/progressLogger.d.ts +8 -0
  21. package/dist/utils/progressLogger.d.ts.map +1 -0
  22. package/dist/utils/progressLogger.js +73 -0
  23. package/package.json +7 -5
  24. package/src/bundler/bundle.ts +9 -1
  25. package/src/bundler/errors.ts +10 -0
  26. package/src/client/factory.ts +8 -1
  27. package/src/initialize.ts +11 -8
  28. package/src/mocker/registry.ts +3 -3
  29. package/src/react-native.d.ts +37 -0
  30. package/src/runner/errors.ts +35 -5
  31. package/src/runner/runSuite.ts +27 -9
  32. package/src/symbolicate.ts +22 -0
  33. package/src/utils/progressLogger.ts +91 -0
  34. package/dist/bundler/dev-server.d.ts +0 -2
  35. package/dist/bundler/dev-server.d.ts.map +0 -1
  36. package/dist/bundler/dev-server.js +0 -5
  37. package/dist/exports.d.ts +0 -7
  38. package/dist/exports.d.ts.map +0 -1
  39. package/dist/exports.js +0 -6
  40. package/dist/getEntryComponent.d.ts +0 -6
  41. package/dist/getEntryComponent.d.ts.map +0 -1
  42. package/dist/getEntryComponent.js +0 -6
  43. package/dist/logger.d.ts +0 -6
  44. package/dist/logger.d.ts.map +0 -1
  45. package/dist/logger.js +0 -14
  46. package/dist/mock.d.ts +0 -15
  47. package/dist/mock.d.ts.map +0 -1
  48. package/dist/mock.js +0 -37
  49. package/dist/module.d.ts +0 -3
  50. package/dist/module.d.ts.map +0 -1
  51. package/dist/module.js +0 -19
  52. package/dist/module.web.d.ts +0 -2
  53. package/dist/module.web.d.ts.map +0 -1
  54. package/dist/module.web.js +0 -12
  55. package/dist/rntl/client.d.ts +0 -3
  56. package/dist/rntl/client.d.ts.map +0 -1
  57. package/dist/rntl/client.js +0 -8
  58. package/dist/rntl/describe.d.ts +0 -2
  59. package/dist/rntl/describe.d.ts.map +0 -1
  60. package/dist/rntl/describe.js +0 -1
  61. package/dist/rntl/expect.d.ts +0 -128
  62. package/dist/rntl/expect.d.ts.map +0 -1
  63. package/dist/rntl/expect.js +0 -670
  64. package/dist/rntl/fn.d.ts +0 -2
  65. package/dist/rntl/fn.d.ts.map +0 -1
  66. package/dist/rntl/fn.js +0 -1
  67. package/dist/rntl/mock.d.ts +0 -2
  68. package/dist/rntl/mock.d.ts.map +0 -1
  69. package/dist/rntl/mock.js +0 -1
  70. package/dist/rntl/render.d.ts +0 -4
  71. package/dist/rntl/render.d.ts.map +0 -1
  72. package/dist/rntl/render.js +0 -11
  73. package/dist/rntl/screen.d.ts +0 -45
  74. package/dist/rntl/screen.d.ts.map +0 -1
  75. package/dist/rntl/screen.js +0 -31
  76. package/dist/rntl/spies.d.ts +0 -45
  77. package/dist/rntl/spies.d.ts.map +0 -1
  78. package/dist/rntl/spies.js +0 -553
  79. package/dist/rntl/userEvent.d.ts +0 -22
  80. package/dist/rntl/userEvent.d.ts.map +0 -1
  81. package/dist/rntl/userEvent.js +0 -19
  82. package/dist/runner.d.ts +0 -7
  83. package/dist/runner.d.ts.map +0 -1
  84. package/dist/runner.js +0 -201
  85. package/dist/runtime.d.ts +0 -2
  86. package/dist/runtime.d.ts.map +0 -1
  87. package/dist/runtime.js +0 -44
  88. package/dist/state.d.ts +0 -25
  89. package/dist/state.d.ts.map +0 -1
  90. package/dist/state.js +0 -37
  91. package/dist/ui/UI.d.ts +0 -13
  92. package/dist/ui/UI.d.ts.map +0 -1
  93. package/dist/ui/UI.js +0 -121
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/bundler/bundle.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAIlE,CAAC"}
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/bundler/bundle.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAUlE,CAAC"}
@@ -1,16 +1,22 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { getDevServerUrl } from '../utils/dev-server.js';
3
+ import { BundlingFailedError } from './errors.js';
3
4
  const getModuleUrl = (fileName) => {
4
5
  const devServerUrl = getDevServerUrl();
5
6
  const bundleName = fileName.split('.').slice(0, -1).join('.') + '.bundle';
6
7
  const urlSearchParams = new URLSearchParams({
7
8
  modulesOnly: 'true',
8
9
  platform: Platform.OS,
10
+ 'resolver.isHarness': 'true',
9
11
  });
10
12
  return `${devServerUrl}/${bundleName}?${urlSearchParams.toString()}`;
11
13
  };
12
14
  export const fetchModule = async (fileName) => {
13
15
  const url = getModuleUrl(fileName);
14
16
  const response = await fetch(url);
15
- return response.text();
17
+ const text = await response.text();
18
+ if (!response.ok) {
19
+ throw new BundlingFailedError(fileName, text);
20
+ }
21
+ return text;
16
22
  };
@@ -7,4 +7,9 @@ export declare class MalformedModuleError extends Error {
7
7
  readonly reason: string;
8
8
  constructor(modulePath: string, reason: string);
9
9
  }
10
+ export declare class BundlingFailedError extends Error {
11
+ readonly modulePath: string;
12
+ readonly reason: string;
13
+ constructor(modulePath: string, reason: string);
14
+ }
10
15
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/bundler/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;gBADd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM;CAKjC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/bundler/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aAE3B,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;gBADd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM;CAKjC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;gBADd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM;CAKjC"}
@@ -16,3 +16,13 @@ export class MalformedModuleError extends Error {
16
16
  this.name = 'MalformedModuleError';
17
17
  }
18
18
  }
19
+ export class BundlingFailedError extends Error {
20
+ modulePath;
21
+ reason;
22
+ constructor(modulePath, reason) {
23
+ super(`Bundling of ${modulePath} failed`);
24
+ this.modulePath = modulePath;
25
+ this.reason = reason;
26
+ this.name = 'BundlingFailedError';
27
+ }
28
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,SAAS,2EA2CrB,CAAC"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,SAAS,2EAiDrB,CAAC"}
@@ -3,6 +3,7 @@ import { store } from '../ui/state.js';
3
3
  import { getTestRunner } from '../runner/index.js';
4
4
  import { getTestCollector } from '../collector/index.js';
5
5
  import { combineEventEmitters } from '../utils/emitter.js';
6
+ import { attachProgressLogger } from '../utils/progressLogger.js';
6
7
  import { getWSServer } from './getWSServer.js';
7
8
  import { fetchModule, evaluateModule } from '../bundler/index.js';
8
9
  export const getClient = async () => {
@@ -26,9 +27,15 @@ export const getClient = async () => {
26
27
  events.addListener((event) => {
27
28
  client.rpc.emitEvent(event.type, event);
28
29
  });
30
+ // Add console logging for progress information
31
+ attachProgressLogger(events, path);
29
32
  const moduleJs = await fetchModule(path);
30
33
  const collectionResult = await collector.collect(() => evaluateModule(moduleJs, path), path);
31
- return await runner.run(collectionResult.testSuite, path);
34
+ const result = await runner.run(collectionResult.testSuite, path);
35
+ return result;
36
+ }
37
+ catch (error) {
38
+ throw error;
32
39
  }
33
40
  finally {
34
41
  collector?.dispose();
@@ -8,9 +8,11 @@ globalThis.EventTarget = Shim.EventTarget;
8
8
  const { LogBox } = require('react-native');
9
9
  LogBox.ignoreAllLogs(true);
10
10
  // Turn off HMR
11
- const HMRClient = require('react-native/Libraries/Utilities/HMRClient');
12
- HMRClient.setup = () => {
13
- // No setup = no HMR
14
- };
15
- // Initialize the client
16
- void getClient().then((client) => client.rpc.reportReady(getDeviceDescriptor()));
11
+ const HMRClientModule = require('react-native/Libraries/Utilities/HMRClient');
12
+ const HMRClient = 'default' in HMRClientModule ? HMRClientModule.default : HMRClientModule;
13
+ // Wait for HMRClient to be initialized
14
+ setTimeout(() => {
15
+ HMRClient.disable();
16
+ // Initialize the React Native Harness
17
+ void getClient().then((client) => client.rpc.reportReady(getDeviceDescriptor()));
18
+ });
@@ -1,5 +1,5 @@
1
- import { ModuleFactory, ModuleId } from './types.js';
2
- export declare const mock: (moduleId: ModuleId, factory: ModuleFactory) => void;
1
+ import { ModuleFactory } from './types.js';
2
+ export declare const mock: (moduleId: string, factory: ModuleFactory) => void;
3
3
  export declare const clearMocks: () => void;
4
4
  export declare const getMockRegistry: () => Map<number, ModuleFactory>;
5
5
  export declare const getMockImplementation: (moduleId: number) => unknown | null;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/mocker/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAW,MAAM,YAAY,CAAC;AAO9D,eAAO,MAAM,IAAI,GAAI,UAAU,QAAQ,EAAE,SAAS,aAAa,KAAG,IAGjE,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,IAG7B,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,GAAG,CAAC,MAAM,EAAE,aAAa,CAE3D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,OAAO,GAAG,IAalE,CAAC;AAGF,eAAO,MAAM,aAAa,GAAI,CAAC,GAAG,GAAG,EAAE,UAAU,MAAM,KAAG,CAEH,CAAC"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/mocker/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAqB,MAAM,YAAY,CAAC;AAO9D,eAAO,MAAM,IAAI,GAAI,UAAU,MAAM,EAAE,SAAS,aAAa,KAAG,IAG/D,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,IAG7B,CAAC;AAEF,eAAO,MAAM,eAAe,QAAO,GAAG,CAAC,MAAM,EAAE,aAAa,CAE3D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,OAAO,GAAG,IAalE,CAAC;AAGF,eAAO,MAAM,aAAa,GAAI,CAAC,GAAG,GAAG,EAAE,UAAU,MAAM,KAAG,CAEH,CAAC"}
@@ -1,9 +1,11 @@
1
- import type { SerializedError } from '@react-native-harness/bridge';
1
+ import type { SerializedError, CodeFrame } from '@react-native-harness/bridge';
2
2
  export declare class TestExecutionError extends Error {
3
3
  file: string;
4
4
  suite: string;
5
5
  test: string;
6
- constructor(error: unknown, file: string, suite: string, test: string);
6
+ codeFrame?: CodeFrame;
7
+ constructor(error: unknown, file: string, suite: string, test: string, codeFrame?: CodeFrame);
7
8
  toSerializedJSON(): SerializedError;
8
9
  }
10
+ export declare const getTestExecutionError: (error: unknown, file: string, suite: string, test: string) => Promise<TestExecutionError>;
9
11
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/runner/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;gBAED,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IASrE,gBAAgB,IAAI,eAAe;CAcpC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/runner/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAG/E,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,SAAS,CAAC;gBAGpB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,SAAS;IAWvB,gBAAgB,IAAI,eAAe;CAapC;AAED,eAAO,MAAM,qBAAqB,GAChC,OAAO,OAAO,EACd,MAAM,MAAM,EACZ,OAAO,MAAM,EACb,MAAM,MAAM,KACX,OAAO,CAAC,kBAAkB,CAe5B,CAAC"}
@@ -1,23 +1,41 @@
1
+ import { getCodeFrame } from '../symbolicate.js';
1
2
  export class TestExecutionError extends Error {
2
3
  file;
3
4
  suite;
4
5
  test;
5
- constructor(error, file, suite, test) {
6
+ codeFrame;
7
+ constructor(error, file, suite, test, codeFrame) {
6
8
  super('Test execution error');
7
9
  this.name = 'TestExecutionError';
8
10
  this.file = file;
9
11
  this.suite = suite;
10
12
  this.test = test;
11
13
  this.cause = error;
14
+ this.codeFrame = codeFrame;
12
15
  }
13
16
  toSerializedJSON() {
14
17
  const causeName = this.cause instanceof Error ? this.cause.name : 'Unknown name';
15
18
  const causeMessage = this.cause instanceof Error ? this.cause.message : 'Unknown message';
16
- const causeStack = this.cause instanceof Error ? this.cause.stack : undefined;
19
+ const causeCodeFrame = this.codeFrame;
17
20
  return {
18
21
  name: causeName,
19
22
  message: causeMessage,
20
- stack: causeStack,
23
+ codeFrame: causeCodeFrame,
21
24
  };
22
25
  }
23
26
  }
27
+ export const getTestExecutionError = async (error, file, suite, test) => {
28
+ try {
29
+ if (error instanceof Error) {
30
+ const codeFrame = await getCodeFrame(error);
31
+ if (codeFrame) {
32
+ return new TestExecutionError(error, file, suite, test, codeFrame);
33
+ }
34
+ }
35
+ return new TestExecutionError(error, file, suite, test);
36
+ }
37
+ catch (error) {
38
+ // If the stack cannot be symbolicated, return the original error
39
+ return new TestExecutionError(error, file, suite, test);
40
+ }
41
+ };
@@ -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;AAsH/C,eAAO,MAAM,QAAQ,GACnB,OAAO,SAAS,EAChB,SAAS,iBAAiB,KACzB,OAAO,CAAC,eAAe,CAuEzB,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;AAGtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAsH/C,eAAO,MAAM,QAAQ,GACnB,OAAO,SAAS,EAChB,SAAS,iBAAiB,KACzB,OAAO,CAAC,eAAe,CAyFzB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { runHooks } from './hooks.js';
2
- import { TestExecutionError } from './errors.js';
2
+ import { getTestExecutionError } from './errors.js';
3
3
  const runTest = async (test, suite, context) => {
4
4
  const startTime = Date.now();
5
5
  // Emit test-started event
@@ -69,7 +69,7 @@ const runTest = async (test, suite, context) => {
69
69
  return result;
70
70
  }
71
71
  catch (error) {
72
- const testError = new TestExecutionError(error, context.testFilePath, suite.name, test.name);
72
+ const testError = await getTestExecutionError(error, context.testFilePath, suite.name, test.name);
73
73
  const duration = Date.now() - startTime;
74
74
  const result = {
75
75
  name: test.name,
@@ -123,11 +123,26 @@ export const runSuite = async (suite, context) => {
123
123
  if (hasFailedTests || hasFailedSuites) {
124
124
  status = 'failed';
125
125
  }
126
- else if ((testResults.every((result) => result.status === 'skipped') &&
127
- suiteResults.every((result) => result.status === 'skipped') &&
128
- testResults.length > 0) ||
129
- suiteResults.length > 0) {
130
- status = 'skipped';
126
+ else {
127
+ // Check if all tests and suites are skipped (and there are some tests/suites to check)
128
+ const allTestsSkipped = testResults.length > 0 &&
129
+ testResults.every((result) => result.status === 'skipped');
130
+ const allSuitesSkipped = suiteResults.length > 0 &&
131
+ suiteResults.every((result) => result.status === 'skipped');
132
+ const hasAnyContent = testResults.length > 0 || suiteResults.length > 0;
133
+ if (hasAnyContent &&
134
+ ((testResults.length > 0 &&
135
+ allTestsSkipped &&
136
+ suiteResults.length === 0) ||
137
+ (suiteResults.length > 0 &&
138
+ allSuitesSkipped &&
139
+ testResults.length === 0) ||
140
+ (testResults.length > 0 &&
141
+ suiteResults.length > 0 &&
142
+ allTestsSkipped &&
143
+ allSuitesSkipped))) {
144
+ status = 'skipped';
145
+ }
131
146
  }
132
147
  // Emit suite-finished event
133
148
  context.events.emit({
@@ -0,0 +1,3 @@
1
+ import type { CodeFrame } from '@react-native-harness/bridge';
2
+ export declare const getCodeFrame: (error: Error) => Promise<CodeFrame | null>;
3
+ //# sourceMappingURL=symbolicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbolicate.d.ts","sourceRoot":"","sources":["../src/symbolicate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAI9D,eAAO,MAAM,YAAY,GAAU,OAAO,KAAK,KAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAiBzE,CAAC"}
@@ -0,0 +1,18 @@
1
+ import parseErrorStack from 'react-native/Libraries/Core/Devtools/parseErrorStack';
2
+ import symbolicateStackTrace from 'react-native/Libraries/Core/Devtools/symbolicateStackTrace';
3
+ export const getCodeFrame = async (error) => {
4
+ const parsedStack = parseErrorStack(error.stack);
5
+ const symbolicatedStack = await symbolicateStackTrace(parsedStack);
6
+ if (!symbolicatedStack.codeFrame) {
7
+ return null;
8
+ }
9
+ // Normalize optionality (null -> undefined)
10
+ return {
11
+ ...symbolicatedStack.codeFrame,
12
+ location: symbolicatedStack.codeFrame.location
13
+ ? {
14
+ ...symbolicatedStack.codeFrame.location,
15
+ }
16
+ : undefined,
17
+ };
18
+ };