Skip to content

Latest commit

 

History

History
395 lines (275 loc) · 8.71 KB

File metadata and controls

395 lines (275 loc) · 8.71 KB

Contributing to htmltest

This document provides guidelines and information for developers.

Project Overview

htmltest is a fast HTML validation and link checker written in Go. It's designed as a faster alternative to the Ruby-based html-proofer tool.

What htmltest Does

  • Validates HTML files for broken links, images, and script references
  • Checks internal and external links
  • Verifies image alt attributes
  • Tests meta refresh tags
  • Checks for valid favicon references
  • Validates DOCTYPE declarations
  • Caches external link checks for faster subsequent runs

Performance

On sites with 2000+ files, htmltest runs in seconds compared to minutes with other tools, making it ideal for CI/CD pipelines.

Development Setup

Prerequisites

  • Go 1.13 or higher (check with go version)
  • Git
  • golangci-lint (optional, for linting)

Getting Started

  1. Clone the repository:

    git clone https://github.com/wjdp/htmltest.git
    cd htmltest
  2. Install dependencies:

    go mod download

    Or using Make:

    make deps
  3. Build the project:

    make build

    Or directly:

    go build -o bin/htmltest main.go
  4. Run tests:

    make test-race

Project Structure

htmltest/
├── main.go             # Entry point
├── htmldoc/            # HTML document parsing and storage
│   ├── document.go     # Document representation
│   ├── reference.go    # Reference (link/image/script) handling
│   └── attr.go         # HTML attribute utilities
├── htmltest/           # Core testing logic
│   ├── htmltest.go     # Main test orchestration
│   ├── options.go      # Configuration options
│   ├── check-*.go      # Specific checkers (links, images, etc.)
│   └── fixtures/       # Test fixtures
├── issues/             # Issue tracking and reporting
├── refcache/           # External reference caching
└── output/             # Output formatting and logging

Running Tests

Unit Tests

Run all tests across all packages:

make test

Tests with Race Detection (Recommended)

Catches concurrency issues:

make test-race

Tests Exactly as CI Runs Them

Run tests with race detection AND coverage (matches GitHub Actions CI):

make test-ci

TDD Workflow (Recommended for Development)

When developing features, use the TDD targets for fast iteration:

# Run specific test with clean cache (shows cache state after)
make test-tdd-cache TEST_RUN=TestTimeoutIsCached

# Run specific test (no cache inspection, faster)
make test-tdd TEST_RUN=TestTimeoutIsCached

# Run multiple tests matching a pattern
make test-tdd TEST_RUN='.*Cache.*'

# Just clean the cache
make clean-cache

The test-tdd targets:

  • Automatically clean the refcache before running tests
  • Support pattern matching to run multiple related tests
  • test-tdd-cache shows the cache state after tests complete
  • Continue even if tests fail (good for RED phase of TDD)

TDD Workflow Example:

  1. Write/update your test first (RED phase):

    make test-tdd-cache TEST_RUN=TestNewFeature
    # Test fails, shows what's in cache
  2. Implement the feature (GREEN phase):

    make test-tdd-cache TEST_RUN=TestNewFeature
    # Test passes, verify cache state
  3. Run related tests to check for regressions:

    make test-tdd TEST_RUN='.*Cache.*'

Test Specific Package

go test ./htmldoc
go test ./htmltest
go test ./issues
go test ./refcache

Test Coverage

make test-coverage

View HTML coverage report:

go tool cover -html=coverage.txt

Benchmark Tests

make test-bench

Run Specific Test (without Make)

go test -v -run TestMissingOptions ./htmltest

Test Structure

Fixtures

Tests use fixture files located in */fixtures/ directories:

  • HTML test files with various scenarios (broken links, valid links, etc.)
  • Configuration files
  • Sample resources (images, scripts)

VCR Cassettes

External HTTP requests are mocked using VCR cassettes (recorded HTTP interactions) in htmltest/fixtures/vcr/*.cassette. This allows tests to run offline and consistently without hitting real external URLs.

Test Naming Convention

  • Test files: *_test.go
  • Test functions: Test<Feature>(t *testing.T)
  • Benchmark functions: Benchmark<Feature>(b *testing.B)
  • Helper functions: t<Helper>() (lowercase t prefix)

Building

Development Build

make build

This creates bin/htmltest with version information from git tags.

Manual Build

go build -ldflags "-X main.version=$(git describe --tags)" -o bin/htmltest main.go

Install to GOPATH

make install

Code Quality

Format Code

make fmt

Check Formatting (CI Mode)

Check if code is properly formatted without modifying files (fails if not formatted):

make fmt-check

Run go vet

make vet

Lint

Requires golangci-lint:

make lint

Run All CI Checks Locally

Run format check, vet, and tests exactly as CI does:

make check
# or
make ci

This is the best command to run before committing to ensure CI will pass.

Testing Your Changes

End-to-End Testing

After building, test the binary manually:

# Show help
./bin/htmltest -h

# Test a single file
./bin/htmltest htmltest/fixtures/links/head_link_href.html

# Test a directory
./bin/htmltest htmldoc/fixtures/documents/

# Test with config
./bin/htmltest -c htmldoc/fixtures/conf.yaml

Testing with Fixtures

When adding new features:

  1. Add appropriate test fixtures in htmltest/fixtures/
  2. Create test cases in the relevant *_test.go file
  3. Use the test helper functions (see test_helpers_test.go)
  4. Ensure tests pass both locally and don't require external network access

Example test pattern:

func TestNewFeature(t *testing.T) {
    hT := tTestFileOpts("fixtures/feature/test.html",
        map[string]interface{}{"NewOption": true})
    tExpectIssueCount(t, hT, 0)
}

Makefile Commands

Run make help to see all available commands:

# Build
make build          # Build the binary
make build-verify   # Build and verify with smoke tests
make install        # Install to GOPATH/bin

# Testing
make test           # Run all tests
make test-race      # Run tests with race detector (recommended)
make test-coverage  # Generate coverage report
make test-ci        # Run tests exactly as CI does (race + coverage)
make test-bench     # Run benchmarks

# TDD Workflow (recommended during development)
make test-tdd              # Run specific test(s) with clean cache
make test-tdd-cache        # Same but shows cache state after
make clean-cache           # Just remove refcache file

# Code Quality
make fmt            # Format code
make fmt-check      # Check formatting (CI mode - fails if not formatted)
make vet            # Run go vet
make lint           # Run linter (requires golangci-lint)
make check          # Run all CI checks locally (fmt-check, vet, test-ci)
make ci             # Alias for check

# Utilities
make clean          # Remove build artifacts and cache
make deps           # Download dependencies
make help           # Show all commands with examples

See make help for TDD workflow examples and more details.

Submitting Changes

Before Submitting

  1. Run all CI checks locally: make check or make ci
    • This runs format checking, vet, and tests with race detection + coverage
    • Ensures your code will pass CI
  2. Update documentation if needed
  3. Add tests for new features

If you need to fix formatting issues, run make fmt before running checks again.

Pull Request Guidelines

  1. Create a descriptive branch name (e.g., feature/check-canonical-links)
  2. Write clear commit messages
  3. Include tests for new functionality
  4. Update README.md if adding user-facing features
  5. Ensure all CI checks pass

Need Help?

  • Issues: Submit an issue
  • Documentation: Check the README for user documentation
  • Code patterns: Look at existing tests and checkers for examples

Coding Conventions

  • Follow standard Go conventions
  • Use go fmt for formatting
  • Write tests for new features
  • Keep functions focused and small
  • Document exported functions and types
  • Use descriptive variable names

License

By contributing to htmltest, you agree that your contributions will be licensed under the same license as the project (see LICENCE).


Thank you for contributing to htmltest! 🎉