@react-native-harness/runtime 1.2.0 → 1.3.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.
Files changed (69) hide show
  1. package/dist/collector/functions.d.ts +3 -3
  2. package/dist/collector/functions.d.ts.map +1 -1
  3. package/dist/collector/types.d.ts +3 -2
  4. package/dist/collector/types.d.ts.map +1 -1
  5. package/dist/collector/validation.d.ts +2 -2
  6. package/dist/collector/validation.d.ts.map +1 -1
  7. package/dist/device/index.d.ts +12 -0
  8. package/dist/device/index.d.ts.map +1 -0
  9. package/dist/device/index.js +62 -0
  10. package/dist/hmr.d.ts +2 -0
  11. package/dist/hmr.d.ts.map +1 -0
  12. package/dist/hmr.js +5 -0
  13. package/dist/logbox.d.ts +4 -0
  14. package/dist/logbox.d.ts.map +1 -0
  15. package/dist/logbox.js +18 -0
  16. package/dist/runner/hooks.d.ts +2 -1
  17. package/dist/runner/hooks.d.ts.map +1 -1
  18. package/dist/runner/hooks.js +27 -17
  19. package/dist/runner/runSuite.d.ts.map +1 -1
  20. package/dist/runner/runSuite.js +56 -6
  21. package/dist/runner/test-context.d.ts +16 -0
  22. package/dist/runner/test-context.d.ts.map +1 -0
  23. package/dist/runner/test-context.js +57 -0
  24. package/dist/runner/types.d.ts +2 -1
  25. package/dist/runner/types.d.ts.map +1 -1
  26. package/dist/test-utils/react-native-url-polyfill.d.ts +9 -0
  27. package/dist/test-utils/react-native-url-polyfill.d.ts.map +1 -0
  28. package/dist/test-utils/react-native-url-polyfill.js +1 -0
  29. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  30. package/out-tsc/vitest/src/__tests__/device.test.d.ts +2 -0
  31. package/out-tsc/vitest/src/__tests__/device.test.d.ts.map +1 -0
  32. package/out-tsc/vitest/src/__tests__/logbox.test.d.ts +2 -0
  33. package/out-tsc/vitest/src/__tests__/logbox.test.d.ts.map +1 -0
  34. package/out-tsc/vitest/src/__tests__/runner-context.test.d.ts +2 -0
  35. package/out-tsc/vitest/src/__tests__/runner-context.test.d.ts.map +1 -0
  36. package/out-tsc/vitest/src/collector/functions.d.ts +3 -3
  37. package/out-tsc/vitest/src/collector/functions.d.ts.map +1 -1
  38. package/out-tsc/vitest/src/collector/types.d.ts +3 -2
  39. package/out-tsc/vitest/src/collector/types.d.ts.map +1 -1
  40. package/out-tsc/vitest/src/collector/validation.d.ts +2 -2
  41. package/out-tsc/vitest/src/collector/validation.d.ts.map +1 -1
  42. package/out-tsc/vitest/src/device/index.d.ts +12 -0
  43. package/out-tsc/vitest/src/device/index.d.ts.map +1 -0
  44. package/out-tsc/vitest/src/hmr.d.ts +2 -0
  45. package/out-tsc/vitest/src/hmr.d.ts.map +1 -0
  46. package/out-tsc/vitest/src/logbox.d.ts +4 -0
  47. package/out-tsc/vitest/src/logbox.d.ts.map +1 -0
  48. package/out-tsc/vitest/src/runner/hooks.d.ts +2 -1
  49. package/out-tsc/vitest/src/runner/hooks.d.ts.map +1 -1
  50. package/out-tsc/vitest/src/runner/runSuite.d.ts.map +1 -1
  51. package/out-tsc/vitest/src/runner/test-context.d.ts +16 -0
  52. package/out-tsc/vitest/src/runner/test-context.d.ts.map +1 -0
  53. package/out-tsc/vitest/src/runner/types.d.ts +2 -1
  54. package/out-tsc/vitest/src/runner/types.d.ts.map +1 -1
  55. package/out-tsc/vitest/src/test-utils/react-native-url-polyfill.d.ts +9 -0
  56. package/out-tsc/vitest/src/test-utils/react-native-url-polyfill.d.ts.map +1 -0
  57. package/out-tsc/vitest/tsconfig.spec.tsbuildinfo +1 -1
  58. package/out-tsc/vitest/vite.config.d.ts.map +1 -1
  59. package/package.json +2 -2
  60. package/src/__tests__/runner-context.test.ts +483 -0
  61. package/src/collector/functions.ts +5 -4
  62. package/src/collector/types.ts +4 -1
  63. package/src/collector/validation.ts +2 -2
  64. package/src/runner/hooks.ts +43 -19
  65. package/src/runner/runSuite.ts +75 -9
  66. package/src/runner/test-context.ts +84 -0
  67. package/src/runner/types.ts +3 -0
  68. package/src/test-utils/react-native-url-polyfill.ts +1 -0
  69. package/vite.config.ts +4 -0
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ HarnessTaskContext,
2
3
  TestCase,
3
4
  TestResult,
4
5
  TestSuite,
@@ -11,7 +12,14 @@ import {
11
12
  import { flushExpectTestState } from '../expect/errors.js';
12
13
  import { runHooks } from './hooks.js';
13
14
  import { getTestExecutionError } from './errors.js';
14
- import { TestRunnerContext } from './types.js';
15
+ import { ActiveTestContext, TestRunnerContext } from './types.js';
16
+ import {
17
+ createTestContext,
18
+ createTestLifecycleState,
19
+ isSkipTestError,
20
+ runOnTestFailed,
21
+ runOnTestFinished,
22
+ } from './test-context.js';
15
23
 
16
24
  declare global {
17
25
  var HARNESS_TEST_PATH: string;
@@ -23,6 +31,27 @@ const runTest = async (
23
31
  context: TestRunnerContext,
24
32
  ): Promise<TestResult> => {
25
33
  const startTime = Date.now();
34
+ const task: HarnessTaskContext = {
35
+ name: test.name,
36
+ type: 'test',
37
+ mode:
38
+ test.status === 'active'
39
+ ? 'run'
40
+ : test.status === 'skipped'
41
+ ? 'skip'
42
+ : 'todo',
43
+ file: {
44
+ name: context.testFilePath,
45
+ },
46
+ suite: {
47
+ name: suite.name,
48
+ },
49
+ };
50
+ const lifecycleState = createTestLifecycleState();
51
+ const activeTestContext: ActiveTestContext = createTestContext(
52
+ task,
53
+ lifecycleState,
54
+ );
26
55
 
27
56
  // Emit test-started event
28
57
  context.events.emit({
@@ -78,16 +107,50 @@ const runTest = async (
78
107
  setCurrentExpectTestState(expectTestState);
79
108
 
80
109
  try {
81
- // Run all beforeEach hooks from the current suite and its parents
82
- await runHooks(suite, 'beforeEach');
83
-
84
- // Run the actual test
85
- await test.fn();
86
-
87
- // Run all afterEach hooks from the current suite and its parents
88
- await runHooks(suite, 'afterEach');
110
+ let didSkip = false;
111
+
112
+ try {
113
+ // Run all beforeEach hooks from the current suite and its parents
114
+ await runHooks(suite, 'beforeEach', activeTestContext);
115
+
116
+ // Run the actual test
117
+ await test.fn(activeTestContext);
118
+ } catch (error) {
119
+ if (!isSkipTestError(error)) {
120
+ throw error;
121
+ }
122
+
123
+ didSkip = true;
124
+ } finally {
125
+ // Run all afterEach hooks from the current suite and its parents
126
+ await runHooks(suite, 'afterEach', activeTestContext);
127
+ }
128
+
129
+ if (didSkip) {
130
+ const duration = Date.now() - startTime;
131
+
132
+ await runOnTestFinished(lifecycleState);
133
+
134
+ const result = {
135
+ name: test.name,
136
+ status: 'skipped' as const,
137
+ duration,
138
+ };
139
+
140
+ context.events.emit({
141
+ type: 'test-finished',
142
+ file: context.testFilePath,
143
+ suite: suite.name,
144
+ name: test.name,
145
+ duration,
146
+ status: 'skipped',
147
+ });
148
+
149
+ return result;
150
+ }
89
151
 
90
152
  await flushExpectTestState(expectTestState);
153
+ await runOnTestFinished(lifecycleState);
91
154
  } finally {
92
155
  setCurrentExpectTestState(undefined);
93
156
  }
@@ -112,6 +175,9 @@ const runTest = async (
112
175
 
113
176
  return result;
114
177
  } catch (error) {
178
+ await runOnTestFailed(lifecycleState);
179
+ await runOnTestFinished(lifecycleState);
180
+
115
181
  const testError = await getTestExecutionError(
116
182
  error,
117
183
  context.testFilePath,
@@ -0,0 +1,84 @@
1
+ import type { HarnessTaskContext } from '@react-native-harness/bridge';
2
+ import type { ActiveTestContext } from './types.js';
3
+
4
+ export type TestLifecycleState = {
5
+ onTestFailed: Array<() => void | Promise<void>>;
6
+ onTestFinished: Array<() => void | Promise<void>>;
7
+ };
8
+
9
+ export class SkipTestError extends Error {
10
+ note?: string;
11
+
12
+ constructor(note?: string) {
13
+ super(note ?? 'Test skipped');
14
+ this.name = 'SkipTestError';
15
+ this.note = note;
16
+ }
17
+ }
18
+
19
+ export const isSkipTestError = (error: unknown): error is SkipTestError => {
20
+ return error instanceof SkipTestError;
21
+ };
22
+
23
+ const createSkip = () => {
24
+ function skip(noteOrCondition?: boolean | string, note?: string): void {
25
+ if (typeof noteOrCondition === 'boolean') {
26
+ if (!noteOrCondition) {
27
+ return;
28
+ }
29
+
30
+ throw new SkipTestError(note);
31
+ }
32
+
33
+ throw new SkipTestError(noteOrCondition);
34
+ }
35
+
36
+ return skip as ActiveTestContext['skip'];
37
+ };
38
+
39
+ const createOnTestFinished = (state: TestLifecycleState) => {
40
+ return (fn: () => void | Promise<void>): void => {
41
+ state.onTestFinished.push(fn);
42
+ };
43
+ };
44
+
45
+ const createOnTestFailed = (state: TestLifecycleState) => {
46
+ return (fn: () => void | Promise<void>): void => {
47
+ state.onTestFailed.push(fn);
48
+ };
49
+ };
50
+
51
+ export const createTestLifecycleState = (): TestLifecycleState => {
52
+ return {
53
+ onTestFailed: [],
54
+ onTestFinished: [],
55
+ };
56
+ };
57
+
58
+ export const runOnTestFailed = async (
59
+ state: TestLifecycleState,
60
+ ): Promise<void> => {
61
+ for (let i = state.onTestFailed.length - 1; i >= 0; i--) {
62
+ await state.onTestFailed[i]();
63
+ }
64
+ };
65
+
66
+ export const runOnTestFinished = async (
67
+ state: TestLifecycleState,
68
+ ): Promise<void> => {
69
+ for (let i = state.onTestFinished.length - 1; i >= 0; i--) {
70
+ await state.onTestFinished[i]();
71
+ }
72
+ };
73
+
74
+ export const createTestContext = (
75
+ task: HarnessTaskContext,
76
+ state: TestLifecycleState,
77
+ ): ActiveTestContext => {
78
+ return {
79
+ task,
80
+ onTestFailed: createOnTestFailed(state),
81
+ onTestFinished: createOnTestFinished(state),
82
+ skip: createSkip(),
83
+ };
84
+ };
@@ -1,5 +1,6 @@
1
1
  import { EventEmitter } from '../utils/emitter.js';
2
2
  import type {
3
+ HarnessTestContext,
3
4
  TestRunnerEvents,
4
5
  TestSuite,
5
6
  TestSuiteResult,
@@ -12,6 +13,8 @@ export type TestRunnerContext = {
12
13
  testFilePath: string;
13
14
  };
14
15
 
16
+ export type ActiveTestContext = HarnessTestContext;
17
+
15
18
  export type RunTestsOptions = {
16
19
  testSuite: TestSuite;
17
20
  testFilePath: string;
@@ -0,0 +1 @@
1
+ export const URL = globalThis.URL;
package/vite.config.ts CHANGED
@@ -22,6 +22,10 @@ export default defineConfig(() => ({
22
22
  alias: {
23
23
  '@vitest/spy': path.resolve(__dirname, 'node_modules/@vitest/spy'),
24
24
  '@vitest/expect': path.resolve(__dirname, 'node_modules/@vitest/expect'),
25
+ 'react-native-url-polyfill': path.resolve(
26
+ __dirname,
27
+ 'src/test-utils/react-native-url-polyfill.ts',
28
+ ),
25
29
  },
26
30
  },
27
31
  }));