Skip to main content

Automated Testing

Comprehensive automated testing for Docusaurus build scripts using Node.js built-in test runner.

Overview

The test suite validates the core functionality of three critical scripts:

  • sync-tools.cjs - Tool documentation syncing and organization
  • validate-mdx.cjs - MDX syntax validation
  • check-links.cjs - Internal and external link checking

Features

  • Zero Dependencies: Uses Node.js built-in test runner (no Jest, Mocha, etc.)
  • Fast Execution: Tests run in seconds
  • CI Integration: Automated testing via GitHub Actions
  • Comprehensive Coverage: Tests parsing, validation, and file operations
  • Clear Output: Structured test results with pass/fail indicators

Running Tests

Run All Tests

cd docusaurus
npm test

This runs all test files using the test runner script.

Run Individual Test Suites

# Test sync-tools.cjs
npm run test:sync

# Test validate-mdx.cjs
npm run test:validate

# Test check-links.cjs
npm run test:links

Run Tests with Node Directly

# Run a specific test file
node --test scripts/__tests__/sync-tools.test.cjs

# Run all tests in directory
node --test scripts/__tests__/*.test.cjs

Test Structure

Test Files Location

docusaurus/
├── scripts/
│ ├── __tests__/
│ │ ├── run-tests.cjs # Test runner
│ │ ├── sync-tools.test.cjs # sync-tools tests
│ │ ├── validate-mdx.test.cjs # validate-mdx tests
│ │ └── check-links.test.cjs # check-links tests
│ ├── sync-tools.cjs
│ ├── validate-mdx.cjs
│ └── check-links.cjs

Test Organization

Each test file uses Node's test and assert modules:

const { describe, it } = require('node:test');
const assert = require('node:assert');

describe('Feature', () => {
it('should do something', () => {
assert.strictEqual(1 + 1, 2);
});
});

Test Coverage

sync-tools.cjs Tests

Tests for tool documentation syncing:

  • Frontmatter Parsing: YAML frontmatter extraction
  • MDX Safety: Email escaping, file:// link handling
  • Category Organization: Slug generation, title conversion
  • Title Extraction: H1 heading extraction
  • H1 Stripping: Leading heading removal
  • Cost Calculation: Annual cost calculation logic

validate-mdx.cjs Tests

Tests for MDX syntax validation:

  • Code Block Detection: Fenced code block identification
  • JSX Expression Detection: Curly brace expression detection
  • Valid Tag Detection: HTML/JSX tag recognition
  • Pattern Detection: Email, numbers, special characters
  • File Type Handling: .md vs .mdx differentiation
  • Line Number Calculation: Error position tracking

check-links.cjs Tests

Tests for link checking:

  • Link Extraction: Markdown, MDX, and HTML links
  • Link Classification: External vs internal links
  • Internal Link Validation: Path resolution
  • URL Parsing: Valid URL detection
  • File Extension Handling: .md/.mdx extensions
  • Results Tracking: Error and warning accumulation

Example Test

Here's a complete test example:

const { describe, it } = require('node:test');
const assert = require('node:assert');

describe('Category Slugification', () => {
it('should convert category to slug correctly', () => {
const categoryToSlug = (category) => {
if (!category) return 'uncategorized';
return category.toLowerCase().replace(/_/g, '-');
};

assert.strictEqual(categoryToSlug('WEBSITE'), 'website');
assert.strictEqual(categoryToSlug('MARKETING_TOOL'), 'marketing-tool');
assert.strictEqual(categoryToSlug('SELF_HOSTING'), 'self-hosting');
assert.strictEqual(categoryToSlug(null), 'uncategorized');
});
});

GitHub Actions CI

Tests run automatically on push and pull requests via GitHub Actions.

Workflow File

.github/workflows/test-docusaurus-scripts.yml

name: Test Docusaurus Scripts

on:
push:
branches: [main]
paths:
- 'docusaurus/scripts/**'
- 'tools/**'
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x, 22.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
working-directory: ./docusaurus
- run: npm test
working-directory: ./docusaurus

Workflow Features

  • Multi-Node Testing: Tests on Node 20 and 22
  • Automatic Triggering: Runs on script changes
  • Build Verification: Runs sync and validation scripts
  • Artifact Upload: Saves test results for review

Writing New Tests

1. Create Test File

Create a new file in scripts/__tests__/:

#!/usr/bin/env node

const { describe, it } = require('node:test');
const assert = require('node:assert');

describe('My Feature', () => {
it('should work correctly', () => {
// Your test here
assert.strictEqual(1 + 1, 2);
});
});

if (require.main === module) {
console.log('Running my tests...\n');
}

2. Add to Test Runner

Edit scripts/__tests__/run-tests.cjs:

const TEST_FILES = [
'sync-tools.test.cjs',
'validate-mdx.test.cjs',
'check-links.test.cjs',
'my-new-test.cjs', // Add your test
];

3. Add npm Script (Optional)

Edit package.json:

{
"scripts": {
"test:mynew": "node --test ./scripts/__tests__/my-new-test.cjs"
}
}

4. Run Your Test

npm run test:mynew

Best Practices

Test Organization

  • One file per script: Keep tests focused
  • Descriptive names: Use clear test descriptions
  • Group related tests: Use describe blocks
  • Test edge cases: Include error conditions

Assertions

Use appropriate assertion methods:

// Equality
assert.strictEqual(actual, expected);
assert.deepStrictEqual(actualObject, expectedObject);

// Truthiness
assert.ok(value);
assert.strictEqual(value, true);

// Exceptions
assert.throws(() => { throw new Error(); });
assert.doesNotThrow(() => { /* safe code */ });

Test Independence

  • No shared state: Each test should be independent
  • Clean up: Remove test fixtures after tests
  • Mock carefully: Avoid complex mocking (keep it simple)

Troubleshooting

Test Failures

Issue: Tests fail locally but pass in CI

Solution: Ensure you're using the same Node version as CI (20.x or 22.x)

node --version
nvm use 20 # or nvm use 22

Issue: Import errors in tests

Solution: Use CommonJS (require) not ES modules (import)

// ✅ Correct
const { describe, it } = require('node:test');

// ❌ Incorrect
import { describe, it } from 'node:test';

Issue: Tests hang or timeout

Solution: Ensure async operations complete

// Use async/await properly
it('async test', async () => {
const result = await someAsyncFunction();
assert.ok(result);
});

Continuous Integration

Local Pre-Commit Testing

Run tests before committing:

cd docusaurus
npm test && npm run check-links

Pre-Push Hook

Add to .git/hooks/pre-push:

#!/bin/bash
cd docusaurus
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fi

Make executable:

chmod +x .git/hooks/pre-push

Performance

Test Execution Time

Typical test run times:

  • sync-tools tests: ~100ms
  • validate-mdx tests: ~150ms
  • check-links tests: ~200ms
  • Total: ~450ms

Optimization Tips

  • Keep tests focused and small
  • Avoid slow operations (file I/O, network)
  • Use fixtures for complex data
  • Run tests in parallel when possible

Future Enhancements

  • Add code coverage reporting
  • Create integration tests for full build process
  • Add performance benchmarks
  • Test Docusaurus build output
  • Add visual regression testing

Last Updated: 2026-01-06
Test Framework: Node.js built-in test runner
Node Version: 20.x, 22.x
Status: Active