# @git.zone/tstest ๐Ÿงช **A powerful, modern test runner for TypeScript** - making your test runs beautiful and informative across multiple runtimes! ## Availability and Links * [npmjs.org (npm package)](https://www.npmjs.com/package/@git.zone/tstest) * [code.foss.global (source)](https://code.foss.global/git.zone/tstest) ## Why tstest? **tstest** is a TypeScript test runner that makes testing delightful. It's designed for modern development workflows with beautiful output, flexible test execution, and powerful features that make debugging a breeze. ### โœจ Key Features - ๐ŸŽฏ **Smart Test Execution** - Run all tests, single files, or use glob patterns - ๐Ÿš€ **Multi-Runtime Support** - Run tests in Node.js, Deno, Bun, and Chromium - ๐ŸŽจ **Beautiful Output** - Color-coded results with emojis and clean formatting - ๐Ÿ“Š **Multiple Output Modes** - Choose from normal, quiet, verbose, or JSON output - ๐Ÿ” **Automatic Discovery** - Finds all your test files automatically - ๐Ÿ“ **Detailed Logging** - Optional file logging for debugging - โšก **Performance Metrics** - See which tests are slow - ๐Ÿค– **CI/CD Ready** - JSON output mode for automation - ๐Ÿท๏ธ **Tag-based Filtering** - Run only tests with specific tags - ๐ŸŽฏ **Parallel Test Execution** - Run tests in parallel groups - ๐Ÿ”ง **Test Lifecycle Hooks** - beforeEach/afterEach support - ๐Ÿ“ธ **Snapshot Testing** - Compare test outputs with saved snapshots - โณ **Timeout Control** - Set custom timeouts for tests - ๐Ÿ” **Retry Logic** - Automatically retry failing tests - ๐Ÿ› ๏ธ **Test Fixtures** - Create reusable test data - ๐Ÿ‘€ **Watch Mode** - Automatically re-run tests on file changes - ๐Ÿ“Š **Real-time Progress** - Live test execution progress updates - ๐ŸŽจ **Visual Diffs** - Beautiful side-by-side diffs for failed assertions - ๐Ÿ”„ **Event-based Reporting** - Real-time test lifecycle events ## Installation ```bash npm install --save-dev @git.zone/tstest # or with pnpm pnpm add -D @git.zone/tstest ``` ## Multi-Runtime Architecture tstest supports running your tests across multiple JavaScript runtimes, allowing you to verify cross-platform compatibility easily. ### Supported Runtimes - **Node.js** - Default runtime, uses tsrun for TypeScript execution - **Chromium** - Browser environment testing with full DOM support - **Deno** - Secure TypeScript/JavaScript runtime with modern features - **Bun** - Ultra-fast all-in-one JavaScript runtime ### Test File Naming Convention Name your test files with runtime specifiers to control where they run: | Pattern | Runtimes | Example | |---------|----------|---------| | `*.ts` | Node.js only (default) | `test.api.ts` | | `*.node.ts` | Node.js only | `test.server.node.ts` | | `*.chromium.ts` | Chromium browser | `test.dom.chromium.ts` | | `*.deno.ts` | Deno runtime | `test.http.deno.ts` | | `*.bun.ts` | Bun runtime | `test.fast.bun.ts` | | `*.all.ts` | All runtimes (Node, Chromium, Deno, Bun) | `test.universal.all.ts` | | `*.node+chromium.ts` | Both Node.js and Chromium | `test.isomorphic.node+chromium.ts` | | `*.node+deno.ts` | Both Node.js and Deno | `test.cross.node+deno.ts` | | `*.deno+bun.ts` | Both Deno and Bun | `test.modern.deno+bun.ts` | | `*.chromium.nonci.ts` | Chromium, skip in CI | `test.visual.chromium.nonci.ts` | | `*.all.nonci.ts` | All runtimes, skip in CI | `test.comprehensive.all.nonci.ts` | **Multi-Runtime Examples:** ```typescript // test.api.all.ts - runs in all runtimes (Node, Chromium, Deno, Bun) import { expect, tap } from '@git.zone/tstest/tapbundle'; tap.test('universal HTTP test', async () => { const response = await fetch('https://api.example.com/test'); expect(response.status).toEqual(200); }); export default tap.start(); ``` ```typescript // test.api.node+deno+bun.ts - runs in specific runtimes import { expect, tap } from '@git.zone/tstest/tapbundle'; tap.test('cross-runtime HTTP test', async () => { const response = await fetch('https://api.example.com/test'); expect(response.status).toEqual(200); }); export default tap.start(); ``` ### Runtime Execution Order When multiple runtimes are specified, tests execute in this order: 1. Node.js 2. Bun 3. Deno 4. Chromium ### Legacy Naming (Deprecated) The following patterns are still supported but deprecated. Use the migration tool to update: | Legacy Pattern | Modern Equivalent | Migration Command | |----------------|-------------------|-------------------| | `*.browser.ts` | `*.chromium.ts` | `tstest migrate` | | `*.both.ts` | `*.node+chromium.ts` | `tstest migrate` | When running legacy files, tstest shows a deprecation warning with the suggested new name. ### Migration Tool Migrate your test files from legacy naming to the new convention: ```bash # Dry run - see what would change tstest migrate --dry-run # Apply migrations (uses git mv to preserve history) tstest migrate --write ``` **Migration Features:** - โœ… Uses `git mv` to preserve file history - โœ… Idempotent - safe to run multiple times - โœ… Dry-run by default for safety - โœ… Colored output showing all changes - โœ… Handles modifiers like `.nonci` correctly Example output: ``` ============================================================ Test File Migration Tool ============================================================ ๐Ÿ” DRY RUN MODE - No files will be modified Found 3 legacy test file(s) Would migrate: test.browser.ts โ†’ test.chromium.ts Would migrate: test.both.ts โ†’ test.node+chromium.ts Would migrate: test.auth.browser.nonci.ts โ†’ test.auth.chromium.nonci.ts ============================================================ Summary: Total legacy files: 3 Successfully migrated: 3 Errors: 0 ============================================================ To apply these changes, run: tstest migrate --write ``` ### Runtime-Specific Permissions #### Deno Runtime Tests run with these permissions by default: ```bash --allow-read --allow-env --allow-net --allow-write --allow-sys --allow-import # Enables npm packages and Node.js built-ins --node-modules-dir # Node.js compatibility mode --sloppy-imports # Allows .js imports to resolve to .ts files ``` Configure custom permissions in your test file or via environment variables. #### Bun Runtime Bun runs with its native TypeScript support and full access to Node.js APIs. ## Usage ### Basic Test Execution ```bash # Run all tests in a directory tstest test/ # Run a specific test file tstest test/test.mycomponent.ts # Use glob patterns tstest "test/**/*.spec.ts" tstest "test/unit/*.ts" ``` ### Execution Modes **tstest** intelligently detects how you want to run your tests: 1. **Directory mode** - Recursively finds all test files 2. **File mode** - Runs a single test file 3. **Glob mode** - Uses pattern matching for flexible test selection ### Command Line Options | Option | Description | |--------|-------------| | `--quiet`, `-q` | Minimal output - perfect for CI environments | | `--verbose`, `-v` | Show all console output from tests | | `--no-color` | Disable colored output | | `--json` | Output results as JSON | | `--logfile` | Save detailed logs with automatic error and diff tracking | | `--tags ` | Run only tests with specific tags (comma-separated) | | `--timeout ` | Timeout test files after specified seconds | | `--startFrom ` | Start running from test file number n | | `--stopAt ` | Stop running at test file number n | | `--watch`, `-w` | Watch for file changes and re-run tests | | `--watch-ignore ` | Ignore patterns in watch mode (comma-separated) | | `--only` | Run only tests marked with .only | ### Example Outputs #### Normal Output (Default) ``` ๐Ÿ” Test Discovery Mode: directory Pattern: test Found: 4 test file(s) โ”โ”โ” Part 1: Node.js โ”โ”โ” โ–ถ๏ธ test/test.node+deno.ts (1/4) Runtime: Node.js โœ… HTTP request works (12ms) โœ… JSON parsing works (3ms) Summary: 2/2 PASSED in 1.2s โ”โ”โ” Part 2: Deno โ”โ”โ” โ–ถ๏ธ test/test.node+deno.ts (1/4) Runtime: Deno โœ… HTTP request works (15ms) โœ… JSON parsing works (2ms) Summary: 2/2 PASSED in 1.1s ๐Ÿ“Š Test Summary โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Total Files: 4 โ”‚ โ”‚ Total Tests: 8 โ”‚ โ”‚ Passed: 8 โ”‚ โ”‚ Failed: 0 โ”‚ โ”‚ Duration: 2.4s โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ALL TESTS PASSED! ๐ŸŽ‰ ``` #### Quiet Mode ``` Found 4 tests โœ… test functionality works โœ… api calls return expected data โœ… error handling works correctly โœ… performance is within limits Summary: 4/4 | 542ms | PASSED ``` #### Verbose Mode Shows all console output from your tests, making debugging easier: ``` โ–ถ๏ธ test/api.test.ts (1/1) Runtime: node.js Making API call to /users... Response received: 200 OK Processing user data... โœ… api calls return expected data (145ms) Summary: 1/1 PASSED ``` #### JSON Mode Perfect for CI/CD pipelines: ```json {"event":"discovery","count":4,"pattern":"test","executionMode":"directory"} {"event":"fileStart","filename":"test/test.ts","runtime":"node.js","index":1,"total":4} {"event":"testResult","testName":"prepare test","passed":true,"duration":1} {"event":"summary","summary":{"totalFiles":4,"totalTests":4,"totalPassed":4,"totalFailed":0,"totalDuration":542}} ``` ## Writing Tests with tapbundle tstest includes tapbundle, a powerful TAP-based test framework. Import it from the embedded tapbundle: ```typescript import { expect, tap } from '@git.zone/tstest/tapbundle'; tap.test('my awesome test', async () => { const result = await myFunction(); expect(result).toEqual('expected value'); }); export default tap.start(); ``` **Module Exports** tstest provides multiple exports for different use cases: - `@git.zone/tstest` - Main CLI and test runner functionality - `@git.zone/tstest/tapbundle` - Browser-compatible test framework - `@git.zone/tstest/tapbundle_node` - Node.js-specific test utilities ## tapbundle Test Framework ### Basic Test Syntax ```typescript import { tap, expect } from '@git.zone/tstest/tapbundle'; // Basic test tap.test('should perform basic arithmetic', async () => { expect(2 + 2).toEqual(4); }); // Async test with tools tap.test('async operations', async (tools) => { await tools.delayFor(100); // delay for 100ms const result = await fetchData(); expect(result).toBeDefined(); }); // Start test execution export default tap.start(); ``` ### Test Modifiers and Chaining ```typescript // Skip a test tap.skip.test('not ready yet', async () => { // This test will be skipped }); // Run only this test (exclusive) tap.only.test('focus on this', async () => { // Only this test will run }); // Todo test - creates actual test object marked as todo tap.todo.test('implement later', async () => { // This test will be counted but marked as todo }); // Chaining modifiers tap.timeout(5000) .retry(3) .tags('api', 'integration') .test('complex test', async (tools) => { // Test with 5s timeout, 3 retries, and tags }); ``` ### Test Organization with describe() ```typescript tap.describe('User Management', () => { let testDatabase; tap.beforeEach(async () => { testDatabase = await createTestDB(); }); tap.afterEach(async () => { await testDatabase.cleanup(); }); tap.test('should create user', async () => { const user = await testDatabase.createUser({ name: 'John' }); expect(user.id).toBeDefined(); }); tap.describe('User Permissions', () => { tap.test('should set admin role', async () => { // Nested describe blocks }); }); }); ``` ### Test Tools (Available in Test Function) Every test function receives a `tools` parameter with utilities: ```typescript tap.test('using test tools', async (tools) => { // Delay utilities await tools.delayFor(1000); // delay for 1000ms await tools.delayForRandom(100, 500); // random delay between 100-500ms // Skip test conditionally tools.skipIf(process.env.CI === 'true', 'Skipping in CI'); // Skip test unconditionally if (!apiKeyAvailable) { tools.skip('API key not available'); } // Mark as todo tools.todo('Needs implementation'); // Retry configuration tools.retry(3); // Set retry count // Timeout configuration tools.timeout(10000); // Set timeout to 10s // Context sharing between tests tools.context.set('userId', 12345); const userId = tools.context.get('userId'); // Deferred promises const deferred = tools.defer(); setTimeout(() => deferred.resolve('done'), 100); await deferred.promise; // Colored console output const coloredString = await tools.coloredString('Success!', 'green'); console.log(coloredString); // Error handling helper const error = await tools.returnError(async () => { throw new Error('Expected error'); }); expect(error).toBeInstanceOf(Error); }); ``` ### Snapshot Testing ```typescript tap.test('snapshot test', async (tools) => { const output = generateComplexOutput(); // Compare with saved snapshot await tools.matchSnapshot(output); // Named snapshots for multiple checks in one test await tools.matchSnapshot(output.header, 'header'); await tools.matchSnapshot(output.body, 'body'); }); // Update snapshots with: UPDATE_SNAPSHOTS=true tstest test/ ``` ### Test Fixtures ```typescript // Define reusable fixtures tap.defineFixture('testUser', async (data) => ({ id: Date.now(), name: data?.name || 'Test User', email: data?.email || 'test@example.com', created: new Date() })); tap.defineFixture('testPost', async (data) => ({ id: Date.now(), title: data?.title || 'Test Post', authorId: data?.authorId || 1 })); // Use fixtures in tests tap.test('fixture test', async (tools) => { const user = await tools.fixture('testUser', { name: 'John' }); const post = await tools.fixture('testPost', { authorId: user.id }); expect(post.authorId).toEqual(user.id); // Factory pattern for multiple instances const users = await tools.factory('testUser').createMany(5); expect(users).toHaveLength(5); }); ``` ### Parallel Test Execution ```typescript // Parallel tests within a file tap.testParallel('parallel test 1', async () => { await heavyOperation(); }); tap.testParallel('parallel test 2', async () => { await anotherHeavyOperation(); }); // File naming for parallel groups // test.api.para__1.ts - runs in parallel with other para__1 files // test.db.para__1.ts - runs in parallel with other para__1 files // test.auth.para__2.ts - runs after para__1 group completes ``` ### Assertions with expect() tapbundle uses @push.rocks/smartexpect for assertions: ```typescript // Basic assertions expect(value).toEqual(5); expect(value).not.toEqual(10); expect(obj).toDeepEqual({ a: 1, b: 2 }); // Type assertions expect('hello').toBeTypeofString(); expect(42).toBeTypeofNumber(); expect(true).toBeTypeofBoolean(); expect([]).toBeArray(); expect({}).toBeTypeOf('object'); // Comparison assertions expect(5).toBeGreaterThan(3); expect(3).toBeLessThan(5); expect(5).toBeGreaterThanOrEqual(5); expect(5).toBeLessThanOrEqual(5); expect(0.1 + 0.2).toBeCloseTo(0.3, 10); // Truthiness expect(true).toBeTrue(); expect(false).toBeFalse(); expect('text').toBeTruthy(); expect(0).toBeFalsy(); expect(null).toBeNull(); expect(undefined).toBeUndefined(); expect(null).toBeNullOrUndefined(); // String assertions expect('hello world').toStartWith('hello'); expect('hello world').toEndWith('world'); expect('hello world').toInclude('lo wo'); expect('hello world').toMatch(/^hello/); expect('option').toBeOneOf(['choice', 'option', 'alternative']); // Array assertions expect([1, 2, 3]).toContain(2); expect([1, 2, 3]).toContainAll([1, 3]); expect([1, 2, 3]).toExclude(4); expect([1, 2, 3]).toHaveLength(3); expect([]).toBeEmptyArray(); expect([{ id: 1 }]).toContainEqual({ id: 1 }); // Object assertions expect(obj).toHaveProperty('name'); expect(obj).toHaveProperty('user.email', 'test@example.com'); expect(obj).toHaveDeepProperty(['level1', 'level2']); expect(obj).toMatchObject({ name: 'John' }); // Function assertions expect(() => { throw new Error('test'); }).toThrow(); expect(() => { throw new Error('test'); }).toThrow(Error); expect(() => { throw new Error('test error'); }).toThrowErrorMatching(/test/); expect(myFunction).not.toThrow(); // Promise assertions await expect(Promise.resolve('value')).resolves.toEqual('value'); await expect(Promise.reject(new Error('fail'))).rejects.toThrow(); // Custom assertions expect(7).customAssertion( value => value % 2 === 1, 'Value is not odd' ); ``` ### Pre-tasks Run setup tasks before tests start: ```typescript tap.preTask('setup database', async () => { await initializeTestDatabase(); console.log('Database initialized'); }); tap.preTask('load environment', async () => { await loadTestEnvironment(); }); // Pre-tasks run in order before any tests ``` ### Tag-based Test Filtering ```typescript // Tag individual tests tap.tags('unit', 'api') .test('api unit test', async () => { // Test code }); tap.tags('integration', 'slow') .test('database integration', async () => { // Test code }); // Run only tests with specific tags // tstest test/ --tags unit,api ``` ### Context Sharing Share data between tests: ```typescript tap.test('first test', async (tools) => { const sessionId = await createSession(); tools.context.set('sessionId', sessionId); }); tap.test('second test', async (tools) => { const sessionId = tools.context.get('sessionId'); expect(sessionId).toBeDefined(); // Cleanup tools.context.delete('sessionId'); }); ``` ### Browser Testing with webhelpers For browser-specific tests: ```typescript import { tap, webhelpers } from '@git.zone/tstest/tapbundle'; tap.test('DOM manipulation', async () => { // Create DOM elements from HTML strings const element = await webhelpers.fixture(webhelpers.html`

Test Title

`); expect(element.querySelector('h1').textContent).toEqual('Test Title'); // Simulate interactions const button = element.querySelector('#test-btn'); button.click(); }); tap.test('CSS testing', async () => { const styles = webhelpers.css` .test-class { color: red; font-size: 16px; } `; // styles is a string that can be injected into the page expect(styles).toInclude('color: red'); }); ``` ### Advanced Error Handling ```typescript tap.test('error handling', async (tools) => { // Capture errors without failing the test const error = await tools.returnError(async () => { await functionThatThrows(); }); expect(error).toBeInstanceOf(Error); expect(error.message).toEqual('Expected error message'); }); ``` ### Test Wrap Create wrapped test environments: ```typescript import { TapWrap } from '@git.zone/tstest/tapbundle'; const tapWrap = new TapWrap({ before: async () => { console.log('Before all tests'); await globalSetup(); }, after: async () => { console.log('After all tests'); await globalCleanup(); } }); // Tests registered here will have the wrap lifecycle tapWrap.tap.test('wrapped test', async () => { // This test runs with the wrap setup/teardown }); ``` ## Advanced Features ### Watch Mode Automatically re-run tests when files change: ```bash # Watch all files in the project tstest test/ --watch # Watch with custom ignore patterns tstest test/ --watch --watch-ignore "dist/**,coverage/**" # Short form tstest test/ -w ``` **Features:** - ๐Ÿ‘€ Shows which files triggered the re-run - โฑ๏ธ 300ms debouncing to batch rapid changes - ๐Ÿ”„ Clears console between runs for clean output - ๐Ÿ“ Intelligently ignores common non-source files ### Real-time Test Progress tstest provides real-time updates during test execution: ``` โ–ถ๏ธ test/api.test.ts (1/4) Runtime: node.js โณ Running: api endpoint validation... โœ… api endpoint validation (145ms) โณ Running: error handling... โœ… error handling (23ms) Summary: 2/2 PASSED ``` ### Visual Diffs for Failed Assertions When assertions fail, tstest shows beautiful side-by-side diffs: ``` โŒ should return correct user data String Diff: - Expected + Received - Hello World + Hello Universe Object Diff: { name: "John", - age: 30, + age: 31, email: "john@example.com" } ``` ### Enhanced Test Logging The `--logfile` option provides intelligent test logging with automatic organization: ```bash tstest test/ --logfile ``` **Log Organization:** - **Current Run**: `.nogit/testlogs/[testname].log` - **Previous Run**: `.nogit/testlogs/previous/[testname].log` - **Failed Tests**: `.nogit/testlogs/00err/[testname].log` - **Changed Output**: `.nogit/testlogs/00diff/[testname].log` **Features:** - Previous logs are automatically moved to the `previous/` folder - Failed tests create copies in `00err/` for quick identification - Tests with changed output create diff reports in `00diff/` - The `00err/` and `00diff/` folders are cleared on each run **Example Diff Report:** ``` DIFF REPORT: test__api__integration.log Generated: 2025-05-24T01:29:13.847Z ================================================================================ - [Line 8] โœ… api test passes (150ms) + [Line 8] โœ… api test passes (165ms) ================================================================================ Previous version had 40 lines Current version has 40 lines ``` ### Test Timeout Protection Prevent runaway tests with the `--timeout` option: ```bash # Timeout any test file that runs longer than 60 seconds tstest test/ --timeout 60 # Shorter timeout for unit tests tstest test/unit/ --timeout 10 ``` When a test exceeds the timeout: - The test process is terminated (SIGTERM) - The test is marked as failed - An error log is created in `.nogit/testlogs/00err/` - Clear error message shows the timeout duration ### Test File Range Control Run specific ranges of test files using `--startFrom` and `--stopAt`: ```bash # Run tests starting from the 5th file tstest test/ --startFrom 5 # Run only files 5 through 10 tstest test/ --startFrom 5 --stopAt 10 # Run only the first 3 test files tstest test/ --stopAt 3 ``` This is particularly useful for: - Debugging specific test failures in large test suites - Running tests in chunks on different CI runners - Quickly testing changes to specific test files The output shows which files are skipped: ``` โญ๏ธ test/auth.test.ts (1/10) Skipped: before start range (5) โญ๏ธ test/user.test.ts (2/10) Skipped: before start range (5) โ–ถ๏ธ test/api.test.ts (5/10) Runtime: node.js โœ… api endpoints work (145ms) ``` ### Performance Analysis In verbose mode, see performance metrics: ``` โฑ๏ธ Performance Metrics: Average per test: 135ms Slowest test: api integration test (486ms) ``` ### Parallel Test Groups Tests can be organized into parallel groups for concurrent execution: ``` โ”โ”โ” Parallel Group: para__1 โ”โ”โ” โ–ถ๏ธ test/auth.para__1.ts โ–ถ๏ธ test/user.para__1.ts ... tests run concurrently ... โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”โ”โ” Parallel Group: para__2 โ”โ”โ” โ–ถ๏ธ test/db.para__2.ts โ–ถ๏ธ test/api.para__2.ts ... tests run concurrently ... โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ``` Files with the same parallel group suffix (e.g., `para__1`) run simultaneously, while different groups run sequentially. ### CI/CD Integration For continuous integration, combine quiet and JSON modes: ```bash # GitHub Actions example tstest test/ --json > test-results.json # Or minimal output tstest test/ --quiet ``` **Advanced CI Example:** ```bash # Run tests with comprehensive logging and safety features tstest test/ \ --timeout 300 \ --logfile \ --json > test-results.json # Run specific test chunks in parallel CI jobs tstest test/ --startFrom 1 --stopAt 10 # Job 1 tstest test/ --startFrom 11 --stopAt 20 # Job 2 tstest test/ --startFrom 21 # Job 3 ``` ### Debugging Failed Tests When tests fail, use the enhanced logging features: ```bash # Run with logging to capture detailed output tstest test/ --logfile --verbose # Check error logs ls .nogit/testlogs/00err/ # Review diffs for flaky tests cat .nogit/testlogs/00diff/test__api__endpoints.log # Re-run specific failed tests tstest test/api/endpoints.test.ts --verbose --timeout 60 ``` ## Changelog ### Version 2.4.0 - ๐Ÿš€ **Multi-Runtime Architecture** - Support for Deno, Bun, Node.js, and Chromium - ๐Ÿ”€ **New Naming Convention** - Flexible `.runtime1+runtime2.ts` pattern - ๐ŸŒ **Universal Testing** - `.all.ts` pattern runs tests on all supported runtimes - ๐Ÿ”„ **Migration Tool** - Easy migration from legacy naming (`.browser.ts`, `.both.ts`) - ๐Ÿฆ• **Deno Support** - Full Deno runtime with Node.js compatibility - ๐Ÿฐ **Bun Support** - Ultra-fast Bun runtime integration - โšก **Dynamic Port Selection** - Random port allocation (30000-40000) prevents conflicts - ๐Ÿ—๏ธ **Runtime Adapter Pattern** - Extensible architecture for adding new runtimes - ๐Ÿ“ **Deprecation Warnings** - Helpful migration suggestions for legacy naming - โœ… **Comprehensive Tests** - Full test coverage for parser and migration tool ### Version 1.11.0 - ๐Ÿ‘€ Added Watch Mode with `--watch`/`-w` flag for automatic test re-runs - ๐Ÿ“Š Implemented real-time test progress updates with event streaming - ๐ŸŽจ Added visual diffs for failed assertions with side-by-side comparison - ๐Ÿ”„ Enhanced event-based test lifecycle reporting - โš™๏ธ Added test configuration system with `.tstest.json` files - ๐Ÿš€ Implemented Protocol V2 with Unicode delimiters for better TAP parsing - ๐Ÿ› Fixed `tap.todo()` to create proper test objects - ๐Ÿ› Fixed `tap.skip.test()` to correctly create and count test objects - ๐Ÿ› Fixed `tap.only.test()` implementation with `--only` flag support - ๐Ÿ“ Added settings inheritance for cascading test configuration - โฑ๏ธ Added debouncing for file change events in watch mode ### Version 1.10.0 - โฑ๏ธ Added `--timeout ` option for test file timeout protection - ๐ŸŽฏ Added `--startFrom ` and `--stopAt ` options for test file range control - ๐Ÿ“ Enhanced `--logfile` with intelligent log organization: - Previous logs moved to `previous/` folder - Failed tests copied to `00err/` folder - Changed tests create diff reports in `00diff/` folder - ๐Ÿ” Improved test discovery to show skipped files with clear reasons - ๐Ÿ› Fixed TypeScript compilation warnings and unused variables - ๐Ÿ“Š Test summaries now include skipped file counts ### Version 1.9.2 - ๐Ÿ› Fixed test timing display issue (removed duplicate timing in output) - ๐Ÿ“ Improved internal protocol design documentation - ๐Ÿ”ง Added protocol v2 utilities for future improvements ### Version 1.9.1 - ๐Ÿ› Fixed log file naming to preserve directory structure - ๐Ÿ“ Log files now prevent collisions: `test__dir__file.log` ### Version 1.9.0 - ๐Ÿ“š Comprehensive documentation update - ๐Ÿ—๏ธ Embedded tapbundle for better integration - ๐ŸŒ Full browser compatibility ### Version 1.8.0 - ๐Ÿ“ฆ Embedded tapbundle directly into tstest project - ๐ŸŒ Made tapbundle fully browser-compatible - ๐Ÿ“ธ Added snapshot testing with base64-encoded communication protocol - ๐Ÿท๏ธ Introduced tag-based test filtering - ๐Ÿ”ง Enhanced test lifecycle hooks (beforeEach/afterEach) - ๐ŸŽฏ Fixed parallel test execution and grouping - โณ Improved timeout and retry mechanisms - ๐Ÿ› ๏ธ Added test fixtures for reusable test data - ๐Ÿ“Š Enhanced TAP parser for better test reporting - ๐Ÿ› Fixed glob pattern handling in shell scripts ## License and Legal Information This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file. ### Trademarks This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH. ### Company Information Task Venture Capital GmbH Registered at District court Bremen HRB 35230 HB, Germany For any legal inquiries or if you require further information, please contact us via email at hello@task.vc. By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.