@git.zone/tstest 1.5.0 → 1.8.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 (68) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/index.js +9 -2
  3. package/dist_ts/tstest.classes.tap.parser.d.ts +4 -0
  4. package/dist_ts/tstest.classes.tap.parser.js +114 -24
  5. package/dist_ts/tstest.classes.testdirectory.d.ts +10 -0
  6. package/dist_ts/tstest.classes.testdirectory.js +31 -1
  7. package/dist_ts/tstest.classes.tstest.d.ts +3 -1
  8. package/dist_ts/tstest.classes.tstest.js +52 -27
  9. package/dist_ts_tapbundle/index.d.ts +1 -0
  10. package/dist_ts_tapbundle/index.js +2 -1
  11. package/dist_ts_tapbundle/tapbundle.classes.tap.d.ts +54 -1
  12. package/dist_ts_tapbundle/tapbundle.classes.tap.js +288 -24
  13. package/dist_ts_tapbundle/tapbundle.classes.taptest.d.ts +7 -1
  14. package/dist_ts_tapbundle/tapbundle.classes.taptest.js +75 -27
  15. package/dist_ts_tapbundle/tapbundle.classes.taptools.d.ts +81 -1
  16. package/dist_ts_tapbundle/tapbundle.classes.taptools.js +180 -2
  17. package/dist_ts_tapbundle/ts_tapbundle/00_commitinfo_data.d.ts +8 -0
  18. package/dist_ts_tapbundle/ts_tapbundle/00_commitinfo_data.js +9 -0
  19. package/dist_ts_tapbundle/ts_tapbundle/index.d.ts +6 -0
  20. package/dist_ts_tapbundle/ts_tapbundle/index.js +7 -0
  21. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.pretask.d.ts +10 -0
  22. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.pretask.js +13 -0
  23. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tap.d.ts +104 -0
  24. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tap.js +401 -0
  25. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptest.d.ts +38 -0
  26. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptest.js +110 -0
  27. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptools.d.ts +109 -0
  28. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptools.js +241 -0
  29. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tapwrap.d.ts +8 -0
  30. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tapwrap.js +7 -0
  31. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.plugins.d.ts +8 -0
  32. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.plugins.js +10 -0
  33. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.tapcreator.d.ts +3 -0
  34. package/dist_ts_tapbundle/ts_tapbundle/tapbundle.tapcreator.js +5 -0
  35. package/dist_ts_tapbundle/ts_tapbundle/webhelpers.d.ts +7 -0
  36. package/dist_ts_tapbundle/ts_tapbundle/webhelpers.js +35 -0
  37. package/dist_ts_tapbundle/ts_tapbundle_node/classes.pathinject.d.ts +5 -0
  38. package/dist_ts_tapbundle/ts_tapbundle_node/classes.pathinject.js +13 -0
  39. package/dist_ts_tapbundle/ts_tapbundle_node/plugins.d.ts +11 -0
  40. package/dist_ts_tapbundle/ts_tapbundle_node/plugins.js +14 -0
  41. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.classes.taptest.d.ts +38 -0
  42. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.classes.taptest.js +110 -0
  43. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.classes.taptools.d.ts +109 -0
  44. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.classes.taptools.js +241 -0
  45. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.plugins.d.ts +8 -0
  46. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.plugins.js +10 -0
  47. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.tapcreator.d.ts +3 -0
  48. package/dist_ts_tapbundle_node/ts_tapbundle/tapbundle.tapcreator.js +5 -0
  49. package/dist_ts_tapbundle_node/ts_tapbundle_node/classes.pathinject.d.ts +5 -0
  50. package/dist_ts_tapbundle_node/ts_tapbundle_node/classes.pathinject.js +13 -0
  51. package/dist_ts_tapbundle_node/ts_tapbundle_node/classes.tapnodetools.d.ts +25 -0
  52. package/dist_ts_tapbundle_node/ts_tapbundle_node/classes.tapnodetools.js +81 -0
  53. package/dist_ts_tapbundle_node/ts_tapbundle_node/classes.testfileprovider.d.ts +6 -0
  54. package/dist_ts_tapbundle_node/ts_tapbundle_node/classes.testfileprovider.js +16 -0
  55. package/dist_ts_tapbundle_node/ts_tapbundle_node/index.d.ts +2 -0
  56. package/dist_ts_tapbundle_node/ts_tapbundle_node/index.js +3 -0
  57. package/dist_ts_tapbundle_node/ts_tapbundle_node/paths.d.ts +2 -0
  58. package/dist_ts_tapbundle_node/ts_tapbundle_node/paths.js +4 -0
  59. package/dist_ts_tapbundle_node/ts_tapbundle_node/plugins.d.ts +11 -0
  60. package/dist_ts_tapbundle_node/ts_tapbundle_node/plugins.js +14 -0
  61. package/package.json +11 -8
  62. package/readme.md +141 -0
  63. package/readme.plan.md +253 -30
  64. package/ts/00_commitinfo_data.ts +1 -1
  65. package/ts/index.ts +8 -1
  66. package/ts/tstest.classes.tap.parser.ts +111 -25
  67. package/ts/tstest.classes.testdirectory.ts +39 -0
  68. package/ts/tstest.classes.tstest.ts +61 -27
@@ -0,0 +1,16 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as paths from './paths.js';
3
+ export const fileUrls = {
4
+ dockerAlpineImage: 'https://code.foss.global/testassets/docker/raw/branch/main/alpine.tar',
5
+ };
6
+ export class TestFileProvider {
7
+ async getDockerAlpineImageAsLocalTarball() {
8
+ const filePath = plugins.path.join(paths.testFilesDir, 'alpine.tar');
9
+ // fetch the docker alpine image
10
+ const response = await plugins.smartrequest.getBinary(fileUrls.dockerAlpineImage);
11
+ await plugins.smartfile.fs.ensureDir(paths.testFilesDir);
12
+ await plugins.smartfile.memory.toFs(response.body, filePath);
13
+ return filePath;
14
+ }
15
+ }
16
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50ZXN0ZmlsZXByb3ZpZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfdGFwYnVuZGxlX25vZGUvY2xhc3Nlcy50ZXN0ZmlsZXByb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxLQUFLLE1BQU0sWUFBWSxDQUFDO0FBRXBDLE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRztJQUN0QixpQkFBaUIsRUFBRSx1RUFBdUU7Q0FDM0YsQ0FBQTtBQUVELE1BQU0sT0FBTyxnQkFBZ0I7SUFDcEIsS0FBSyxDQUFDLGtDQUFrQztRQUM3QyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFBO1FBQ3BFLGdDQUFnQztRQUNoQyxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ2xGLE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN6RCxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzdELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7Q0FDRiJ9
@@ -0,0 +1,2 @@
1
+ export * from './classes.tapnodetools.js';
2
+ export * from './classes.pathinject.js';
@@ -0,0 +1,3 @@
1
+ export * from './classes.tapnodetools.js';
2
+ export * from './classes.pathinject.js';
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c190YXBidW5kbGVfbm9kZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMseUJBQXlCLENBQUMifQ==
@@ -0,0 +1,2 @@
1
+ export declare const cwd: string;
2
+ export declare const testFilesDir: string;
@@ -0,0 +1,4 @@
1
+ import * as plugins from './plugins.js';
2
+ export const cwd = process.cwd();
3
+ export const testFilesDir = plugins.path.join(cwd, './.nogit/testfiles/');
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c190YXBidW5kbGVfbm9kZS9wYXRocy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxNQUFNLENBQUMsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQ2pDLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUscUJBQXFCLENBQUMsQ0FBQyJ9
@@ -0,0 +1,11 @@
1
+ import * as crypto from 'crypto';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ export { crypto, fs, path, };
5
+ import * as qenv from '@push.rocks/qenv';
6
+ import * as smartcrypto from '@push.rocks/smartcrypto';
7
+ import * as smartfile from '@push.rocks/smartfile';
8
+ import * as smartpath from '@push.rocks/smartpath';
9
+ import * as smartrequest from '@push.rocks/smartrequest';
10
+ import * as smartshell from '@push.rocks/smartshell';
11
+ export { qenv, smartcrypto, smartfile, smartpath, smartrequest, smartshell, };
@@ -0,0 +1,14 @@
1
+ // node native
2
+ import * as crypto from 'crypto';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ export { crypto, fs, path, };
6
+ // @push.rocks scope
7
+ import * as qenv from '@push.rocks/qenv';
8
+ import * as smartcrypto from '@push.rocks/smartcrypto';
9
+ import * as smartfile from '@push.rocks/smartfile';
10
+ import * as smartpath from '@push.rocks/smartpath';
11
+ import * as smartrequest from '@push.rocks/smartrequest';
12
+ import * as smartshell from '@push.rocks/smartshell';
13
+ export { qenv, smartcrypto, smartfile, smartpath, smartrequest, smartshell, };
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX3RhcGJ1bmRsZV9ub2RlL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYztBQUNkLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQ2pDLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3pCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLE9BQU8sRUFBRSxNQUFNLEVBQUMsRUFBRSxFQUFFLElBQUksR0FBRyxDQUFDO0FBRTVCLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssSUFBSSxNQUFNLGtCQUFrQixDQUFDO0FBQ3pDLE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxLQUFLLFNBQVMsTUFBTSx1QkFBdUIsQ0FBQztBQUNuRCxPQUFPLEtBQUssU0FBUyxNQUFNLHVCQUF1QixDQUFDO0FBQ25ELE9BQU8sS0FBSyxZQUFZLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxVQUFVLEdBQUcsQ0FBQyJ9
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@git.zone/tstest",
3
- "version": "1.5.0",
3
+ "version": "1.8.0",
4
4
  "private": false,
5
5
  "description": "a test utility to run tests that match test/**/*.ts",
6
- "main": "dist_ts/index.js",
7
- "typings": "dist_ts/index.d.ts",
6
+ "exports": {
7
+ ".": "./dist_ts/index.js",
8
+ "./tapbundle": "./dist_ts_tapbundle/index.js",
9
+ "./tapbundle_node": "./dist_ts_tapbundle_node/index.js"
10
+ },
8
11
  "type": "module",
9
12
  "author": "Lossless GmbH",
10
13
  "license": "MIT",
@@ -56,11 +59,11 @@
56
59
  "last 1 chrome versions"
57
60
  ],
58
61
  "scripts": {
59
- "test": "pnpm run build && pnpm run test:tapbundle && pnpm run test:tstest",
60
- "test:tapbundle": "tsx ./cli.child.ts test/tapbundle/**/*.ts",
61
- "test:tapbundle:verbose": "tsx ./cli.child.ts test/tapbundle/**/*.ts --verbose",
62
- "test:tstest": "tsx ./cli.child.ts test/tstest/**/*.ts",
63
- "test:tstest:verbose": "tsx ./cli.child.ts test/tstest/**/*.ts --verbose",
62
+ "test": "pnpm run build && pnpm run test:tapbundle:verbose && pnpm run test:tstest:verbose",
63
+ "test:tapbundle": "tsx ./cli.child.ts \"test/tapbundle/**/*.ts\"",
64
+ "test:tapbundle:verbose": "tsx ./cli.child.ts \"test/tapbundle/**/*.ts\" --verbose",
65
+ "test:tstest": "tsx ./cli.child.ts \"test/tstest/**/*.ts\"",
66
+ "test:tstest:verbose": "tsx ./cli.child.ts \"test/tstest/**/*.ts\" --verbose",
64
67
  "build": "(tsbuild tsfolders)",
65
68
  "buildDocs": "tsdoc"
66
69
  }
package/readme.md CHANGED
@@ -19,6 +19,14 @@
19
19
  - 📝 **Detailed Logging** - Optional file logging for debugging
20
20
  - ⚡ **Performance Metrics** - See which tests are slow
21
21
  - 🤖 **CI/CD Ready** - JSON output mode for automation
22
+ - 🏷️ **Tag-based Filtering** - Run only tests with specific tags
23
+ - 🎯 **Parallel Test Execution** - Run tests in parallel groups
24
+ - 🔧 **Test Lifecycle Hooks** - beforeEach/afterEach support
25
+ - 📸 **Snapshot Testing** - Compare test outputs with saved snapshots
26
+ - ⏳ **Timeout Control** - Set custom timeouts for tests
27
+ - 🔁 **Retry Logic** - Automatically retry failing tests
28
+ - 🛠️ **Test Fixtures** - Create reusable test data
29
+ - 📦 **Browser-Compatible** - Full browser support for tapbundle
22
30
 
23
31
  ## Installation
24
32
 
@@ -61,6 +69,7 @@ tstest "test/unit/*.ts"
61
69
  | `--no-color` | Disable colored output |
62
70
  | `--json` | Output results as JSON |
63
71
  | `--logfile` | Save detailed logs to `.nogit/testlogs/[testname].log` |
72
+ | `--tags <tags>` | Run only tests with specific tags (comma-separated) |
64
73
 
65
74
  ### Example Outputs
66
75
 
@@ -147,6 +156,103 @@ tap.test('my awesome test', async () => {
147
156
  tap.start();
148
157
  ```
149
158
 
159
+ #### Test Features
160
+
161
+ **Tag-based Test Filtering**
162
+ ```typescript
163
+ tap.tags('unit', 'api')
164
+ .test('should handle API requests', async () => {
165
+ // Test code
166
+ });
167
+
168
+ // Run with: tstest test/ --tags unit,api
169
+ ```
170
+
171
+ **Test Lifecycle Hooks**
172
+ ```typescript
173
+ tap.describe('User API Tests', () => {
174
+ let testUser;
175
+
176
+ tap.beforeEach(async () => {
177
+ testUser = await createTestUser();
178
+ });
179
+
180
+ tap.afterEach(async () => {
181
+ await deleteTestUser(testUser.id);
182
+ });
183
+
184
+ tap.test('should update user profile', async () => {
185
+ // Test code using testUser
186
+ });
187
+ });
188
+ ```
189
+
190
+ **Parallel Test Execution**
191
+ ```typescript
192
+ // Files with matching parallel group names run concurrently
193
+ // test.auth.para__1.ts
194
+ tap.test('authentication test', async () => { /* ... */ });
195
+
196
+ // test.user.para__1.ts
197
+ tap.test('user operations test', async () => { /* ... */ });
198
+ ```
199
+
200
+ **Test Timeouts and Retries**
201
+ ```typescript
202
+ tap.timeout(5000)
203
+ .retry(3)
204
+ .test('flaky network test', async (tools) => {
205
+ // This test has 5 seconds to complete and will retry up to 3 times
206
+ });
207
+ ```
208
+
209
+ **Snapshot Testing**
210
+ ```typescript
211
+ tap.test('should match snapshot', async (tools) => {
212
+ const result = await generateReport();
213
+ await tools.matchSnapshot(result);
214
+ });
215
+ ```
216
+
217
+ **Test Fixtures**
218
+ ```typescript
219
+ // Define a reusable fixture
220
+ tap.defineFixture('testUser', async () => ({
221
+ id: 1,
222
+ name: 'Test User',
223
+ email: 'test@example.com'
224
+ }));
225
+
226
+ tap.test('user test', async (tools) => {
227
+ const user = tools.fixture('testUser');
228
+ expect(user.name).toEqual('Test User');
229
+ });
230
+ ```
231
+
232
+ **Skipping and Todo Tests**
233
+ ```typescript
234
+ tap.skip.test('work in progress', async () => {
235
+ // This test will be skipped
236
+ });
237
+
238
+ tap.todo('implement user deletion', async () => {
239
+ // This marks a test as todo
240
+ });
241
+ ```
242
+
243
+ **Browser Testing**
244
+ ```typescript
245
+ // test.browser.ts
246
+ import { tap, webhelpers } from '@push.rocks/tapbundle';
247
+
248
+ tap.test('DOM manipulation', async () => {
249
+ const element = await webhelpers.fixture(webhelpers.html`
250
+ <div>Hello World</div>
251
+ `);
252
+ expect(element).toBeInstanceOf(HTMLElement);
253
+ });
254
+ ```
255
+
150
256
  ## Advanced Features
151
257
 
152
258
  ### Glob Pattern Support
@@ -163,6 +269,8 @@ tstest "test/integration/*.test.ts"
163
269
  tstest "test/**/*.spec.ts" "test/**/*.test.ts"
164
270
  ```
165
271
 
272
+ **Important**: Always quote glob patterns to prevent shell expansion. Without quotes, the shell will expand the pattern and only pass the first matching file to tstest.
273
+
166
274
  ### Automatic Logging
167
275
 
168
276
  Use `--logfile` to automatically save test output:
@@ -181,6 +289,26 @@ In verbose mode, see performance metrics:
181
289
  Slowest test: api integration test (486ms)
182
290
  ```
183
291
 
292
+ ### Parallel Test Groups
293
+
294
+ Tests can be organized into parallel groups for concurrent execution:
295
+
296
+ ```
297
+ ━━━ Parallel Group: para__1 ━━━
298
+ ▶️ test/auth.para__1.ts
299
+ ▶️ test/user.para__1.ts
300
+ ... tests run concurrently ...
301
+ ──────────────────────────────────
302
+
303
+ ━━━ Parallel Group: para__2 ━━━
304
+ ▶️ test/db.para__2.ts
305
+ ▶️ test/api.para__2.ts
306
+ ... tests run concurrently ...
307
+ ──────────────────────────────────
308
+ ```
309
+
310
+ Files with the same parallel group suffix (e.g., `para__1`) run simultaneously, while different groups run sequentially.
311
+
184
312
  ### CI/CD Integration
185
313
 
186
314
  For continuous integration, combine quiet and JSON modes:
@@ -192,6 +320,19 @@ tstest test/ --json > test-results.json
192
320
  tstest test/ --quiet
193
321
  ```
194
322
 
323
+ ## Changelog
324
+
325
+ ### Version 1.7.0
326
+ - 🎉 Made `@push.rocks/tapbundle` fully browser-compatible
327
+ - 📸 Added snapshot testing with base64-encoded communication protocol
328
+ - 🏷️ Introduced tag-based test filtering
329
+ - 🔧 Enhanced test lifecycle hooks (beforeEach/afterEach)
330
+ - 🎯 Fixed parallel test execution and grouping
331
+ - ⏳ Improved timeout and retry mechanisms
332
+ - 🛠️ Added test fixtures for reusable test data
333
+ - 📊 Enhanced TAP parser for better test reporting
334
+ - 🐛 Fixed glob pattern handling in shell scripts
335
+
195
336
  ## Contribution
196
337
 
197
338
  We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
package/readme.plan.md CHANGED
@@ -1,41 +1,264 @@
1
- # Plan for showing logs for failed tests
1
+ # Improvement Plan for tstest and tapbundle
2
2
 
3
3
  !! FIRST: Reread /home/philkunz/.claude/CLAUDE.md to ensure following all guidelines !!
4
4
 
5
- ## Goal
6
- When a test fails, we want to display all the console logs from that failed test in the terminal, even without the --verbose flag. This makes debugging failed tests much easier.
5
+ ## 1. Enhanced Communication Between tapbundle and tstest
7
6
 
8
- ## Current Behavior
9
- - Default mode: Only shows test results, no console logs
10
- - Verbose mode: Shows all console logs from all tests
11
- - When a test fails: Only shows the error message
7
+ ### 1.1 Real-time Test Progress API
8
+ - Create a bidirectional communication channel between tapbundle and tstest
9
+ - Emit events for test lifecycle stages (start, progress, completion)
10
+ - Allow tstest to subscribe to tapbundle events for better progress reporting
11
+ - Implement a standardized message format for test metadata
12
12
 
13
- ## Desired Behavior
14
- - Default mode: Shows test results, and IF a test fails, shows all console logs from that failed test
15
- - Verbose mode: Shows all console logs from all tests (unchanged)
16
- - When a test fails: Shows all console logs from that test plus the error
13
+ ### 1.2 Rich Error Reporting
14
+ - Pass structured error objects from tapbundle to tstest
15
+ - Include stack traces, code snippets, and contextual information
16
+ - Support for error categorization (assertion failures, timeouts, uncaught exceptions)
17
+ - Visual diff output for failed assertions
17
18
 
18
- ## Implementation Plan
19
+ ## 2. Enhanced toolsArg Functionality
19
20
 
20
- ### 1. Update TapParser
21
- - Store console logs for each test temporarily
22
- - When a test fails, mark that its logs should be shown
21
+ ### 2.1 Test Flow Control ✅
22
+ ```typescript
23
+ tap.test('conditional test', async (toolsArg) => {
24
+ const result = await someOperation();
25
+
26
+ // Skip the rest of the test
27
+ if (!result) {
28
+ return toolsArg.skip('Precondition not met');
29
+ }
30
+
31
+ // Conditional skipping
32
+ await toolsArg.skipIf(condition, 'Reason for skipping');
33
+
34
+ // Mark test as todo
35
+ await toolsArg.todo('Not implemented yet');
36
+ });
37
+ ```
23
38
 
24
- ### 2. Update TsTestLogger
25
- - Add a new method to handle failed test logs
26
- - Modify testConsoleOutput to buffer logs when not in verbose mode
27
- - When a test fails, flush the buffered logs for that test
39
+ ### 2.2 Test Metadata and Configuration ✅
40
+ ```typescript
41
+ // Fluent syntax
42
+ tap.tags('slow', 'integration')
43
+ .priority('high')
44
+ .timeout(5000)
45
+ .retry(3)
46
+ .test('configurable test', async (toolsArg) => {
47
+ // Test implementation
48
+ });
49
+ ```
28
50
 
29
- ### 3. Update test result handling
30
- - When a test fails, trigger display of all buffered logs for that test
31
- - Clear logs after each test completes successfully
51
+ ### 2.3 Test Data and Context Sharing ✅
52
+ ```typescript
53
+ tap.test('data-driven test', async (toolsArg) => {
54
+ // Access shared context ✅
55
+ const sharedData = toolsArg.context.get('sharedData');
56
+
57
+ // Set data for other tests ✅
58
+ toolsArg.context.set('resultData', computedValue);
59
+
60
+ // Parameterized test data (not yet implemented)
61
+ const testData = toolsArg.data<TestInput>();
62
+ expect(processData(testData)).toEqual(expected);
63
+ });
64
+ ```
32
65
 
33
- ## Code Changes Needed
34
- 1. Add log buffering to TapParser
35
- 2. Update TsTestLogger to handle failed test logs
36
- 3. Modify test result processing to show logs on failure
66
+ ## 3. Nested Tests and Test Suites
37
67
 
38
- ## Files to Modify
39
- - `ts/tstest.classes.tap.parser.ts` - Add log buffering
40
- - `ts/tstest.logging.ts` - Add failed test log handling
41
- - `ts/tstest.classes.tap.testresult.ts` - May need to store logs
68
+ ### 3.1 Test Grouping with describe() ✅
69
+ ```typescript
70
+ tap.describe('User Authentication', () => {
71
+ tap.beforeEach(async (toolsArg) => {
72
+ // Setup for each test in this suite
73
+ await toolsArg.context.set('db', await createTestDatabase());
74
+ });
75
+
76
+ tap.afterEach(async (toolsArg) => {
77
+ // Cleanup after each test
78
+ await toolsArg.context.get('db').cleanup();
79
+ });
80
+
81
+ tap.test('should login with valid credentials', async (toolsArg) => {
82
+ // Test implementation
83
+ });
84
+
85
+ tap.describe('Password Reset', () => {
86
+ tap.test('should send reset email', async (toolsArg) => {
87
+ // Nested test
88
+ });
89
+ });
90
+ });
91
+ ```
92
+
93
+ ### 3.2 Hierarchical Test Organization
94
+ - Support for multiple levels of nesting
95
+ - Inherited context and configuration from parent suites
96
+ - Aggregated reporting for test suites
97
+ - Suite-level lifecycle hooks
98
+
99
+ ## 4. Advanced Test Features
100
+
101
+ ### 4.1 Snapshot Testing
102
+ ```typescript
103
+ tap.test('component render', async (toolsArg) => {
104
+ const output = renderComponent(props);
105
+
106
+ // Compare with stored snapshot
107
+ await toolsArg.matchSnapshot(output, 'component-output');
108
+ });
109
+ ```
110
+
111
+ ### 4.2 Performance Benchmarking
112
+ ```typescript
113
+ tap.test('performance test', async (toolsArg) => {
114
+ const benchmark = toolsArg.benchmark();
115
+
116
+ // Run operation
117
+ await expensiveOperation();
118
+
119
+ // Assert performance constraints
120
+ benchmark.expect({
121
+ maxDuration: 1000,
122
+ maxMemory: '100MB'
123
+ });
124
+ });
125
+ ```
126
+
127
+ ### 4.3 Test Fixtures and Factories ✅
128
+ ```typescript
129
+ tap.test('with fixtures', async (toolsArg) => {
130
+ // Create test fixtures
131
+ const user = await toolsArg.fixture('user', { name: 'Test User' });
132
+ const post = await toolsArg.fixture('post', { author: user });
133
+
134
+ // Use factory functions
135
+ const users = await toolsArg.factory('user').createMany(5);
136
+ });
137
+ ```
138
+
139
+ ## 5. Test Execution Improvements
140
+
141
+ ### 5.1 Parallel Test Execution ✅
142
+ - Run independent tests concurrently ✅
143
+ - Configurable concurrency limits (via file naming convention)
144
+ - Resource pooling for shared resources
145
+ - Proper isolation between parallel tests ✅
146
+
147
+ Implementation:
148
+ - Tests with `para__<groupNumber>` in filename run in parallel
149
+ - Different groups run sequentially
150
+ - Tests without `para__` run serially
151
+
152
+ ### 5.2 Watch Mode
153
+ - Automatically re-run tests on file changes
154
+ - Intelligent test selection based on changed files
155
+ - Fast feedback loop for development
156
+ - Integration with IDE/editor plugins
157
+
158
+ ### 5.3 Advanced Test Filtering ✅ (partially)
159
+ ```typescript
160
+ // Run tests by tags ✅
161
+ tstest --tags "unit,fast"
162
+
163
+ // Exclude tests by pattern (not yet implemented)
164
+ tstest --exclude "**/slow/**"
165
+
166
+ // Run only failed tests from last run (not yet implemented)
167
+ tstest --failed
168
+
169
+ // Run tests modified in git (not yet implemented)
170
+ tstest --changed
171
+ ```
172
+
173
+ ## 6. Reporting and Analytics
174
+
175
+ ### 6.1 Custom Reporters
176
+ - Plugin architecture for custom reporters
177
+ - Built-in reporters: JSON, JUnit, HTML, Markdown
178
+ - Real-time streaming reporters
179
+ - Aggregated test metrics and trends
180
+
181
+ ### 6.2 Coverage Integration
182
+ - Built-in code coverage collection
183
+ - Coverage thresholds and enforcement
184
+ - Coverage trending over time
185
+ - Integration with CI/CD pipelines
186
+
187
+ ### 6.3 Test Analytics Dashboard
188
+ - Web-based dashboard for test results
189
+ - Historical test performance data
190
+ - Flaky test detection
191
+ - Test impact analysis
192
+
193
+ ## 7. Developer Experience
194
+
195
+ ### 7.1 Better Error Messages
196
+ - Clear, actionable error messages
197
+ - Suggestions for common issues
198
+ - Links to documentation
199
+ - Code examples in error output
200
+
201
+ ### 7.2 Interactive Mode (Needs Detailed Specification)
202
+ - REPL for exploring test failures
203
+ - Need to define: How to enter interactive mode? When tests fail?
204
+ - What commands/features should be available in the REPL?
205
+ - Debugging integration
206
+ - Node.js inspector protocol integration?
207
+ - Breakpoint support?
208
+ - Step-through test execution
209
+ - Pause between tests?
210
+ - Step into/over/out functionality?
211
+ - Interactive test data manipulation
212
+ - Modify test inputs on the fly?
213
+ - Inspect intermediate values?
214
+
215
+ ### 7.3 ~~VS Code Extension~~ (Scratched)
216
+ - ~~Test explorer integration~~
217
+ - ~~Inline test results~~
218
+ - ~~CodeLens for running individual tests~~
219
+ - ~~Debugging support~~
220
+
221
+ ## Implementation Phases
222
+
223
+ ### Phase 1: Core Enhancements (Priority: High) ✅
224
+ 1. Implement enhanced toolsArg methods (skip, skipIf, timeout, retry) ✅
225
+ 2. Add basic test grouping with describe() ✅
226
+ 3. Improve error reporting between tapbundle and tstest ✅
227
+
228
+ ### Phase 2: Advanced Features (Priority: Medium)
229
+ 1. Implement nested test suites ✅ (basic describe support)
230
+ 2. Add snapshot testing ✅
231
+ 3. Create test fixture system ✅
232
+ 4. Implement parallel test execution ✅
233
+
234
+ ### Phase 3: Developer Experience (Priority: Medium)
235
+ 1. Add watch mode
236
+ 2. Implement custom reporters
237
+ 3. ~~Create VS Code extension~~ (Scratched)
238
+ 4. Add interactive debugging (Needs detailed spec first)
239
+
240
+ ### Phase 4: Analytics and Performance (Priority: Low)
241
+ 1. Build test analytics dashboard
242
+ 2. Add performance benchmarking
243
+ 3. Implement coverage integration
244
+ 4. Create trend analysis tools
245
+
246
+ ## Technical Considerations
247
+
248
+ ### API Design Principles
249
+ - Maintain backward compatibility
250
+ - Progressive enhancement approach
251
+ - Opt-in features to avoid breaking changes
252
+ - Clear migration paths for new features
253
+
254
+ ### Performance Goals
255
+ - Minimal overhead for test execution
256
+ - Efficient parallel execution
257
+ - Fast test discovery
258
+ - Optimized browser test bundling
259
+
260
+ ### Integration Points
261
+ - Clean interfaces between tstest and tapbundle
262
+ - Extensible plugin architecture
263
+ - Standard test result format
264
+ - Compatible with existing CI/CD tools
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@git.zone/tstest',
6
- version: '1.5.0',
6
+ version: '1.8.0',
7
7
  description: 'a test utility to run tests that match test/**/*.ts'
8
8
  }
package/ts/index.ts CHANGED
@@ -12,6 +12,7 @@ export const runCli = async () => {
12
12
  const args = process.argv.slice(2);
13
13
  const logOptions: LogOptions = {};
14
14
  let testPath: string | null = null;
15
+ let tags: string[] = [];
15
16
 
16
17
  // Parse options
17
18
  for (let i = 0; i < args.length; i++) {
@@ -36,6 +37,11 @@ export const runCli = async () => {
36
37
  case '--logfile':
37
38
  logOptions.logFile = true; // Set this as a flag, not a value
38
39
  break;
40
+ case '--tags':
41
+ if (i + 1 < args.length) {
42
+ tags = args[++i].split(',');
43
+ }
44
+ break;
39
45
  default:
40
46
  if (!arg.startsWith('-')) {
41
47
  testPath = arg;
@@ -52,6 +58,7 @@ export const runCli = async () => {
52
58
  console.error(' --no-color Disable colored output');
53
59
  console.error(' --json Output results as JSON');
54
60
  console.error(' --logfile Write logs to .nogit/testlogs/[testfile].log');
61
+ console.error(' --tags Run only tests with specified tags (comma-separated)');
55
62
  process.exit(1);
56
63
  }
57
64
 
@@ -66,6 +73,6 @@ export const runCli = async () => {
66
73
  executionMode = TestExecutionMode.DIRECTORY;
67
74
  }
68
75
 
69
- const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions);
76
+ const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions, tags);
70
77
  await tsTestInstance.run();
71
78
  };