Skip to content

serkonda7/textmate-grammar-test

Repository files navigation

TextMate Grammar Test

CI npm version npm updated

Write unit and snapshot tests for TextMate grammars, validated against the VS Code TextMate engine.

📦 Installation

npm install --save-dev textmate-grammar-test

🔄 Migrating from vscode-tmgrammar-test

Looking for up-to-date dependencies, cleaner and fully refactored codebase, plus additional bug fixes and features?

Migration is straightforward and should only take a few minutes:

  • Install the new package: npm i -D textmate-grammar-test
  • Replace occurrences of
    • vscode-tmgrammar-test -> textmate-grammar-test
    • vscode-tmgrammar-snap -> textmate-grammar-snap
  • Snapshot testing: run once with --updateSnapshot to apply minor .snap format changes
  • Newer versions include a few minor breaking changes. For migration notes see:

🚀 Usage

Note

Spaces are recommended indentation for test files.

This package provides the commands textmate-grammar-test and textmate-grammar-snap.

Add a package.json script like:

"scripts": {
  "test:grammar": "npx textmate-grammar-test syntax/tests/**/*.foo"
}

To see all available command line options, run:

npx textmate-grammar-test --help
# or
npx textmate-grammar-snap --help

📸 Snapshot Testing

Snapshot tests are a simple and fast way to test your grammar.

  1. Create small source files for your test cases
  2. Run npx textmate-grammar-snap "tests/**/*.foo"
  3. Review the generated .snap files
  4. Commit them to your version control

After grammar changes, update snapshots and review the diffs:

npx textmate-grammar-snap --updateSnapshot "tests/**/*.foo"

🧩 Unit Testing Syntax

File Header

Every test file must start with a header line in the format <comment token> SYNTAX TEST v1 "<scopeName>" "Optional description".

For example:

// SYNTAX TEST v1 "source.ts" "Example header for a TypeScript grammar test"

Require specific scopes

Assert that a token has a specific scope using ^:

let count: number = 1
//  ^^^^^ variable.other.readwrite.ts
//         ^^^^^^ support.type.primitive.ts

You can also assert multiple scopes on the same token. Scopes must be ordered from most general to most specific:

let count: number = 1
//         ^^^^^^ meta.type.annotation.ts meta.var-single-variable.expr.ts meta.var.expr.ts

Or you assert the same scopes for multiple tokens in one line:

let x = y + z
//  ^   ^   ^ variable.other.readwrite.ts

// Also works with negative assertions:
let x = y + z
//  ^   ^   ^ variable.other.readwrite.ts ! keyword.operator.arithmetic.ts

Prevent specific scopes

To ensure a token does not receive an unexpected scope, use ! (surrounded by spaces):

    / not a comment
//  ^ ! comment.line.double-slash.ts

Positive and negative assertions can be combined. The ! is only needed to separate the groups:

    / not a comment
//  ^ source.ts ! comment.line.double-slash.ts storage.type.ts

Test the first token of a line

To target a token at the start of a line, use <-. The number of - characters defines the token length.

If an offset is needed, use ~:

let x = "a"
// <--- storage.type.ts

// With offset:
x = "b"
// <~~- keyword.operator.assignment.ts

Language configuration via package.json

Needed information about the grammars is read from the package.json contribution points contributes.grammars and contributes.languages.

If it's not in your project root, provide the path with the --config option.

You can also pass the path to a custom json file imitating the structure.

📜 License

This repo is licensed under the MIT License.

About

Tool for TextMate grammar unit and snapshot testing

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Contributors