@hyperfixi/testing-framework 2.0.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 (37) hide show
  1. package/dist/assertions-BImuwZsB.d.mts +458 -0
  2. package/dist/assertions-BImuwZsB.d.ts +458 -0
  3. package/dist/assertions.d.mts +1 -0
  4. package/dist/assertions.d.ts +1 -0
  5. package/dist/assertions.js +625 -0
  6. package/dist/assertions.js.map +1 -0
  7. package/dist/assertions.mjs +621 -0
  8. package/dist/assertions.mjs.map +1 -0
  9. package/dist/index.d.mts +246 -0
  10. package/dist/index.d.ts +246 -0
  11. package/dist/index.js +1465 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/index.mjs +1435 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/package.json +121 -0
  16. package/src/assertions.test.ts +490 -0
  17. package/src/assertions.ts +779 -0
  18. package/src/index.test.ts +490 -0
  19. package/src/index.ts +601 -0
  20. package/src/jsdom.d.ts +7 -0
  21. package/src/multilingual/README.md +295 -0
  22. package/src/multilingual/bundle-builder.ts +345 -0
  23. package/src/multilingual/cli.ts +224 -0
  24. package/src/multilingual/index.ts +68 -0
  25. package/src/multilingual/orchestrator.ts +275 -0
  26. package/src/multilingual/pattern-loader.ts +176 -0
  27. package/src/multilingual/reporters/console-reporter.ts +294 -0
  28. package/src/multilingual/reporters/json-reporter.ts +99 -0
  29. package/src/multilingual/reporters/regression-reporter.ts +263 -0
  30. package/src/multilingual/tools/analyze-failures.ts +326 -0
  31. package/src/multilingual/types.ts +268 -0
  32. package/src/multilingual/validators/parse-diagnostics.ts +337 -0
  33. package/src/multilingual/validators/parse-validator.ts +193 -0
  34. package/src/multilingual/validators/size-validator.ts +187 -0
  35. package/src/runner.test.ts +813 -0
  36. package/src/runner.ts +639 -0
  37. package/src/types.ts +505 -0
@@ -0,0 +1,490 @@
1
+ /**
2
+ * Tests for Testing Framework Core Functions
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
+ import {
7
+ describe as describeTest,
8
+ it as itTest,
9
+ test,
10
+ describe_skip,
11
+ it_skip,
12
+ describe_only,
13
+ it_only,
14
+ beforeAll,
15
+ afterAll,
16
+ beforeEach as beforeEachTest,
17
+ afterEach as afterEachTest,
18
+ clearTests,
19
+ runTests,
20
+ fixture,
21
+ createMock,
22
+ createSpy,
23
+ waitFor,
24
+ createPageObject,
25
+ createLokaScriptTestContext,
26
+ quickStartTesting,
27
+ VERSION,
28
+ DEFAULT_CONFIG,
29
+ } from './index';
30
+
31
+ describe('Testing Framework Core', () => {
32
+ beforeEach(() => {
33
+ clearTests();
34
+ });
35
+
36
+ describe('describe function', () => {
37
+ it('should register a test suite', async () => {
38
+ describeTest('Test Suite', () => {
39
+ itTest('test case', () => {});
40
+ });
41
+
42
+ const results = await runTests({ environment: 'node' });
43
+ expect(results).toHaveLength(1);
44
+ expect(results[0].suite).toBe('Test Suite');
45
+ });
46
+
47
+ it('should support nested suites', async () => {
48
+ describeTest('Outer', () => {
49
+ describeTest('Inner', () => {
50
+ itTest('test', () => {});
51
+ });
52
+ });
53
+
54
+ const results = await runTests({ environment: 'node' });
55
+ expect(results).toHaveLength(1);
56
+ expect(results[0].suite).toBe('Inner');
57
+ });
58
+ });
59
+
60
+ describe('it function', () => {
61
+ it('should throw when used outside describe', () => {
62
+ expect(() => itTest('orphan test', () => {})).toThrow();
63
+ });
64
+
65
+ it('should register test with name', async () => {
66
+ describeTest('Suite', () => {
67
+ itTest('my test', () => {});
68
+ });
69
+
70
+ const results = await runTests({ environment: 'node' });
71
+ expect(results[0].test).toBe('my test');
72
+ });
73
+ });
74
+
75
+ describe('test function (alias for it)', () => {
76
+ it('should be an alias for it', () => {
77
+ expect(test).toBe(itTest);
78
+ });
79
+ });
80
+
81
+ describe('describe_skip', () => {
82
+ it('should skip all tests in suite', async () => {
83
+ describe_skip('Skipped Suite', () => {
84
+ itTest('test 1', () => {});
85
+ itTest('test 2', () => {});
86
+ });
87
+
88
+ const results = await runTests({ environment: 'node' });
89
+ expect(results.every(r => r.status === 'skipped')).toBe(true);
90
+ });
91
+ });
92
+
93
+ describe('it_skip', () => {
94
+ it('should skip individual test', async () => {
95
+ describeTest('Suite', () => {
96
+ it_skip('skipped test', () => {});
97
+ itTest('normal test', () => {});
98
+ });
99
+
100
+ const results = await runTests({ environment: 'node' });
101
+ expect(results[0].status).toBe('skipped');
102
+ expect(results[1].status).toBe('passed');
103
+ });
104
+ });
105
+
106
+ describe('lifecycle hooks', () => {
107
+ it('should throw beforeAll outside describe', () => {
108
+ expect(() => beforeAll(() => {})).toThrow();
109
+ });
110
+
111
+ it('should throw afterAll outside describe', () => {
112
+ expect(() => afterAll(() => {})).toThrow();
113
+ });
114
+
115
+ it('should throw beforeEach outside describe', () => {
116
+ expect(() => beforeEachTest(() => {})).toThrow();
117
+ });
118
+
119
+ it('should throw afterEach outside describe', () => {
120
+ expect(() => afterEachTest(() => {})).toThrow();
121
+ });
122
+ });
123
+
124
+ describe('clearTests', () => {
125
+ it('should clear all registered tests', async () => {
126
+ describeTest('Suite 1', () => {
127
+ itTest('test', () => {});
128
+ });
129
+
130
+ clearTests();
131
+
132
+ describeTest('Suite 2', () => {
133
+ itTest('test', () => {});
134
+ });
135
+
136
+ const results = await runTests({ environment: 'node' });
137
+ expect(results).toHaveLength(1);
138
+ expect(results[0].suite).toBe('Suite 2');
139
+ });
140
+ });
141
+ });
142
+
143
+ describe('createMock', () => {
144
+ it('should create a mock function', () => {
145
+ const mock = createMock();
146
+ expect(typeof mock).toBe('function');
147
+ });
148
+
149
+ it('should track calls', () => {
150
+ const mock = createMock();
151
+ mock(1, 2);
152
+ mock('a', 'b');
153
+
154
+ expect(mock.calls).toHaveLength(2);
155
+ expect(mock.calls[0]).toEqual([1, 2]);
156
+ expect(mock.calls[1]).toEqual(['a', 'b']);
157
+ });
158
+
159
+ it('should track results', () => {
160
+ const mock = createMock(() => 42);
161
+ const result = mock();
162
+
163
+ expect(result).toBe(42);
164
+ expect(mock.results).toHaveLength(1);
165
+ expect(mock.results[0]).toEqual({ type: 'return', value: 42 });
166
+ });
167
+
168
+ it('should track thrown errors', () => {
169
+ const error = new Error('test');
170
+ const mock = createMock(() => {
171
+ throw error;
172
+ });
173
+
174
+ expect(() => mock()).toThrow(error);
175
+ expect(mock.results[0]).toEqual({ type: 'throw', value: error });
176
+ });
177
+
178
+ it('should support mockReturnValue', () => {
179
+ const mock = createMock();
180
+ mock.mockReturnValue(123);
181
+
182
+ expect(mock()).toBe(123);
183
+ expect(mock()).toBe(123);
184
+ });
185
+
186
+ it('should support mockReturnValueOnce', () => {
187
+ const mock = createMock().mockReturnValue('default');
188
+ mock.mockReturnValueOnce('once');
189
+
190
+ expect(mock()).toBe('once');
191
+ expect(mock()).toBe('default');
192
+ });
193
+
194
+ it('should support mockResolvedValue', async () => {
195
+ const mock = createMock();
196
+ mock.mockResolvedValue('resolved');
197
+
198
+ await expect(mock()).resolves.toBe('resolved');
199
+ });
200
+
201
+ it('should support mockRejectedValue', async () => {
202
+ const mock = createMock();
203
+ const error = new Error('rejected');
204
+ mock.mockRejectedValue(error);
205
+
206
+ await expect(mock()).rejects.toThrow(error);
207
+ });
208
+
209
+ it('should support mockImplementation', () => {
210
+ const mock = createMock();
211
+ mock.mockImplementation((x: number) => x * 2);
212
+
213
+ expect(mock(5)).toBe(10);
214
+ expect(mock(3)).toBe(6);
215
+ });
216
+
217
+ it('should support mockClear', () => {
218
+ const mock = createMock();
219
+ mock(1);
220
+ mock(2);
221
+
222
+ mock.mockClear();
223
+
224
+ expect(mock.calls).toHaveLength(0);
225
+ expect(mock.results).toHaveLength(0);
226
+ });
227
+
228
+ it('should support mockReset', () => {
229
+ const mock = createMock(() => 42);
230
+ mock.mockReturnValue(100);
231
+ mock();
232
+
233
+ mock.mockReset();
234
+
235
+ expect(mock.calls).toHaveLength(0);
236
+ expect(mock()).toBeUndefined();
237
+ });
238
+
239
+ it('should support mockRestore', () => {
240
+ const originalFn = (x: number) => x * 2;
241
+ const mock = createMock(originalFn);
242
+ mock.mockReturnValue(100);
243
+ mock();
244
+
245
+ mock.mockRestore();
246
+
247
+ expect(mock.calls).toHaveLength(0);
248
+ expect(mock(5)).toBe(10);
249
+ });
250
+ });
251
+
252
+ describe('createSpy', () => {
253
+ it('should spy on object methods', () => {
254
+ const obj = {
255
+ greet(name: string) {
256
+ return `Hello, ${name}!`;
257
+ },
258
+ };
259
+
260
+ const spy = createSpy(obj, 'greet');
261
+
262
+ expect(obj.greet('World')).toBe('Hello, World!');
263
+ expect(spy.calls).toHaveLength(1);
264
+ expect(spy.calls[0]).toEqual(['World']);
265
+ });
266
+
267
+ it('should store original function', () => {
268
+ const original = function greet() {
269
+ return 'hello';
270
+ };
271
+ const obj = { greet: original };
272
+
273
+ const spy = createSpy(obj, 'greet');
274
+ expect(spy.original).toBe(original);
275
+ });
276
+
277
+ it('should restore original on mockRestore', () => {
278
+ const original = function greet() {
279
+ return 'hello';
280
+ };
281
+ const obj = { greet: original };
282
+
283
+ const spy = createSpy(obj, 'greet');
284
+ spy.mockReturnValue('mocked');
285
+
286
+ expect(obj.greet()).toBe('mocked');
287
+
288
+ spy.mockRestore();
289
+ expect(obj.greet).toBe(original);
290
+ });
291
+ });
292
+
293
+ describe('waitFor', () => {
294
+ it('should resolve when condition is true', async () => {
295
+ let counter = 0;
296
+ const condition = () => {
297
+ counter++;
298
+ return counter >= 3;
299
+ };
300
+
301
+ await waitFor(condition, { interval: 10, timeout: 1000 });
302
+ expect(counter).toBe(3);
303
+ });
304
+
305
+ it('should throw on timeout', async () => {
306
+ const condition = () => false;
307
+
308
+ await expect(waitFor(condition, { timeout: 50, interval: 10 })).rejects.toThrow(
309
+ /not met within/
310
+ );
311
+ });
312
+
313
+ it('should handle async conditions', async () => {
314
+ let counter = 0;
315
+ const condition = async () => {
316
+ counter++;
317
+ return counter >= 2;
318
+ };
319
+
320
+ await waitFor(condition, { interval: 10, timeout: 1000 });
321
+ expect(counter).toBe(2);
322
+ });
323
+
324
+ it('should use default timeout and interval', async () => {
325
+ let called = false;
326
+ const condition = () => {
327
+ called = true;
328
+ return true;
329
+ };
330
+
331
+ await waitFor(condition);
332
+ expect(called).toBe(true);
333
+ });
334
+ });
335
+
336
+ describe('fixture', () => {
337
+ it('should create fixture with setup', async () => {
338
+ const myFixture = fixture('db', () => ({ connected: true }));
339
+
340
+ expect(myFixture.name).toBe('db');
341
+ const instance = await myFixture.create();
342
+ expect(instance).toEqual({ connected: true });
343
+ });
344
+
345
+ it('should support async setup', async () => {
346
+ const myFixture = fixture('async', async () => {
347
+ await new Promise(r => setTimeout(r, 10));
348
+ return { loaded: true };
349
+ });
350
+
351
+ const instance = await myFixture.create();
352
+ expect(instance.loaded).toBe(true);
353
+ });
354
+
355
+ it('should call teardown on destroy', async () => {
356
+ const teardownCalled = { value: false };
357
+ const myFixture = fixture(
358
+ 'teardown-test',
359
+ () => ({ id: 1 }),
360
+ () => {
361
+ teardownCalled.value = true;
362
+ }
363
+ );
364
+
365
+ const instance = await myFixture.create();
366
+ await myFixture.destroy(instance);
367
+
368
+ expect(teardownCalled.value).toBe(true);
369
+ });
370
+ });
371
+
372
+ describe('createPageObject', () => {
373
+ it('should create page object with selectors', () => {
374
+ const loginPage = createPageObject({
375
+ name: 'LoginPage',
376
+ url: '/login',
377
+ selectors: {
378
+ username: '#username',
379
+ password: '#password',
380
+ submitBtn: 'button[type="submit"]',
381
+ },
382
+ actions: {},
383
+ assertions: {},
384
+ });
385
+
386
+ expect(loginPage.name).toBe('LoginPage');
387
+ expect(loginPage.element('username')).toBe('#username');
388
+ expect(loginPage.element('password')).toBe('#password');
389
+ });
390
+
391
+ it('should throw for unknown selector', () => {
392
+ const page = createPageObject({
393
+ name: 'Page',
394
+ selectors: { known: '#known' },
395
+ actions: {},
396
+ assertions: {},
397
+ });
398
+
399
+ expect(() => page.element('unknown')).toThrow(/not found/);
400
+ });
401
+ });
402
+
403
+ describe('createLokaScriptTestContext', () => {
404
+ it('should create context with compile and test methods', () => {
405
+ const mockHyperFixi = {
406
+ compile: async (script: string) => `compiled: ${script}`,
407
+ };
408
+
409
+ const context = createLokaScriptTestContext(mockHyperFixi);
410
+
411
+ expect(context.compileAndTest).toBeDefined();
412
+ expect(context.testCompilation).toBeDefined();
413
+ expect(context.testExecution).toBeDefined();
414
+ });
415
+
416
+ it('should test compilation', async () => {
417
+ const mockHyperFixi = {
418
+ compile: async (script: string) => `compiled: ${script}`,
419
+ };
420
+
421
+ const context = createLokaScriptTestContext(mockHyperFixi);
422
+ const result = await context.testCompilation('on click log "hello"');
423
+
424
+ expect(result.success).toBe(true);
425
+ expect(result.result).toBe('compiled: on click log "hello"');
426
+ });
427
+
428
+ it('should handle compilation errors', async () => {
429
+ const mockHyperFixi = {
430
+ compile: async () => {
431
+ throw new Error('Syntax error');
432
+ },
433
+ };
434
+
435
+ const context = createLokaScriptTestContext(mockHyperFixi);
436
+ const result = await context.testCompilation('invalid script');
437
+
438
+ expect(result.success).toBe(false);
439
+ expect(result.error).toBeDefined();
440
+ });
441
+ });
442
+
443
+ describe('quickStartTesting', () => {
444
+ afterEach(() => {
445
+ clearTests();
446
+ });
447
+
448
+ it('should return testing utilities', async () => {
449
+ const testing = await quickStartTesting();
450
+
451
+ expect(testing.config).toBeDefined();
452
+ expect(testing.run).toBeDefined();
453
+ expect(testing.clear).toBeDefined();
454
+ });
455
+
456
+ it('should use provided environment', async () => {
457
+ const testing = await quickStartTesting({ environment: 'node' });
458
+ expect(testing.config.environment).toBe('node');
459
+ });
460
+
461
+ it('should use provided browser', async () => {
462
+ const testing = await quickStartTesting({ browser: 'firefox' });
463
+ expect(testing.config.browser).toBe('firefox');
464
+ });
465
+
466
+ it('should default to headless mode', async () => {
467
+ const testing = await quickStartTesting();
468
+ expect(testing.config.headless).toBe(true);
469
+ });
470
+
471
+ it('should allow disabling headless', async () => {
472
+ const testing = await quickStartTesting({ headless: false });
473
+ expect(testing.config.headless).toBe(false);
474
+ });
475
+ });
476
+
477
+ describe('Constants', () => {
478
+ it('should export VERSION', () => {
479
+ expect(VERSION).toBe('0.1.0');
480
+ });
481
+
482
+ it('should export DEFAULT_CONFIG', () => {
483
+ expect(DEFAULT_CONFIG).toBeDefined();
484
+ expect(DEFAULT_CONFIG.environment).toBe('jsdom');
485
+ expect(DEFAULT_CONFIG.timeout).toBe(5000);
486
+ expect(DEFAULT_CONFIG.retries).toBe(0);
487
+ expect(DEFAULT_CONFIG.parallel).toBe(false);
488
+ expect(DEFAULT_CONFIG.headless).toBe(true);
489
+ });
490
+ });