@react-native-harness/runtime 1.0.0-alpha.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 (229) hide show
  1. package/.babelrc.js +23 -0
  2. package/LICENSE +20 -0
  3. package/README.md +7 -0
  4. package/assets/logo.png +0 -0
  5. package/assets/moduleSystem.flow.js +1062 -0
  6. package/dist/bundler/bundle.d.ts +2 -0
  7. package/dist/bundler/bundle.d.ts.map +1 -0
  8. package/dist/bundler/bundle.js +16 -0
  9. package/dist/bundler/dev-server.d.ts +2 -0
  10. package/dist/bundler/dev-server.d.ts.map +1 -0
  11. package/dist/bundler/dev-server.js +5 -0
  12. package/dist/bundler/errors.d.ts +10 -0
  13. package/dist/bundler/errors.d.ts.map +1 -0
  14. package/dist/bundler/errors.js +18 -0
  15. package/dist/bundler/evaluate.d.ts +2 -0
  16. package/dist/bundler/evaluate.d.ts.map +1 -0
  17. package/dist/bundler/evaluate.js +18 -0
  18. package/dist/bundler/index.d.ts +3 -0
  19. package/dist/bundler/index.d.ts.map +1 -0
  20. package/dist/bundler/index.js +2 -0
  21. package/dist/client/factory.d.ts +2 -0
  22. package/dist/client/factory.d.ts.map +1 -0
  23. package/dist/client/factory.js +41 -0
  24. package/dist/client/getDeviceDescriptor.d.ts +8 -0
  25. package/dist/client/getDeviceDescriptor.d.ts.map +1 -0
  26. package/dist/client/getDeviceDescriptor.js +20 -0
  27. package/dist/client/getWSServer.d.ts +2 -0
  28. package/dist/client/getWSServer.d.ts.map +1 -0
  29. package/dist/client/getWSServer.js +7 -0
  30. package/dist/client/index.d.ts +2 -0
  31. package/dist/client/index.d.ts.map +1 -0
  32. package/dist/client/index.js +1 -0
  33. package/dist/collector/errors.d.ts +8 -0
  34. package/dist/collector/errors.d.ts.map +1 -0
  35. package/dist/collector/errors.js +20 -0
  36. package/dist/collector/factory.d.ts +3 -0
  37. package/dist/collector/factory.d.ts.map +1 -0
  38. package/dist/collector/factory.js +25 -0
  39. package/dist/collector/functions.d.ts +22 -0
  40. package/dist/collector/functions.d.ts.map +1 -0
  41. package/dist/collector/functions.js +271 -0
  42. package/dist/collector/index.d.ts +5 -0
  43. package/dist/collector/index.d.ts.map +1 -0
  44. package/dist/collector/index.js +3 -0
  45. package/dist/collector/types.d.ts +10 -0
  46. package/dist/collector/types.d.ts.map +1 -0
  47. package/dist/collector/types.js +1 -0
  48. package/dist/collector/validation.d.ts +4 -0
  49. package/dist/collector/validation.d.ts.map +1 -0
  50. package/dist/collector/validation.js +15 -0
  51. package/dist/constants.d.ts +3 -0
  52. package/dist/constants.d.ts.map +1 -0
  53. package/dist/constants.js +2 -0
  54. package/dist/errors.d.ts +6 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/errors.js +13 -0
  57. package/dist/expect/index.d.ts +9 -0
  58. package/dist/expect/index.d.ts.map +1 -0
  59. package/dist/expect/index.js +71 -0
  60. package/dist/expect/setup.d.ts +2 -0
  61. package/dist/expect/setup.d.ts.map +1 -0
  62. package/dist/expect/setup.js +5 -0
  63. package/dist/exports.d.ts +7 -0
  64. package/dist/exports.d.ts.map +1 -0
  65. package/dist/exports.js +6 -0
  66. package/dist/getEntryComponent.d.ts +6 -0
  67. package/dist/getEntryComponent.d.ts.map +1 -0
  68. package/dist/getEntryComponent.js +6 -0
  69. package/dist/globals.d.ts +5 -0
  70. package/dist/globals.d.ts.map +1 -0
  71. package/dist/globals.js +1 -0
  72. package/dist/index.d.ts +7 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +6 -0
  75. package/dist/initialize.d.ts +2 -0
  76. package/dist/initialize.d.ts.map +1 -0
  77. package/dist/initialize.js +16 -0
  78. package/dist/logger.d.ts +6 -0
  79. package/dist/logger.d.ts.map +1 -0
  80. package/dist/logger.js +14 -0
  81. package/dist/mock.d.ts +15 -0
  82. package/dist/mock.d.ts.map +1 -0
  83. package/dist/mock.js +37 -0
  84. package/dist/mocker/index.d.ts +2 -0
  85. package/dist/mocker/index.d.ts.map +1 -0
  86. package/dist/mocker/index.js +1 -0
  87. package/dist/mocker/registry.d.ts +7 -0
  88. package/dist/mocker/registry.d.ts.map +1 -0
  89. package/dist/mocker/registry.js +41 -0
  90. package/dist/mocker/types.d.ts +6 -0
  91. package/dist/mocker/types.d.ts.map +1 -0
  92. package/dist/mocker/types.js +1 -0
  93. package/dist/module.d.ts +3 -0
  94. package/dist/module.d.ts.map +1 -0
  95. package/dist/module.js +19 -0
  96. package/dist/module.web.d.ts +2 -0
  97. package/dist/module.web.d.ts.map +1 -0
  98. package/dist/module.web.js +12 -0
  99. package/dist/rntl/client.d.ts +3 -0
  100. package/dist/rntl/client.d.ts.map +1 -0
  101. package/dist/rntl/client.js +8 -0
  102. package/dist/rntl/describe.d.ts +2 -0
  103. package/dist/rntl/describe.d.ts.map +1 -0
  104. package/dist/rntl/describe.js +1 -0
  105. package/dist/rntl/expect.d.ts +128 -0
  106. package/dist/rntl/expect.d.ts.map +1 -0
  107. package/dist/rntl/expect.js +670 -0
  108. package/dist/rntl/fn.d.ts +2 -0
  109. package/dist/rntl/fn.d.ts.map +1 -0
  110. package/dist/rntl/fn.js +1 -0
  111. package/dist/rntl/mock.d.ts +2 -0
  112. package/dist/rntl/mock.d.ts.map +1 -0
  113. package/dist/rntl/mock.js +1 -0
  114. package/dist/rntl/render.d.ts +4 -0
  115. package/dist/rntl/render.d.ts.map +1 -0
  116. package/dist/rntl/render.js +11 -0
  117. package/dist/rntl/screen.d.ts +45 -0
  118. package/dist/rntl/screen.d.ts.map +1 -0
  119. package/dist/rntl/screen.js +31 -0
  120. package/dist/rntl/spies.d.ts +45 -0
  121. package/dist/rntl/spies.d.ts.map +1 -0
  122. package/dist/rntl/spies.js +553 -0
  123. package/dist/rntl/userEvent.d.ts +22 -0
  124. package/dist/rntl/userEvent.d.ts.map +1 -0
  125. package/dist/rntl/userEvent.js +19 -0
  126. package/dist/runner/errors.d.ts +9 -0
  127. package/dist/runner/errors.d.ts.map +1 -0
  128. package/dist/runner/errors.js +23 -0
  129. package/dist/runner/factory.d.ts +3 -0
  130. package/dist/runner/factory.d.ts.map +1 -0
  131. package/dist/runner/factory.js +17 -0
  132. package/dist/runner/hooks.d.ts +4 -0
  133. package/dist/runner/hooks.d.ts.map +1 -0
  134. package/dist/runner/hooks.js +39 -0
  135. package/dist/runner/index.d.ts +4 -0
  136. package/dist/runner/index.d.ts.map +1 -0
  137. package/dist/runner/index.js +2 -0
  138. package/dist/runner/runSuite.d.ts +4 -0
  139. package/dist/runner/runSuite.d.ts.map +1 -0
  140. package/dist/runner/runSuite.js +147 -0
  141. package/dist/runner/types.d.ts +13 -0
  142. package/dist/runner/types.d.ts.map +1 -0
  143. package/dist/runner/types.js +1 -0
  144. package/dist/runner.d.ts +7 -0
  145. package/dist/runner.d.ts.map +1 -0
  146. package/dist/runner.js +201 -0
  147. package/dist/runtime.d.ts +2 -0
  148. package/dist/runtime.d.ts.map +1 -0
  149. package/dist/runtime.js +44 -0
  150. package/dist/spy/index.d.ts +2 -0
  151. package/dist/spy/index.d.ts.map +1 -0
  152. package/dist/spy/index.js +2 -0
  153. package/dist/state.d.ts +25 -0
  154. package/dist/state.d.ts.map +1 -0
  155. package/dist/state.js +37 -0
  156. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  157. package/dist/ui/ReadyScreen.d.ts +2 -0
  158. package/dist/ui/ReadyScreen.d.ts.map +1 -0
  159. package/dist/ui/ReadyScreen.js +110 -0
  160. package/dist/ui/UI.d.ts +13 -0
  161. package/dist/ui/UI.d.ts.map +1 -0
  162. package/dist/ui/UI.js +121 -0
  163. package/dist/ui/WrongEnvironmentScreen.d.ts +2 -0
  164. package/dist/ui/WrongEnvironmentScreen.d.ts.map +1 -0
  165. package/dist/ui/WrongEnvironmentScreen.js +87 -0
  166. package/dist/ui/index.d.ts +2 -0
  167. package/dist/ui/index.d.ts.map +1 -0
  168. package/dist/ui/index.js +3 -0
  169. package/dist/ui/state.d.ts +7 -0
  170. package/dist/ui/state.d.ts.map +1 -0
  171. package/dist/ui/state.js +6 -0
  172. package/dist/utils/dev-server.d.ts +2 -0
  173. package/dist/utils/dev-server.d.ts.map +1 -0
  174. package/dist/utils/dev-server.js +5 -0
  175. package/dist/utils/emitter.d.ts +16 -0
  176. package/dist/utils/emitter.d.ts.map +1 -0
  177. package/dist/utils/emitter.js +39 -0
  178. package/eslint.config.mjs +16 -0
  179. package/package.json +38 -0
  180. package/src/__tests__/collector.test.ts +553 -0
  181. package/src/__tests__/error-handling.test.ts +132 -0
  182. package/src/__tests__/expect.test.ts +619 -0
  183. package/src/__tests__/spy.test.ts +538 -0
  184. package/src/bundler/bundle.ts +19 -0
  185. package/src/bundler/errors.ts +16 -0
  186. package/src/bundler/evaluate.ts +25 -0
  187. package/src/bundler/index.ts +2 -0
  188. package/src/client/factory.ts +56 -0
  189. package/src/client/getDeviceDescriptor.ts +30 -0
  190. package/src/client/getWSServer.ts +9 -0
  191. package/src/client/index.ts +1 -0
  192. package/src/collector/errors.ts +27 -0
  193. package/src/collector/factory.ts +32 -0
  194. package/src/collector/functions.ts +376 -0
  195. package/src/collector/index.ts +12 -0
  196. package/src/collector/types.ts +15 -0
  197. package/src/collector/validation.ts +21 -0
  198. package/src/constants.ts +2 -0
  199. package/src/errors.ts +12 -0
  200. package/src/expect/index.ts +117 -0
  201. package/src/expect/setup.ts +10 -0
  202. package/src/globals.ts +5 -0
  203. package/src/index.ts +7 -0
  204. package/src/initialize.ts +22 -0
  205. package/src/mocker/index.ts +1 -0
  206. package/src/mocker/metro-require.d.ts +5 -0
  207. package/src/mocker/registry.ts +58 -0
  208. package/src/mocker/types.ts +6 -0
  209. package/src/react-native.d.ts +16 -0
  210. package/src/runner/errors.ts +31 -0
  211. package/src/runner/factory.ts +21 -0
  212. package/src/runner/hooks.ts +51 -0
  213. package/src/runner/index.ts +7 -0
  214. package/src/runner/runSuite.ts +201 -0
  215. package/src/runner/types.ts +19 -0
  216. package/src/spy/index.ts +2 -0
  217. package/src/ui/ReadyScreen.tsx +151 -0
  218. package/src/ui/WrongEnvironmentScreen.tsx +113 -0
  219. package/src/ui/index.ts +3 -0
  220. package/src/ui/state.ts +13 -0
  221. package/src/utils/dev-server.ts +6 -0
  222. package/src/utils/emitter.ts +64 -0
  223. package/tsconfig.json +16 -0
  224. package/tsconfig.lib.json +33 -0
  225. package/tsconfig.spec.json +30 -0
  226. package/tsconfig.tsbuildinfo +1 -0
  227. package/types/global.d.ts +2 -0
  228. package/types/index.d.ts +1 -0
  229. package/vite.config.ts +27 -0
@@ -0,0 +1,16 @@
1
+ import nx from '@nx/eslint-plugin';
2
+ import baseConfig from '../../eslint.config.mjs';
3
+
4
+ export default [
5
+ ...baseConfig,
6
+ ...nx.configs['flat/react'],
7
+ {
8
+ files: ['./src/rntl/**/*.ts'],
9
+ rules: {
10
+ 'react-hooks/rules-of-hooks': 'off',
11
+ },
12
+ },
13
+ {
14
+ ignores: ['public', '.cache', 'node_modules'],
15
+ },
16
+ ];
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@react-native-harness/runtime",
3
+ "version": "1.0.0-alpha.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "development": "./src/index.ts",
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./moduleSystem": "./assets/moduleSystem.flow.js",
17
+ "./types": "./types/index.d.ts"
18
+ },
19
+ "peerDependencies": {
20
+ "react": "~18.3.1",
21
+ "react-native": "~0.76.3"
22
+ },
23
+ "dependencies": {
24
+ "@vitest/expect": "4.0.0-beta.8",
25
+ "@vitest/spy": "4.0.0-beta.8",
26
+ "chai": "^5.3.1",
27
+ "event-target-shim": "^6.0.2",
28
+ "react-native-url-polyfill": "^2.0.0",
29
+ "sinon": "^21.0.0",
30
+ "util": "^0.12.5",
31
+ "zustand": "^5.0.5",
32
+ "@react-native-harness/bridge": "1.0.0-alpha.1"
33
+ },
34
+ "devDependencies": {
35
+ "@types/chai": "^5.2.2",
36
+ "@types/sinon": "^17.0.4"
37
+ }
38
+ }
@@ -0,0 +1,553 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import * as collectorFunctions from '../collector/functions.js';
3
+
4
+ const noop = () => {
5
+ // Noop
6
+ };
7
+
8
+ describe('test collector - test case recognition', () => {
9
+ it('should collect basic test cases using it()', () => {
10
+ const collectedSuite = collectorFunctions.collectTests(() => {
11
+ collectorFunctions.describe('Sample Suite', () => {
12
+ collectorFunctions.it('test 1', noop);
13
+ collectorFunctions.it('test 2', noop);
14
+ });
15
+ });
16
+
17
+ expect(collectedSuite.testSuite.suites).toHaveLength(1);
18
+ const sampleSuite = collectedSuite.testSuite.suites[0];
19
+ expect(sampleSuite.name).toBe('Sample Suite');
20
+ expect(sampleSuite.tests).toHaveLength(2);
21
+ expect(sampleSuite.tests[0].name).toBe('test 1');
22
+ expect(sampleSuite.tests[1].name).toBe('test 2');
23
+ expect(sampleSuite.tests[0].status).toBe('active');
24
+ expect(sampleSuite.tests[1].status).toBe('active');
25
+ });
26
+
27
+ it('should collect basic test cases using test()', () => {
28
+ const collectedSuite = collectorFunctions.collectTests(() => {
29
+ collectorFunctions.describe('Sample Suite', () => {
30
+ collectorFunctions.test('test 1', noop);
31
+ collectorFunctions.test('test 2', noop);
32
+ });
33
+ });
34
+
35
+ expect(collectedSuite.testSuite.suites).toHaveLength(1);
36
+ const sampleSuite = collectedSuite.testSuite.suites[0];
37
+ expect(sampleSuite.tests).toHaveLength(2);
38
+ expect(sampleSuite.tests[0].name).toBe('test 1');
39
+ expect(sampleSuite.tests[1].name).toBe('test 2');
40
+ });
41
+
42
+ it('should collect async test functions', () => {
43
+ const collectedSuite = collectorFunctions.collectTests(() => {
44
+ collectorFunctions.describe('Async Suite', () => {
45
+ collectorFunctions.it('async test', async () => {
46
+ await new Promise((resolve) => setTimeout(resolve, 10));
47
+ });
48
+ });
49
+ });
50
+
51
+ const asyncSuite = collectedSuite.testSuite.suites[0];
52
+ expect(asyncSuite.tests[0].name).toBe('async test');
53
+ expect(typeof asyncSuite.tests[0].fn).toBe('function');
54
+ });
55
+
56
+ it('should collect tests at root level', () => {
57
+ const collectedSuite = collectorFunctions.collectTests(() => {
58
+ collectorFunctions.it('root test 1', noop);
59
+ collectorFunctions.test('root test 2', noop);
60
+
61
+ collectorFunctions.describe('Suite with tests', () => {
62
+ collectorFunctions.it('suite test', noop);
63
+ });
64
+ });
65
+
66
+ // Collected root suite should have the root-level tests
67
+ expect(collectedSuite.testSuite.tests).toHaveLength(2);
68
+ expect(collectedSuite.testSuite.tests[0].name).toBe('root test 1');
69
+ expect(collectedSuite.testSuite.tests[1].name).toBe('root test 2');
70
+ expect(collectedSuite.testSuite.tests[0].status).toBe('active');
71
+ expect(collectedSuite.testSuite.tests[1].status).toBe('active');
72
+
73
+ // Should also have the describe suite
74
+ expect(collectedSuite.testSuite.suites).toHaveLength(1);
75
+ expect(collectedSuite.testSuite.suites[0].tests).toHaveLength(1);
76
+ expect(collectedSuite.testSuite.suites[0].tests[0].name).toBe('suite test');
77
+ });
78
+
79
+ it('should collect tests with modifiers at root level', () => {
80
+ const collectedSuite = collectorFunctions.collectTests(() => {
81
+ collectorFunctions.it('regular root test', noop);
82
+ collectorFunctions.test.skip('skipped root test', noop);
83
+ collectorFunctions.it.todo('todo root test');
84
+ collectorFunctions.test.only('focused root test', noop);
85
+ collectorFunctions.it('another root test', noop);
86
+ });
87
+
88
+ // Collected root suite should have all the tests with correct statuses
89
+ expect(collectedSuite.testSuite.tests).toHaveLength(5);
90
+ expect(collectedSuite.testSuite.tests[0].name).toBe('regular root test');
91
+ expect(collectedSuite.testSuite.tests[0].status).toBe('skipped'); // Due to .only
92
+ expect(collectedSuite.testSuite.tests[1].name).toBe('skipped root test');
93
+ expect(collectedSuite.testSuite.tests[1].status).toBe('skipped');
94
+ expect(collectedSuite.testSuite.tests[2].name).toBe('todo root test');
95
+ expect(collectedSuite.testSuite.tests[2].status).toBe('todo');
96
+ expect(collectedSuite.testSuite.tests[3].name).toBe('focused root test');
97
+ expect(collectedSuite.testSuite.tests[3].status).toBe('active'); // The .only test
98
+ expect(collectedSuite.testSuite.tests[4].name).toBe('another root test');
99
+ expect(collectedSuite.testSuite.tests[4].status).toBe('skipped'); // Due to .only
100
+ });
101
+ });
102
+
103
+ describe('test collector - suite recognition', () => {
104
+ it('should collect nested describe blocks', () => {
105
+ const collectedSuite = collectorFunctions.collectTests(() => {
106
+ collectorFunctions.describe('Outer Suite', () => {
107
+ collectorFunctions.describe('Inner Suite 1', () => {
108
+ collectorFunctions.it('test 1', noop);
109
+ });
110
+ collectorFunctions.describe('Inner Suite 2', () => {
111
+ collectorFunctions.it('test 2', noop);
112
+ });
113
+ });
114
+ });
115
+
116
+ expect(collectedSuite.testSuite.suites).toHaveLength(1);
117
+ const outerSuite = collectedSuite.testSuite.suites[0];
118
+ expect(outerSuite.name).toBe('Outer Suite');
119
+ expect(outerSuite.suites).toHaveLength(2);
120
+ expect(outerSuite.suites[0].name).toBe('Inner Suite 1');
121
+ expect(outerSuite.suites[1].name).toBe('Inner Suite 2');
122
+ expect(outerSuite.suites[0].tests[0].name).toBe('test 1');
123
+ expect(outerSuite.suites[1].tests[0].name).toBe('test 2');
124
+ });
125
+
126
+ it('should collect multiple top-level describe blocks', () => {
127
+ const collectedSuite = collectorFunctions.collectTests(() => {
128
+ collectorFunctions.describe('Suite 1', () => {
129
+ collectorFunctions.it('test 1', noop);
130
+ });
131
+ collectorFunctions.describe('Suite 2', () => {
132
+ collectorFunctions.it('test 2', noop);
133
+ });
134
+ });
135
+
136
+ expect(collectedSuite.testSuite.suites).toHaveLength(2);
137
+ expect(collectedSuite.testSuite.suites[0].name).toBe('Suite 1');
138
+ expect(collectedSuite.testSuite.suites[1].name).toBe('Suite 2');
139
+ });
140
+
141
+ it('should collect deeply nested suites', () => {
142
+ const collectedSuite = collectorFunctions.collectTests(() => {
143
+ collectorFunctions.describe('Level 1', () => {
144
+ collectorFunctions.describe('Level 2', () => {
145
+ collectorFunctions.describe('Level 3', () => {
146
+ collectorFunctions.it('deep test', noop);
147
+ });
148
+ });
149
+ });
150
+ });
151
+
152
+ const level1 = collectedSuite.testSuite.suites[0];
153
+ const level2 = level1.suites[0];
154
+ const level3 = level2.suites[0];
155
+
156
+ expect(level1.name).toBe('Level 1');
157
+ expect(level2.name).toBe('Level 2');
158
+ expect(level3.name).toBe('Level 3');
159
+ expect(level3.tests[0].name).toBe('deep test');
160
+ });
161
+ });
162
+
163
+ describe('test collector - skip modifier recognition', () => {
164
+ it('should collect and mark skipped tests with test.skip()', () => {
165
+ const collectedSuite = collectorFunctions.collectTests(() => {
166
+ collectorFunctions.describe('Skip Suite', () => {
167
+ collectorFunctions.it('active test', noop);
168
+ collectorFunctions.test.skip('skipped test', noop);
169
+ collectorFunctions.it.skip('another skipped test', noop);
170
+ });
171
+ });
172
+
173
+ const skipSuite = collectedSuite.testSuite.suites[0];
174
+ expect(skipSuite.tests).toHaveLength(3);
175
+ expect(skipSuite.tests[0].status).toBe('active');
176
+ expect(skipSuite.tests[1].status).toBe('skipped');
177
+ expect(skipSuite.tests[2].status).toBe('skipped');
178
+ });
179
+
180
+ it('should collect and mark skipped suites with describe.skip()', () => {
181
+ const collectedSuite = collectorFunctions.collectTests(() => {
182
+ collectorFunctions.describe('Active Suite', () => {
183
+ collectorFunctions.it('active test', noop);
184
+ });
185
+ collectorFunctions.describe.skip('Skipped Suite', () => {
186
+ collectorFunctions.it('test in skipped suite', noop);
187
+ });
188
+ });
189
+
190
+ expect(collectedSuite.testSuite.suites).toHaveLength(2);
191
+ expect(collectedSuite.testSuite.suites[0].status).toBe('active');
192
+ expect(collectedSuite.testSuite.suites[1].status).toBe('skipped');
193
+ });
194
+
195
+ it('should collect nested skipped suites', () => {
196
+ const collectedSuite = collectorFunctions.collectTests(() => {
197
+ collectorFunctions.describe.skip('Outer Skipped', () => {
198
+ collectorFunctions.describe('Inner Suite', () => {
199
+ collectorFunctions.it('test', noop);
200
+ });
201
+ });
202
+ });
203
+
204
+ const outerSuite = collectedSuite.testSuite.suites[0];
205
+ expect(outerSuite.status).toBe('skipped');
206
+ expect(outerSuite.suites[0].tests[0].name).toBe('test');
207
+ });
208
+ });
209
+
210
+ describe('test collector - only modifier recognition', () => {
211
+ it('should collect and mark only tests and skip others with test.only()', () => {
212
+ const collectedSuite = collectorFunctions.collectTests(() => {
213
+ collectorFunctions.describe('Only Suite', () => {
214
+ collectorFunctions.it('regular test 1', noop);
215
+ collectorFunctions.test.only('focused test', noop);
216
+ collectorFunctions.it('regular test 2', noop);
217
+ });
218
+ });
219
+
220
+ const onlySuite = collectedSuite.testSuite.suites[0];
221
+ expect(onlySuite.tests).toHaveLength(3);
222
+ expect(onlySuite.tests[0].status).toBe('skipped');
223
+ expect(onlySuite.tests[1].status).toBe('active');
224
+ expect(onlySuite.tests[2].status).toBe('skipped');
225
+ expect(onlySuite._hasFocused).toBe(true);
226
+ });
227
+
228
+ it('should collect multiple test.only() calls', () => {
229
+ const collectedSuite = collectorFunctions.collectTests(() => {
230
+ collectorFunctions.describe('Multiple Only Suite', () => {
231
+ collectorFunctions.it('regular test', noop);
232
+ collectorFunctions.test.only('focused test 1', noop);
233
+ collectorFunctions.test.only('focused test 2', noop);
234
+ });
235
+ });
236
+
237
+ const multipleSuite = collectedSuite.testSuite.suites[0];
238
+ expect(multipleSuite.tests[0].status).toBe('skipped');
239
+ expect(multipleSuite.tests[1].status).toBe('active'); // First only stays active
240
+ expect(multipleSuite.tests[2].status).toBe('active'); // Second only also active
241
+ });
242
+
243
+ it('should collect and mark only suites and skip others with describe.only()', () => {
244
+ const collectedSuite = collectorFunctions.collectTests(() => {
245
+ collectorFunctions.describe('Regular Suite 1', () => {
246
+ collectorFunctions.it('test 1', noop);
247
+ });
248
+ collectorFunctions.describe.only('Focused Suite', () => {
249
+ collectorFunctions.it('focused test', noop);
250
+ });
251
+ collectorFunctions.describe('Regular Suite 2', () => {
252
+ collectorFunctions.it('test 2', noop);
253
+ });
254
+ });
255
+
256
+ expect(collectedSuite.testSuite.suites).toHaveLength(3);
257
+ expect(collectedSuite.testSuite.suites[0].status).toBe('skipped');
258
+ expect(collectedSuite.testSuite.suites[1].status).toBe('active');
259
+ expect(collectedSuite.testSuite.suites[2].status).toBe('skipped');
260
+ expect(collectedSuite.testSuite.suites[1]._hasFocused).toBe(true);
261
+ });
262
+
263
+ it('should collect nested describe.only()', () => {
264
+ const collectedSuite = collectorFunctions.collectTests(() => {
265
+ collectorFunctions.describe('Outer Suite', () => {
266
+ collectorFunctions.describe('Regular Inner', () => {
267
+ collectorFunctions.it('test 1', noop);
268
+ });
269
+ collectorFunctions.describe.only('Focused Inner', () => {
270
+ collectorFunctions.it('focused test', noop);
271
+ });
272
+ });
273
+ });
274
+
275
+ const outerSuite = collectedSuite.testSuite.suites[0];
276
+ expect(outerSuite.status).toBe('active');
277
+ expect(outerSuite._hasFocused).toBe(true);
278
+ expect(outerSuite.suites[0].status).toBe('skipped');
279
+ expect(outerSuite.suites[1].status).toBe('active');
280
+ });
281
+ });
282
+
283
+ describe('test collector - todo test recognition', () => {
284
+ it('should collect and mark todo tests with test.todo()', () => {
285
+ const collectedSuite = collectorFunctions.collectTests(() => {
286
+ collectorFunctions.describe('Todo Suite', () => {
287
+ collectorFunctions.it('regular test', noop);
288
+ collectorFunctions.test.todo('todo test');
289
+ collectorFunctions.it.todo('another todo test');
290
+ });
291
+ });
292
+
293
+ const todoSuite = collectedSuite.testSuite.suites[0];
294
+ expect(todoSuite.tests).toHaveLength(3);
295
+ expect(todoSuite.tests[0].status).toBe('active');
296
+ expect(todoSuite.tests[1].status).toBe('todo');
297
+ expect(todoSuite.tests[2].status).toBe('todo');
298
+ });
299
+
300
+ it('should collect todo tests without function bodies', () => {
301
+ const collectedSuite = collectorFunctions.collectTests(() => {
302
+ collectorFunctions.describe('Todo Suite', () => {
303
+ collectorFunctions.test.todo('implement this feature');
304
+ });
305
+ });
306
+
307
+ const todoSuite = collectedSuite.testSuite.suites[0];
308
+ expect(todoSuite.tests[0].name).toBe('implement this feature');
309
+ expect(todoSuite.tests[0].status).toBe('todo');
310
+ expect(typeof todoSuite.tests[0].fn).toBe('function');
311
+ });
312
+ });
313
+
314
+ describe('test collector - hook recognition', () => {
315
+ it('should collect beforeAll hooks', () => {
316
+ const collectedSuite = collectorFunctions.collectTests(() => {
317
+ collectorFunctions.describe('Hook Suite', () => {
318
+ collectorFunctions.beforeAll(() => {
319
+ // setup
320
+ });
321
+ collectorFunctions.beforeAll(async () => {
322
+ // async setup
323
+ });
324
+ collectorFunctions.it('test', noop);
325
+ });
326
+ });
327
+
328
+ const hookSuite = collectedSuite.testSuite.suites[0];
329
+ expect(hookSuite.beforeAll).toHaveLength(2);
330
+ expect(typeof hookSuite.beforeAll[0]).toBe('function');
331
+ expect(typeof hookSuite.beforeAll[1]).toBe('function');
332
+ });
333
+
334
+ it('should collect afterAll hooks', () => {
335
+ const collectedSuite = collectorFunctions.collectTests(() => {
336
+ collectorFunctions.describe('Hook Suite', () => {
337
+ collectorFunctions.afterAll(() => {
338
+ // cleanup
339
+ });
340
+ collectorFunctions.it('test', noop);
341
+ });
342
+ });
343
+
344
+ const hookSuite = collectedSuite.testSuite.suites[0];
345
+ expect(hookSuite.afterAll).toHaveLength(1);
346
+ expect(typeof hookSuite.afterAll[0]).toBe('function');
347
+ });
348
+
349
+ it('should collect beforeEach hooks', () => {
350
+ const collectedSuite = collectorFunctions.collectTests(() => {
351
+ collectorFunctions.describe('Hook Suite', () => {
352
+ collectorFunctions.beforeEach(() => {
353
+ // setup each
354
+ });
355
+ collectorFunctions.beforeEach(async () => {
356
+ // async setup each
357
+ });
358
+ collectorFunctions.it('test', noop);
359
+ });
360
+ });
361
+
362
+ const hookSuite = collectedSuite.testSuite.suites[0];
363
+ expect(hookSuite.beforeEach).toHaveLength(2);
364
+ expect(typeof hookSuite.beforeEach[0]).toBe('function');
365
+ expect(typeof hookSuite.beforeEach[1]).toBe('function');
366
+ });
367
+
368
+ it('should collect afterEach hooks', () => {
369
+ const collectedSuite = collectorFunctions.collectTests(() => {
370
+ collectorFunctions.describe('Hook Suite', () => {
371
+ collectorFunctions.afterEach(() => {
372
+ // cleanup each
373
+ });
374
+ collectorFunctions.it('test', noop);
375
+ });
376
+ });
377
+
378
+ const hookSuite = collectedSuite.testSuite.suites[0];
379
+ expect(hookSuite.afterEach).toHaveLength(1);
380
+ expect(typeof hookSuite.afterEach[0]).toBe('function');
381
+ });
382
+
383
+ it('should collect all types of hooks together', () => {
384
+ const collectedSuite = collectorFunctions.collectTests(() => {
385
+ collectorFunctions.describe('All Hooks Suite', () => {
386
+ collectorFunctions.beforeAll(noop);
387
+ collectorFunctions.afterAll(noop);
388
+ collectorFunctions.beforeEach(noop);
389
+ collectorFunctions.afterEach(noop);
390
+ collectorFunctions.it('test', noop);
391
+ });
392
+ });
393
+
394
+ const allHooksSuite = collectedSuite.testSuite.suites[0];
395
+ expect(allHooksSuite.beforeAll).toHaveLength(1);
396
+ expect(allHooksSuite.afterAll).toHaveLength(1);
397
+ expect(allHooksSuite.beforeEach).toHaveLength(1);
398
+ expect(allHooksSuite.afterEach).toHaveLength(1);
399
+ });
400
+
401
+ it('should collect hooks at root level', () => {
402
+ const collectedSuite = collectorFunctions.collectTests(() => {
403
+ collectorFunctions.beforeAll(() => {
404
+ // root level setup
405
+ });
406
+ collectorFunctions.afterAll(() => {
407
+ // root level cleanup
408
+ });
409
+ collectorFunctions.beforeEach(() => {
410
+ // root level setup each
411
+ });
412
+ collectorFunctions.afterEach(() => {
413
+ // root level cleanup each
414
+ });
415
+
416
+ collectorFunctions.describe('Test Suite', () => {
417
+ collectorFunctions.it('test', noop);
418
+ });
419
+ });
420
+
421
+ // Collected root suite should have the hooks
422
+ expect(collectedSuite.testSuite.beforeAll).toHaveLength(1);
423
+ expect(collectedSuite.testSuite.afterAll).toHaveLength(1);
424
+ expect(collectedSuite.testSuite.beforeEach).toHaveLength(1);
425
+ expect(collectedSuite.testSuite.afterEach).toHaveLength(1);
426
+ expect(typeof collectedSuite.testSuite.beforeAll[0]).toBe('function');
427
+ expect(typeof collectedSuite.testSuite.afterAll[0]).toBe('function');
428
+ expect(typeof collectedSuite.testSuite.beforeEach[0]).toBe('function');
429
+ expect(typeof collectedSuite.testSuite.afterEach[0]).toBe('function');
430
+ });
431
+
432
+ it('should collect hooks at both root and suite levels', () => {
433
+ const collectedSuite = collectorFunctions.collectTests(() => {
434
+ // Root level hooks
435
+ collectorFunctions.beforeAll(() => {
436
+ // global setup
437
+ });
438
+ collectorFunctions.beforeEach(() => {
439
+ // global setup each
440
+ });
441
+
442
+ collectorFunctions.describe('Suite with hooks', () => {
443
+ // Suite level hooks
444
+ collectorFunctions.beforeAll(() => {
445
+ // suite setup
446
+ });
447
+ collectorFunctions.beforeEach(() => {
448
+ // suite setup each
449
+ });
450
+ collectorFunctions.it('test', noop);
451
+ });
452
+ });
453
+
454
+ // Collected root suite should have its hooks
455
+ expect(collectedSuite.testSuite.beforeAll).toHaveLength(1);
456
+ expect(collectedSuite.testSuite.beforeEach).toHaveLength(1);
457
+
458
+ // Child suite should have its own hooks
459
+ const childSuite = collectedSuite.testSuite.suites[0];
460
+ expect(childSuite.beforeAll).toHaveLength(1);
461
+ expect(childSuite.beforeEach).toHaveLength(1);
462
+ });
463
+ });
464
+
465
+ describe('test collector - complex scenarios', () => {
466
+ it('should collect mix of tests, suites, hooks, and modifiers', () => {
467
+ const collectedSuite = collectorFunctions.collectTests(() => {
468
+ collectorFunctions.describe('Complex Suite', () => {
469
+ collectorFunctions.beforeAll(noop);
470
+ collectorFunctions.beforeEach(noop);
471
+
472
+ collectorFunctions.it('regular test', noop);
473
+ collectorFunctions.test.skip('skipped test', noop);
474
+ collectorFunctions.test.todo('todo test');
475
+
476
+ collectorFunctions.describe.skip('Skipped Inner Suite', () => {
477
+ collectorFunctions.it('inner test', noop);
478
+ });
479
+
480
+ collectorFunctions.describe('Regular Inner Suite', () => {
481
+ collectorFunctions.beforeEach(noop);
482
+ collectorFunctions.it('inner test 1', noop);
483
+ collectorFunctions.test.only('focused inner test', noop);
484
+ collectorFunctions.it('inner test 2', noop);
485
+ collectorFunctions.afterEach(noop);
486
+ });
487
+
488
+ collectorFunctions.afterAll(noop);
489
+ });
490
+ });
491
+
492
+ const complexSuite = collectedSuite.testSuite.suites[0];
493
+
494
+ // Check hooks
495
+ expect(complexSuite.beforeAll).toHaveLength(1);
496
+ expect(complexSuite.afterAll).toHaveLength(1);
497
+ expect(complexSuite.beforeEach).toHaveLength(1);
498
+
499
+ // Check tests
500
+ expect(complexSuite.tests).toHaveLength(3);
501
+ expect(complexSuite.tests[0].status).toBe('active');
502
+ expect(complexSuite.tests[1].status).toBe('skipped');
503
+ expect(complexSuite.tests[2].status).toBe('todo');
504
+
505
+ // Check nested suites
506
+ expect(complexSuite.suites).toHaveLength(2);
507
+ expect(complexSuite.suites[0].status).toBe('skipped');
508
+
509
+ const innerSuite = complexSuite.suites[1];
510
+ expect(innerSuite.beforeEach).toHaveLength(1);
511
+ expect(innerSuite.afterEach).toHaveLength(1);
512
+ expect(innerSuite.tests).toHaveLength(3);
513
+ expect(innerSuite.tests[0].status).toBe('skipped'); // Due to .only
514
+ expect(innerSuite.tests[1].status).toBe('active'); // The .only test
515
+ expect(innerSuite.tests[2].status).toBe('skipped'); // Due to .only
516
+ });
517
+
518
+ it('should clear collector state between collectTests calls', () => {
519
+ const collectedSuite1 = collectorFunctions.collectTests(() => {
520
+ collectorFunctions.describe('Suite 1', () => {
521
+ collectorFunctions.it('test 1', noop);
522
+ });
523
+ });
524
+
525
+ const collectedSuite2 = collectorFunctions.collectTests(() => {
526
+ collectorFunctions.describe('Suite 2', () => {
527
+ collectorFunctions.it('test 2', noop);
528
+ });
529
+ });
530
+
531
+ expect(collectedSuite1.testSuite.suites).toHaveLength(1);
532
+ expect(collectedSuite2.testSuite.suites).toHaveLength(1);
533
+ expect(collectedSuite1.testSuite.suites[0].name).toBe('Suite 1');
534
+ expect(collectedSuite2.testSuite.suites[0].name).toBe('Suite 2');
535
+ });
536
+
537
+ it('should collect empty describe blocks', () => {
538
+ const collectedSuite = collectorFunctions.collectTests(() => {
539
+ collectorFunctions.describe('Empty Suite', () => {
540
+ // No tests or hooks
541
+ });
542
+ });
543
+
544
+ const emptySuite = collectedSuite.testSuite.suites[0];
545
+ expect(emptySuite.name).toBe('Empty Suite');
546
+ expect(emptySuite.tests).toHaveLength(0);
547
+ expect(emptySuite.suites).toHaveLength(0);
548
+ expect(emptySuite.beforeAll).toHaveLength(0);
549
+ expect(emptySuite.afterAll).toHaveLength(0);
550
+ expect(emptySuite.beforeEach).toHaveLength(0);
551
+ expect(emptySuite.afterEach).toHaveLength(0);
552
+ });
553
+ });