# Configuration
NogginLessDom is designed to work with minimal configuration. Most settings are
managed through Bun's configuration file (`bunfig.toml`), standard TypeScript
configuration, and environment variables.
## Test File Patterns
By default, Bun discovers test files matching these patterns:
- `**/*.test.ts`
- `**/*.test.tsx`
- `**/*.spec.ts`
- `**/*.spec.tsx`
Files in `node_modules/` are excluded. You can override test file discovery
by passing explicit paths:
```bash
# Run tests in a specific directory
bun test tests/unit
# Run a specific test file
bun test tests/unit/assertions/expect.test.ts
# Run multiple specific files
bun test tests/unit/dom/element.test.ts tests/unit/dom/document.test.ts
```
### Programmatic Test File Filtering
You can set a file pattern programmatically:
```typescript
import {
setTestFilePattern,
clearTestFilePattern,
getTestFilePattern,
} from '@asymmetric-effort/nogginlessdom';
// Only run test files matching this glob
setTestFilePattern('**/dom/**/*.test.ts');
// Check current pattern
console.log(getTestFilePattern());
// Clear the pattern
clearTestFilePattern();
```
## TypeScript Configuration
NogginLessDom targets ESNext and uses ESM modules. Your `tsconfig.json` should
be compatible with these settings:
```json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true
}
}
```
If you are using Bun, add `bun-types` to your `types` array for full runtime
type support:
```json
{
"compilerOptions": {
"types": ["bun-types"]
}
}
```
NogginLessDom ships with TypeScript type declarations (`*.d.ts`). No additional
`@types/` packages are needed.
## Coverage Configuration
Coverage is configured in `bunfig.toml` at the project root.
### Basic Coverage
```toml
[test]
coverage = true
```
### Coverage Thresholds
Set minimum coverage percentages. The test run fails if any threshold is not
met:
```toml
[test]
coverage = true
coverageThreshold = { line = 90, function = 90, statement = 90 }
```
| Threshold Field | Description |
| --------------- | ---------------------------------------- |
| `line` | Minimum percentage of lines covered |
| `function` | Minimum percentage of functions covered |
| `statement` | Minimum percentage of statements covered |
### Coverage Providers
NogginLessDom supports two coverage providers:
- **V8** -- Uses the V8 JavaScript engine's built-in coverage instrumentation.
Fast and accurate for Node.js and Bun environments.
- **Istanbul** -- Traditional instrumentation-based coverage. Useful for
compatibility with existing toolchains.
### Coverage Reporters
The framework includes 11 coverage reporters:
| Reporter | Description |
| -------------- | ----------------------------------- |
| `text` | Terminal table output |
| `text-summary` | Condensed terminal summary |
| `json` | JSON coverage data |
| `json-summary` | JSON coverage summary |
| `lcov` | LCOV format with optional HTML |
| `lcov-only` | LCOV format without HTML |
| `html` | Full HTML coverage report |
| `html-spa` | Single-page application HTML report |
| `clover` | Clover XML format |
| `cobertura` | Cobertura XML format |
| `teamcity` | TeamCity service messages |
### Per-Test Coverage
Track coverage on a per-test basis using the programmatic API:
```typescript
import {
startCoverage,
takeCoverage,
stopCoverage,
reportCoverage,
} from '@asymmetric-effort/nogginlessdom';
startCoverage();
// ... run code under test ...
const data = takeCoverage();
stopCoverage();
reportCoverage(data);
```
## Reporter Configuration
NogginLessDom provides built-in test reporters that can be configured
programmatically:
```typescript
import {
configureReporters,
DefaultReporter,
VerboseReporter,
DotReporter,
JsonReporter,
SilentReporter,
} from '@asymmetric-effort/nogginlessdom';
```
### Available Reporters
| Reporter | Description |
| ----------------- | ---------------------------------------------- |
| `DefaultReporter` | Standard output with pass/fail indicators |
| `VerboseReporter` | Detailed output with timing and nested suites |
| `DotReporter` | Minimal dot-per-test output for CI |
| `JsonReporter` | Machine-readable JSON output |
| `SilentReporter` | Suppresses all output (useful for programmatic |
| | use) |
### Bun Test Reporters
You can also use Bun's built-in reporter flags:
```bash
# Default reporter
bun test
# JUnit reporter (for CI systems)
bun test --reporter junit
# Custom reporter module
bun test --reporter ./reporters/custom.ts
```
## Watch Mode Configuration
Re-run tests automatically when files change:
```bash
bun test --watch
```
You can configure watch mode in `bunfig.toml`:
```toml
[test]
# watch = false
```
Combine watch mode with test filtering for focused development:
```bash
bun test --watch --grep "DOM element"
```
### Programmatic Watch API
```typescript
import { watchTests } from '@asymmetric-effort/nogginlessdom';
const controller = watchTests({
// Watch options
});
```
## Test Filtering
### Command-Line Filtering
```bash
# Run tests matching a name pattern
bun test --grep "should handle"
# Run tests in a specific file
bun test path/to/file.test.ts
# Run tests in a specific directory
bun test tests/unit/dom
```
### Programmatic Name Filtering
```typescript
import {
setTestNamePattern,
clearTestNamePattern,
getTestNamePattern,
} from '@asymmetric-effort/nogginlessdom';
// Only run tests whose names match this regex
setTestNamePattern(/DOM.*element/i);
// Check current pattern
console.log(getTestNamePattern());
// Clear the filter
clearTestNamePattern();
```
### Test Modifiers
Filter tests directly in your test code:
```typescript
import { describe, it } from '@asymmetric-effort/nogginlessdom';
describe('Feature', () => {
it('runs normally', () => { /* ... */ });
it.skip('is skipped', () => { /* ... */ });
it.only('runs exclusively', () => { /* ... */ });
it.todo('is planned for later');
});
```
Conditional execution:
```typescript
import { describe, it } from '@asymmetric-effort/nogginlessdom';
const isCI = process.env.CI === 'true';
describe('Platform tests', () => {
it.skipIf(isCI)('skipped in CI', () => { /* ... */ });
it.runIf(!isCI)('only runs locally', () => { /* ... */ });
});
```
## Mock Auto-Cleanup Configuration
Configure how mock functions are automatically cleaned up between tests:
```typescript
import {
configureMockBehavior,
getMockConfig,
} from '@asymmetric-effort/nogginlessdom';
configureMockBehavior({
// Configuration options for mock behavior
});
// Check current mock configuration
const config = getMockConfig();
```
### Auto-Cleanup with Lifecycle Hooks
Install automatic mock cleanup in your test setup:
```typescript
import { installAutoMockCleanup } from '@asymmetric-effort/nogginlessdom';
// Automatically restore all mocks after each test
installAutoMockCleanup();
```
This registers `afterEach` hooks that call `restoreAllMocks()` so mocks do not
leak between tests.
## Test Isolation Configuration
Control how tests are isolated from each other:
```typescript
import { configureIsolation } from '@asymmetric-effort/nogginlessdom';
import type { IsolationConfig } from '@asymmetric-effort/nogginlessdom';
const config: IsolationConfig = {
// Isolation settings
};
configureIsolation(config);
```
## Serial Execution
Force tests to run sequentially instead of concurrently:
```typescript
import {
setSerialMode,
getSerialMode,
} from '@asymmetric-effort/nogginlessdom';
// Enable serial execution
setSerialMode(true);
// Check current mode
console.log(getSerialMode()); // true
```
This is useful when tests share state or interact with resources that do not
support concurrent access.
## Test Setup Files
Run setup code before all tests by creating a preload file:
```toml
[test]
preload = ["./tests/setup.ts"]
```
Example `tests/setup.ts`:
```typescript
import {
Document,
installAutoMockCleanup,
} from '@asymmetric-effort/nogginlessdom';
// Auto-cleanup mocks after each test
installAutoMockCleanup();
// Create a global document available to all tests
globalThis.testDocument = new Document();
```
## DOM Configuration
The DOM simulation does not require configuration for basic use. Simply import
and instantiate:
```typescript
import { Document } from '@asymmetric-effort/nogginlessdom';
const doc = new Document();
```
### Shared Document via Lifecycle Hooks
```typescript
import {
describe,
beforeEach,
Document,
} from '@asymmetric-effort/nogginlessdom';
describe('Component Tests', () => {
let doc: Document;
beforeEach(() => {
doc = new Document();
const root = doc.createElement('div');
root.id = 'root';
doc.appendChild(root);
});
// tests use `doc` here...
});
```
### innerHTML for Complex Structures
```typescript
const container = doc.createElement('div');
container.innerHTML = `
Welcome
`;
doc.appendChild(container);
```
## Dependency Analysis
NogginLessDom includes built-in tools for analyzing your project's import
structure. These can be enabled via environment variables or the programmatic
API.
### Circular Dependency Detection
Detect circular import chains that cause initialization issues and break
module mocking.
```bash
# Warn on cycles (continues test run)
DETECT_CYCLES=1 bun test
# Fail on cycles (exits before running tests)
DETECT_CYCLES=strict bun test
```
Programmatic API:
```typescript
import {
detectCircularImports,
formatCycleReport,
configureCycleDetection,
} from '@asymmetric-effort/nogginlessdom';
// Detect cycles in specific files
const cycles = detectCircularImports(['src/index.ts']);
if (cycles.length > 0) {
console.log(formatCycleReport(cycles));
}
// Enable during test runs
configureCycleDetection({ enabled: true, strict: true });
```
### Import Depth Analysis
Analyze the depth of your import chains to catch barrel file explosion and
deeply nested module structures.
```bash
# Warn if any file exceeds depth 8
IMPORT_DEPTH_THRESHOLD=8 bun test
# Strict mode
IMPORT_DEPTH_THRESHOLD=8:strict bun test
```
Programmatic API:
```typescript
import { analyzeImportDepth } from '@asymmetric-effort/nogginlessdom';
const result = analyzeImportDepth(['src/index.ts'], { threshold: 10 });
console.log('Max depth:', result.maxDepth);
console.log('Average depth:', result.averageDepth.toFixed(1));
for (const entry of result.filesExceedingThreshold) {
console.log(` ${entry.file}: depth ${entry.depth}`);
console.log(` Chain: ${entry.longestChain.join(' -> ')}`);
}
```
### Unused Import Detection
Find imports that are declared but never referenced in your source files.
```bash
# Warn on unused imports
DETECT_UNUSED_IMPORTS=1 bun test
# Fail on unused imports
DETECT_UNUSED_IMPORTS=strict bun test
```
Programmatic API:
```typescript
import {
detectUnusedImports,
formatUnusedImportReport,
} from '@asymmetric-effort/nogginlessdom';
const unused = detectUnusedImports(['src/**/*.ts']);
if (unused.length > 0) {
console.log(formatUnusedImportReport(unused));
}
```
Configuration options:
```typescript
import {
configureUnusedImportDetection,
} from '@asymmetric-effort/nogginlessdom';
configureUnusedImportDetection({
enabled: true,
strict: false,
ignoreTypeImports: true,
ignoreSideEffectImports: true,
exclude: ['**/*.d.ts'],
});
```
### Dependency Graph Visualization
Export your project's import graph for visualization and analysis.
```bash
# Write JSON graph after tests
EXPORT_DEPENDENCY_GRAPH=deps.json bun test
# Generate Graphviz DOT
EXPORT_DEPENDENCY_GRAPH=deps.dot bun test
# Generate Mermaid
EXPORT_DEPENDENCY_GRAPH=deps.mmd bun test
```
Programmatic API:
```typescript
import {
buildDependencyGraph,
exportGraphJSON,
exportGraphDOT,
exportGraphMermaid,
saveGraph,
} from '@asymmetric-effort/nogginlessdom';
import * as fs from 'node:fs';
const graph = buildDependencyGraph(['src/index.ts']);
// JSON export
fs.writeFileSync('deps.json', exportGraphJSON(graph, true));
// Graphviz (render with: dot -Tpng deps.dot -o deps.png)
fs.writeFileSync('deps.dot', exportGraphDOT(graph));
// Mermaid (paste into GitHub markdown)
console.log(exportGraphMermaid(graph));
// Save directly to a file (format inferred from extension)
saveGraph(graph, 'deps.json');
// Summary
console.log('Files:', graph.summary.totalFiles);
console.log('Max depth:', graph.summary.maxDepth);
console.log('Cycles:', graph.summary.cycleCount);
console.log('Hub files:', graph.summary.hubFiles.join(', '));
```
## Environment Variables Reference
| Variable | Values | Description |
| ------------------------- | --------------- | ------------------------------------------------------------ |
| `NODE_ENV` | `test` | Set to `test` during test runs (Bun default) |
| `CI` | `true` | Set in CI environments; can affect reporter and snapshot |
| | | behavior |
| `BUN_DEBUG` | `true` | Enable Bun debug output |
| `DETECT_CYCLES` | `1`, `strict` | Enable circular dependency detection; `strict` fails the run |
| `IMPORT_DEPTH_THRESHOLD` | `N`, `N:strict` | Warn or fail if import depth exceeds N |
| `DETECT_UNUSED_IMPORTS` | `1`, `strict` | Enable unused import detection; `strict` fails the run |
| `EXPORT_DEPENDENCY_GRAPH` | file path | Export dependency graph to the given file (JSON, DOT, or |
| | | Mermaid based on extension) |