@testgorilla/tgo-testing-checker
v0.2.0
Published
Test-quality checker and deterministic autofixers for TestGorilla Angular projects
Readme
Testing Checker & Fixer
Static analysis tool for test files. 62 rules across three engines, with a deterministic fixer system for mechanical violations.
Quick start
# Check all test files
npm run check:tests
# Check specific rule(s)
npm run check:tests -- --rule A01,G18
# Machine-readable output (use npx directly to avoid npm prefix noise)
npx ts-node utils/testing/testing-checker/index.ts --json --rule A02
# List all rules with severity, category, and fixable status
npm run check:tests -- --list-rules
# Dry-run fixer (shows proposed changes, no files modified)
npm run fix:tests
# Apply fixes + idempotency verification
npm run fix:tests:applyCLI flags
| Flag | Description | | --- | --- | | --rule | Comma-separated rule IDs (e.g. A01,G18) | | --type | integration, unit, or all (default) | | --json | JSON output | | --errors-only | Skip warnings | | --compact | Summary only, no line details | | --group-by rule | Group by rule instead of by file | | --list-rules | Print rule table and exit | | --src | Override source root (default: src) | | --config | Per-repo JSON config merged over the defaults (see below) | | --files | Comma-separated changed files (repo-relative): scan only these | | --files-from | Read the changed-file list (one per line) from a file |
Fixer flags: --apply (write changes), --rule <IDS> (filter), --src <PATH>.
Running as a per-repo gate
The same checker runs across TestGorilla frontend repos, which differ in conventions and library versions. Two mechanisms make that work without forking the rules.
Per-repo config (--config)
Point --config at a JSON file committed in the target repo. It is merged
over the built-in defaults: rules per id (so you can flip one rule's
enabled/severity without restating the rest), plus options and
testFilePatterns, which layer over their own defaults.
{
"rules": {
"G11": { "enabled": false }, // opt out of the mock-naming policy
"A17": { "severity": "warning" } // downgrade, don't block
},
"options": {
// Function names accepted as the shared Transloco testing-module helper
// (G10, A14, C12). Default already covers the known TestGorilla names.
"translocoTestingHelpers": ["getTranslocoTestingModule"],
// Component field naming the translation-key prefix (C15).
"translationContextField": "translationContext",
// Mock variable convention (G11): "suffix" (fooMock) or "prefix" (mockFoo).
"mockNaming": "suffix",
// Material form controls C09 steers toward TGO UI.
"matFormComponents": ["mat-form-field", "mat-select", "mat-checkbox"],
// Element tags whose text is an icon ligature, not copy (C04).
"iconTags": ["mat-icon"]
},
// For a repo that doesn't use the .integration.spec.ts split: route plain
// specs into the integration bucket so integration-scoped rules run on them.
"testFilePatterns": { "integration": ".spec.ts", "unit": ".spec.ts" }
}Every options field is optional and falls back to the TestGorilla default;
a supplied array replaces the default wholesale rather than merging.
Diff scope (--files / --files-from)
A gate should report the flow of new violations on a PR's changed files, not the repo's whole existing stock. Pass the changed files and the checker dispatches each rule only on those (a rule still reads any related file it needs, e.g. a changed spec's unchanged template). An empty list scans nothing and passes trivially.
# In CI, on a PR:
git diff --name-only "origin/$BASE_BRANCH...HEAD" > changed.txt
npx ts-node index.ts --json --config .tgo-testing-checker.json --files-from changed.txtArchitecture
testing-checker/
index.ts CLI entry point (checker)
config/rules-config.ts Severity overrides
reporter/ Output formatting
rules/
rule.model.ts Shared types (RuleDefinition, RuleFixer, etc.)
ast-helpers.ts Shared TypeScript AST utilities
grep-rules.ts G01-G23: regex pattern matching on raw text
ast-rules.ts A01-A22: TypeScript AST analysis
cross-file-rules.ts C01-C17: correlates template, component, and test files
fixers/
registry.ts Maps rule ID -> RuleFixer (single source of truth)
fix-a01.ts A01 fixer implementation
index.ts CLI entry point (fixer)Rule engines
- Grep (G-rules): Pattern match on raw file content. Fast, no parsing.
- AST (A-rules): Parse TypeScript into syntax tree. Checks structure (describe/it nesting, naming, etc.).
- Cross-file (C-rules): Read related files (component template, .mocks.ts, production code) to validate test completeness.
Every rule has: id, name, description, severity (error/warning), category (grep/ast/cross-file), testType (integration/unit/both/production).
Fixer system
Fixers are decoupled from rules via a registry pattern:
rules/ ← zero knowledge of fixers
fixers/registry.ts → imports fixers + maps to rule IDs
fixers/fix-*.ts → imports from rules/ (types, AST helpers)Each RuleFixer implements two pure functions:
collectFixes(filePath, content)— returnsFixReplacement[](no side effects)applyFixes(content, replacements)— returns new file content
The fixer CLI handles file I/O, pattern matching, and idempotency verification (re-runs after apply, expects 0 remaining).
Adding a new fixer
- Create
fixers/fix-<id>.tsexporting aRuleFixer - Add one line to
fixers/registry.ts
No rule files need to be modified.
Rule severity
- error — must fix (blocks CI when enforced)
- warning — should fix, non-blocking
Severity can be overridden in config/rules-config.ts.
Fix complexity
Not all rules are mechanically fixable. Three categories:
- Mechanical: Safe find-replace, deterministic (A01, A11, G03, G11, G13). Candidates for automated fixers.
- Pattern transform: Mechanical but context-sensitive replacement (A05, A06, A08, G05, G10, G12). Partially automatable.
- Judgment: Requires reading surrounding code (A04, A17, G06, G08, G18, C01, C06). AI-assisted, not automated.
Run --list-rules to see which rules currently have [fixable] status.
