128 lines
5.8 KiB
Markdown
128 lines
5.8 KiB
Markdown
# Architecture Overview
|
||
|
||
## Project Structure
|
||
|
||
This project integrates tstest with tapbundle through a modular architecture:
|
||
|
||
1. **tstest** (`/ts/`) - The test runner that discovers and executes test files
|
||
2. **tapbundle** (`/ts_tapbundle/`) - The TAP testing framework for writing tests
|
||
3. **tapbundle_node** (`/ts_tapbundle_node/`) - Node.js-specific testing utilities
|
||
|
||
## How Components Work Together
|
||
|
||
### Test Execution Flow
|
||
|
||
1. **CLI Entry Point** (`cli.js` <20> `cli.ts.js` <20> `cli.child.ts`)
|
||
- The CLI uses tsx to run TypeScript files directly
|
||
- Accepts glob patterns to find test files
|
||
- Supports options like `--verbose`, `--quiet`, `--web`
|
||
|
||
2. **Test Discovery**
|
||
- tstest scans for test files matching the provided pattern
|
||
- Defaults to `test/**/*.ts` when no pattern is specified
|
||
- Supports both file and directory modes
|
||
|
||
3. **Test Runner**
|
||
- Each test file imports `tap` and `expect` from tapbundle
|
||
- Tests are written using `tap.test()` with async functions
|
||
- Browser tests are compiled with esbuild and run in Chromium via Puppeteer
|
||
|
||
### Key Integration Points
|
||
|
||
1. **Import Structure**
|
||
- Test files import from local tapbundle: `import { tap, expect } from '../../ts_tapbundle/index.js'`
|
||
- Node-specific tests also import from tapbundle_node: `import { tapNodeTools } from '../../ts_tapbundle_node/index.js'`
|
||
|
||
2. **WebHelpers**
|
||
- Browser tests can use webhelpers for DOM manipulation
|
||
- `webhelpers.html` - Template literal for creating HTML strings
|
||
- `webhelpers.fixture` - Creates DOM elements from HTML strings
|
||
- Automatically detects browser environment and only enables in browser context
|
||
|
||
3. **Build System**
|
||
- Uses `tsbuild tsfolders` to compile TypeScript (invoked by `pnpm build`)
|
||
- Maintains separate output directories: `/dist_ts/`, `/dist_ts_tapbundle/`, `/dist_ts_tapbundle_node/`, `/dist_ts_tapbundle_protocol/`
|
||
- Compilation order is resolved automatically based on dependencies in tspublish.json files
|
||
- Protocol imports use compiled dist directories:
|
||
```typescript
|
||
// In ts/tstest.classes.tap.parser.ts
|
||
import { ProtocolParser } from '../dist_ts_tapbundle_protocol/index.js';
|
||
|
||
// In ts_tapbundle/tapbundle.classes.tap.ts
|
||
import { ProtocolEmitter } from '../dist_ts_tapbundle_protocol/index.js';
|
||
```
|
||
|
||
### Test Scripts
|
||
|
||
The package.json defines several test scripts:
|
||
- `test` - Builds and runs all tests (tapbundle and tstest)
|
||
- `test:tapbundle` - Runs tapbundle framework tests
|
||
- `test:tstest` - Runs tstest's own tests
|
||
- Both support `:verbose` variants for detailed output
|
||
|
||
### Environment Detection
|
||
|
||
The framework automatically detects the runtime environment:
|
||
- Node.js tests run directly via tsx
|
||
- Browser tests are compiled and served via a local server
|
||
- WebHelpers are only enabled in browser environment
|
||
|
||
This architecture allows for seamless testing across both Node.js and browser environments while maintaining a clean separation of concerns.
|
||
|
||
## Logging System
|
||
|
||
### Log File Naming (Fixed in v1.9.1)
|
||
|
||
When using the `--logfile` flag, tstest creates log files in `.nogit/testlogs/`. The log file naming was updated to preserve directory structure and prevent collisions:
|
||
|
||
- **Old behavior**: `test/tapbundle/test.ts` → `.nogit/testlogs/test.log`
|
||
- **New behavior**: `test/tapbundle/test.ts` → `.nogit/testlogs/test__tapbundle__test.log`
|
||
|
||
This fix ensures that test files with the same basename in different directories don't overwrite each other's logs. The implementation:
|
||
1. Takes the relative path from the current working directory
|
||
2. Replaces path separators (`/`) with double underscores (`__`)
|
||
3. Removes the `.ts` extension
|
||
4. Creates a flat filename that preserves the directory structure
|
||
|
||
### Test Timing Display (Fixed in v1.9.2)
|
||
|
||
Fixed an issue where test timing was displayed incorrectly with duplicate values like:
|
||
- Before: `✅ test name # time=133ms (0ms)`
|
||
- After: `✅ test name (133ms)`
|
||
|
||
The issue was in the TAP parser regex which was greedily capturing the entire line including the TAP timing comment. Changed the regex from `(.*)` to `(.*?)` to make it non-greedy, properly separating the test name from the timing metadata.
|
||
|
||
## Protocol Limitations and Improvements
|
||
|
||
### Current TAP Protocol Issues
|
||
The current implementation uses standard TAP format with metadata in comments:
|
||
```
|
||
ok 1 - test name # time=123ms
|
||
```
|
||
|
||
This has several limitations:
|
||
1. **Delimiter Conflict**: Test descriptions containing `#` can break parsing
|
||
2. **Regex Fragility**: Complex regex patterns that are hard to maintain
|
||
3. **Limited Metadata**: Difficult to add rich error information or custom data
|
||
|
||
### Planned Protocol V2
|
||
A new internal protocol is being designed that will:
|
||
- Use Unicode delimiters `⟦TSTEST:⟧` that won't conflict with test content
|
||
- Support structured JSON metadata
|
||
- Allow rich error reporting with stack traces and diffs
|
||
- Completely replace v1 protocol (no backwards compatibility)
|
||
|
||
### ts_tapbundle_protocol Directory
|
||
The protocol v2 implementation is contained in a separate `ts_tapbundle_protocol` directory:
|
||
- **Isomorphic Code**: All protocol code works in both browser and Node.js environments
|
||
- **No Platform Dependencies**: No Node.js-specific imports, ensuring true cross-platform compatibility
|
||
- **Clean Separation**: Protocol logic is isolated from platform-specific code in tstest and tapbundle
|
||
- **Shared Implementation**: Both tstest (parser) and tapbundle (emitter) use the same protocol classes
|
||
- **Build Process**:
|
||
- Compiled by `pnpm build` via tsbuild to `dist_ts_tapbundle_protocol/`
|
||
- Build order managed through tspublish.json files
|
||
- Other modules import from the compiled dist directory, not source
|
||
|
||
This architectural decision ensures the protocol can be used in any JavaScript environment without modification and maintains proper build dependencies.
|
||
|
||
See `readme.protocol.md` for the full specification and `ts_tapbundle_protocol/` for the implementation. |