# What Is the Purpose of the Tests Directory in Automattic/harper?

> Discover the purpose of the tests directory in Automattic/harper. Explore how it ensures linting accuracy, prevents regressions, and verifies cross-platform functionality.

- Repository: [Automattic/harper](https://github.com/Automattic/harper)
- Tags: internals
- Published: 2026-07-26

---

**The `tests` directories in Automattic/harper serve as the automated quality-assurance backbone, housing unit and integration suites that validate linting accuracy, prevent rule regressions, and verify cross-platform functionality across the Rust core and JavaScript plugin ecosystem.**

The **Harper** monorepo relies on distributed test suites to maintain correctness as the grammar-checking engine evolves. Each crate and plugin package maintains its own dedicated `tests` folder, creating a decentralized but unified safety net that executes on every pull request and CI run. This architecture ensures that changes to the core `LintGroup` logic or individual language parsers do not inadvertently break existing linting behavior or UI integrations.

## Validating Core Linting Accuracy

The primary function of the **tests directory** is to guarantee that the engine produces deterministic, correct results for every supported document format. In [`harper-core/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-core/tests/run_tests.rs), the test suite feeds sample Markdown, Org-mode, and plain text into `LintGroup::new_curated` and asserts specific lint counts against expected values.

These unit tests act as the source of truth for expected behavior. When a developer adds a new grammar rule, corresponding test cases in `harper-core/tests/` document exactly which phrases trigger the lint and which pass silently. This prevents "phantom lints" or missed errors that would degrade the user experience in downstream editor extensions.

## Preventing Rule-Specific Regressions

Harper’s modular architecture isolates language-specific parsers into separate crates, each with targeted regression tests. The **rule-focused tests** in paths like [`harper-ink/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-ink/tests/run_tests.rs), [`harper-html/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-html/tests/run_tests.rs), and [`harper-git-commit/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-git-commit/tests/run_tests.rs) evaluate edge-case inputs using paired "good" and "bad" file comparisons.

For example, when modifying the HTML renderer or Ink parser logic, developers run these isolated suites to confirm that existing linting rules still apply correctly to documents in those formats. This granular approach prevents a change in the Markdown parser from accidentally breaking LaTeX or Git commit message validation.

## Cross-Language Integration Coverage

The **tests directory** extends beyond Rust unit tests to validate the JavaScript/TypeScript bindings and browser extension UIs. Integration tests in `packages/chrome-plugin/tests/*.spec.ts` spin up headless Chrome instances, inject HTML content, and verify that the WebAssembly-compiled linting engine returns diagnostics through the browser API.

Similarly, [`packages/vscode-plugin/src/tests/runTests.ts`](https://github.com/Automattic/harper/blob/main/packages/vscode-plugin/src/tests/runTests.ts) performs end-to-end validation of the Visual Studio Code extension, ensuring activation events, configuration changes, and diagnostic providers function as documented. This cross-language consistency guarantees that the same `LintGroup` logic produces identical results whether running in a native Rust CLI or a WebAssembly browser context.

## CLI and Output Stability

The command-line interface maintains its own validation suite in [`harper-cli/tests/output_format.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/tests/output_format.rs). These tests verify color handling, serialization formats (JSON vs. plain text), and exit codes. By automating CLI behavior checks, Harper ensures that shell scripts and CI pipelines depending on `harper-cli` output format remain stable across releases.

## Running the Test Suites

Execute the full Rust core suite using the Just runner:

```bash
just test-core

```

This command discovers and runs all `#[test]` functions in `harper-core/` and dependent crates via `cargo test`.

For browser extension validation:

```bash
just test-chrome-plugin

```

This launches Jest against the TypeScript files in `packages/chrome-plugin/tests/`.

To run a specific Rust test file directly:

```bash
cargo test --manifest-path harper-core/Cargo.toml --test run_tests

```

Adding a new rule requires a corresponding test case:

```rust
// harper-core/tests/my_new_rule.rs
#[test]
fn detects_my_rule() {
    let src = "This sentence contains a commonmistake.";
    let dict = harper_core::spell::FstDictionary::curated();
    let doc = Document::new_markdown_default(src, &dict);
    let mut linter = LintGroup::new_curated(dict, Dialect::American);
    let lints = linter.lint(&doc);
    assert!(lints.iter().any(|l| l.rule_name == "common-mistake"));
}

```

## Summary

- **Quality assurance backbone**: The `tests` directories provide automated validation for every component in the Harper monorepo.
- **Linting accuracy**: Files like [`harper-core/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-core/tests/run_tests.rs) assert exact lint counts for sample documents.
- **Regression safety**: Language-specific crates contain isolated test suites to prevent collateral damage when modifying parsers.
- **Cross-platform verification**: Integration tests in `packages/` validate JavaScript bindings and browser extension behavior.
- **CI integration**: All tests execute via `just test-*` commands, gating pull requests against unintentional behavior changes.

## Frequently Asked Questions

### How do I run tests locally in the Automattic/harper repository?

Use the Just task runner commands `just test-core` for Rust components or `just test-chrome-plugin` for the Chrome extension. For specific crates, run `cargo test --manifest-path harper-core/Cargo.toml --test run_tests` to target individual test files like [`harper-core/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-core/tests/run_tests.rs).

### What types of tests are included in the tests directories?

The **tests directories** contain three primary categories: unit tests for linting logic (Rust), integration tests for language parsers (e.g., [`harper-html/tests/run_tests.rs`](https://github.com/Automattic/harper/blob/main/harper-html/tests/run_tests.rs)), and end-to-end UI tests for editor plugins (TypeScript in `packages/vscode-plugin/src/tests/` and `packages/chrome-plugin/tests/`).

### How are new grammar rules tested?

New rules require test cases that instantiate `LintGroup::new_curated`, parse a sample document using `Document::new_markdown_default`, and assert that `linter.lint(&doc)` returns the expected diagnostics. These tests typically reside in `harper-core/tests/` or the specific language crate affected by the rule.

### Why does each crate maintain its own tests directory?

Harper follows Rust workspace conventions where each crate (`harper-core`, `harper-ink`, `harper-cli`) owns its validation logic. This decentralization allows developers to run targeted tests for specific parsers without executing the entire monorepo suite, while ensuring that HTML, Git commit, and Ink parsers validate independently against their own edge cases.