|
| 1 | +# Type Testing Infrastructure |
| 2 | + |
| 3 | +This directory contains TypeScript type tests using a **hybrid approach** that combines: |
| 4 | +1. **Vitest `expectTypeOf`** for positive type assertions (clear error messages) |
| 5 | +2. **`@ts-expect-error`** for negative assertions (enforces code doesn't compile) |
| 6 | + |
| 7 | +## Running Type Tests |
| 8 | + |
| 9 | +```bash |
| 10 | +# Run all type tests (vitest + TS2578 validation) |
| 11 | +pnpm nx test:types dsl |
| 12 | + |
| 13 | +# Individual targets for faster iteration: |
| 14 | +pnpm nx test:types:vitest dsl # Vitest only (fast, ~300ms) |
| 15 | +pnpm nx test:types:strict dsl # TS2578 validation only |
| 16 | + |
| 17 | +# Health check (verifies testing infrastructure works) |
| 18 | +pnpm nx test:types:health dsl |
| 19 | +``` |
| 20 | + |
| 21 | +## Development Workflow |
| 22 | + |
| 23 | +**Fast iteration (during development):** |
| 24 | +```bash |
| 25 | +pnpm nx test:types:vitest dsl # Fast, nice output |
| 26 | +``` |
| 27 | + |
| 28 | +**Full validation (before commit):** |
| 29 | +```bash |
| 30 | +pnpm nx test:types dsl # Runs both vitest and TS2578 checks |
| 31 | +``` |
| 32 | + |
| 33 | +## Health Check System |
| 34 | + |
| 35 | +### Purpose |
| 36 | +The health check ensures the type testing infrastructure itself is working correctly. Without this, type tests could silently break and fail to catch bugs. |
| 37 | + |
| 38 | +### Components |
| 39 | + |
| 40 | +#### 1. Canary File (`__canary__.test-d.ts`) |
| 41 | +- **Intentionally fails** type checking |
| 42 | +- Contains known type errors that MUST be detected |
| 43 | +- Excluded from normal test runs (see `tsconfig.typecheck.json`) |
| 44 | +- Tests both `expectTypeOf` and `@ts-expect-error` mechanisms |
| 45 | + |
| 46 | +#### 2. Verification Script (`scripts/verify-type-test-health.sh`) |
| 47 | +Runs diagnostic tests to verify: |
| 48 | +- tsc detects type errors |
| 49 | +- `expectTypeOf` produces clear "Expected X, Actual Y" messages |
| 50 | +- TS2578 detection works (unused `@ts-expect-error`) |
| 51 | +- Expected error patterns appear (TS2344, TS2578) |
| 52 | + |
| 53 | +#### 3. Nx Target (`test:types:health`) |
| 54 | +Run with: `pnpm nx test:types:health dsl` |
| 55 | + |
| 56 | +### When to Run Health Check |
| 57 | + |
| 58 | +- **After TypeScript version upgrades** |
| 59 | +- **After Vitest updates** |
| 60 | +- **After modifying tsconfig files** |
| 61 | +- **After changing typecheck-ts2578.sh script** |
| 62 | +- **In CI** (recommended: run weekly or on release branches) |
| 63 | + |
| 64 | +### Expected Output |
| 65 | + |
| 66 | +✅ **Healthy system:** |
| 67 | +``` |
| 68 | +✅ SUCCESS: Type testing infrastructure is healthy |
| 69 | +
|
| 70 | +All checks passed: |
| 71 | + • Pass 1 (project-wide) catches type errors |
| 72 | + • expectTypeOf produces clear error messages |
| 73 | + • Pass 2 (individual files) catches TS2578 errors |
| 74 | + • Canary file exhibits expected error patterns |
| 75 | +``` |
| 76 | + |
| 77 | +❌ **Broken system:** |
| 78 | +``` |
| 79 | +❌ FAILURE: Type testing infrastructure is BROKEN |
| 80 | +
|
| 81 | +This means type tests may not be catching bugs! |
| 82 | +``` |
| 83 | + |
| 84 | +## Hybrid Testing Approach |
| 85 | + |
| 86 | +### Use `expectTypeOf` for Positive Assertions |
| 87 | + |
| 88 | +```typescript |
| 89 | +it('should correctly infer types', () => { |
| 90 | + const flow = new Flow<{ userId: string }>({ slug: 'test' }) |
| 91 | + .step({ slug: 's1' }, () => 42); |
| 92 | + |
| 93 | + const step = flow.getStepDefinition('s1'); |
| 94 | + |
| 95 | + // Clear, explicit type assertion |
| 96 | + expectTypeOf(step.handler).returns.toEqualTypeOf<number>(); |
| 97 | +}); |
| 98 | +``` |
| 99 | + |
| 100 | +**Benefits:** |
| 101 | +- ✅ Clear error messages: `"Expected: number, Actual: string"` |
| 102 | +- ✅ Explicit about what types SHOULD be |
| 103 | +- ✅ Good for complex type testing |
| 104 | + |
| 105 | +### Use `@ts-expect-error` for Negative Assertions |
| 106 | + |
| 107 | +```typescript |
| 108 | +it('should reject invalid handlers', () => { |
| 109 | + new Flow({ slug: 'test' }) |
| 110 | + // @ts-expect-error - should reject null return |
| 111 | + .array({ slug: 'bad' }, () => null) |
| 112 | + |
| 113 | + // @ts-expect-error - should reject undefined return |
| 114 | + .array({ slug: 'bad2' }, () => undefined); |
| 115 | +}); |
| 116 | +``` |
| 117 | + |
| 118 | +**Benefits:** |
| 119 | +- ✅ Actually enforces code doesn't compile |
| 120 | +- ✅ Detected by typecheck-ts2578.sh via TS2578 |
| 121 | +- ✅ Tests real-world usage patterns |
| 122 | + |
| 123 | +### Why Both? |
| 124 | + |
| 125 | +- **`expectTypeOf`**: Tests type relationships and transformations |
| 126 | +- **`@ts-expect-error`**: Tests that invalid code is actually rejected |
| 127 | + |
| 128 | +Using both provides comprehensive coverage and catches different classes of bugs. |
| 129 | + |
| 130 | +## Troubleshooting |
| 131 | + |
| 132 | +### Health Check Fails |
| 133 | + |
| 134 | +1. Check TypeScript version: `pnpm tsc --version` |
| 135 | +2. Check Vitest version: `pnpm vitest --version` |
| 136 | +3. Review `tsconfig.typecheck.json` |
| 137 | +4. Check `typecheck-ts2578.sh` script |
| 138 | +5. Look at canary file errors: `pnpm tsc --noEmit __tests__/types/__canary__.test-d.ts` |
| 139 | + |
| 140 | +### Type Tests Pass But Should Fail |
| 141 | + |
| 142 | +This usually means: |
| 143 | +- Type signatures are too permissive |
| 144 | +- Missing `@ts-expect-error` directives |
| 145 | +- Run health check to verify infrastructure works |
| 146 | + |
| 147 | +### TS2578 Not Detected |
| 148 | + |
| 149 | +- Ensure `typecheck-ts2578.sh` runs correctly |
| 150 | +- Check that file is included in typecheck |
| 151 | +- Verify `@ts-expect-error` is on its own line above the code |
| 152 | + |
| 153 | +## Adding New Type Tests |
| 154 | + |
| 155 | +1. **Choose the right tool**: |
| 156 | + - Positive assertion (what type IS) → `expectTypeOf` |
| 157 | + - Negative assertion (what shouldn't compile) → `@ts-expect-error` |
| 158 | + |
| 159 | +2. **Follow existing patterns** in the test files |
| 160 | + |
| 161 | +3. **Run health check** after major changes: |
| 162 | + ```bash |
| 163 | + pnpm nx test:types:health dsl |
| 164 | + ``` |
| 165 | + |
| 166 | +4. **Test your tests**: Temporarily break the type signature and ensure the test fails |
0 commit comments