aux4
Documentation
HomeGetting StartedInstallationIDEsVariablesExecutorsFunctionsConfigurationCommandsHooksSecurityRenderTestingPackage ManagerPackagingGitHub ActionsDocker

Testing

aux4 includes a markdown-based testing framework for writing and running tests against your commands.

Installation

Install aux4/test:

1> aux4 aux4 pkger install aux4/test

Usage

Run Tests

1> aux4 test run [directory|file] [options]

Options:

  • --configFile <path> — Path to a config.yaml file for variable substitution
  • --config <section> — Config section name to load variables from
  • --aiConfig <section> — Config section for AI-powered validation (expect:ai, expect:ai:score)
  • --group <name> — Run only a specific test group (can be repeated for multiple groups)
  • --output <path> — Write test results as JSON to a file

Examples:

1# Run all tests in current directory 2> aux4 test run 3 4# Run a specific test file 5> aux4 test run test/greet.test.md 6 7# Run with config variables 8> aux4 test run --configFile config.yaml --config dev 9 10# Run a specific group 11> aux4 test run --group smoke 12 13# Save results to JSON 14> aux4 test run --output results.json

Add Tests

Programmatically add new tests to existing .test.md files:

1> aux4 test add --testFile <file> --level <heading_level> --name <name> [--file <filename>] [--execute <command>]

Inspect Tests

Extract all files from a test scenario and save them to a directory. Useful for debugging test fixtures:

1> aux4 test inspect --testFile <file> --name <scenario_name> --dir <output_directory>

Writing Tests with .test.md Files

aux4 tests are written in Markdown files with the .test.md extension. These files use a structured format with headings to define test scopes and code blocks for test execution and expectations.

Test Structure and Scope

Tests are organized hierarchically using Markdown headings:

  • # (H1): Defines the main test scenario/suite
  • ## (H2-H6): Defines nested test scenarios within the parent scope

Each heading level creates a new test scope that can contain:

  • Setup/teardown commands
  • Test files
  • Execute/expect test pairs

Code Blocks

Execute Block

Defines the command to run:

1```execute 2echo "Hello World" 3```

Expect Block

Defines the expected output with optional modifiers:

1```expect 2Hello World 3```

Expect Modifiers

You can modify expect behavior using colon-separated modifiers:

  • partial: Match substring instead of exact match
  • ignoreCase: Case-insensitive matching
  • regex: Treat expected value as regular expression

Modifiers can be combined:

1```expect:partial 2Hello 3``` 4 5```expect:ignoreCase 6hello world 7``` 8 9```expect:regex 10Hello.*World 11``` 12 13```expect:partial:ignoreCase 14hello 15``` 16 17```expect:regex:ignoreCase 18error code: [a-z]+\d+ 19```

JSON Modifier

Use expect:json to compare JSON output. Both the actual output and expected value are parsed as JSON before comparison, so formatting differences don't matter:

1```execute 2aux4 config get dev 3``` 4 5```expect:json 6{ 7 "host": "localhost", 8 "port": 3000 9} 10```

Can be combined with other modifiers:

1```expect:json:partial 2{ 3 "host": "localhost" 4} 5```

AI Validation

Use expect:ai to validate output using an LLM. The expect block contains a natural language description of what the output should be. Requires the aux4/ai-agent package installed and --aiConfig flag:

1```execute 2aux4 greet --name Alice 3``` 4 5```expect:ai 6The output should be a friendly greeting that includes the name Alice 7```
1> aux4 test run --configFile config.yaml --aiConfig ai

AI Scoring

Use expect:ai:score to score output on a numeric scale. Define the evaluation criteria and pass threshold:

1```execute 2aux4 greet --name Alice 3``` 4 5```expect:ai:score 6name: friendliness 7eval: How friendly is this greeting? 8range: 1-5 9pass: 3 10```

Fields:

  • name — Score label shown in output
  • eval — Evaluation prompt for the LLM
  • range — Numeric scale (default: 1-5)
  • pass — Minimum passing score (default: 3)

Text Similarity

Use expect:similar to compare output using deterministic text similarity metrics without AI:

1```execute 2aux4 greet --name Alice 3``` 4 5```expect:similar 6metric: fuzzy 7pass: 0.9 8--- 9Hello Alice! Welcome aboard. 10```

Fields:

  • metric — Similarity algorithm: fuzzy (Levenshtein, default), cosine (word vectors), jaccard (word set overlap)
  • pass — Minimum similarity score from 0 to 1 (default: 0.8)
  • After ---, the reference text to compare against
  • Can also use file: path/to/reference.txt to load reference from a file

Can be combined with :ignoreCase:

Wildcard Patterns in Partial Matching

When using expect:partial, you can use special wildcard patterns:

  • *?: Match any characters on a single line
  • **: Match any characters across multiple lines (multiline wildcard)
1```execute 2echo "File: test.txt Size: 1024 bytes" 3``` 4 5```expect:partial 6File: *? Size: *? bytes 7``` 8 9```execute 10echo -e "Header: Processing\n\nMultiple lines\nof output\n\nFooter: Complete" 11``` 12 13```expect:partial 14Header:**Footer: Complete 15```

You can combine wildcards:

1```execute 2echo -e "File: test.txt\nSize: 1024 bytes\nModified: today" 3``` 4 5```expect:partial 6File: *?**Modified: *? 7```

Multiple Expect Blocks

A single execute command can have multiple expect blocks with different modifiers:

1```execute 2echo "[Line 1](lines_1): Hello World 3[Line 2](lines_2): Testing 123 4[Line 3](lines_3): Final result" 5``` 6 7```expect:partial 8Hello World 9``` 10 11```expect:partial 12Testing 123 13``` 14 15```expect:regex 16Line \d+: Hello World 17```

Error Block

Expect specific error output:

1```error 2Command not found 3```

Error blocks support the same modifiers as expect blocks (partial, ignoreCase, regex).

Timeout Block

Configure a custom timeout for tests in milliseconds. This is useful for long-running commands:

1```timeout 25000 3``` 4 5```execute 6sleep 2 && echo "Command completed" 7``` 8 9```expect 10Command completed 11```

If no timeout is specified, the default timeout is used.

Setup and Teardown Blocks

  • beforeAll: Run once before all tests in the scope
  • afterAll: Run once after all tests in the scope
  • beforeEach: Run before each test in the scope
  • afterEach: Run after each test in the scope
1```beforeAll 2mkdir temp 3``` 4 5```afterAll 6rm -rf temp 7```

File Block

Create temporary files for testing:

1```file:test.txt 2This is test content 3that spans multiple lines 4```
File Scope

Files are scoped to their parent heading level and all nested tests within it. Files created at one level are:

  • Available to all nested tests (deeper heading levels)
  • Not available to sibling tests (same heading level)
  • Not available to tests in other parent sections
1## Parent Scenario 2 3```file:parent-file.txt 4This file is created at parent level 5``` 6 7### Nested Test - File Available 8 9```execute 10cat parent-file.txt 11``` 12 13```expect 14This file is created at parent level 15``` 16 17## Sibling Scenario - File NOT Available 18 19```execute 20cat parent-file.txt 2>/dev/null || echo "File not found" 21``` 22 23```expect 24File not found 25```

Flexible Backticks

When your test content contains markdown code blocks, you can use more than 3 backticks for the outer block. The test parser will correctly match the same number of backticks:

1````execute 2printf "Code block:\n\`\`\`javascript\nconsole.log(\"hello\");\n\`\`\`\n" 3```` 4 5````expect 6Code block: 7```javascript 8console.log("hello"); 9``` 10````

This works for all block types: execute, expect, error, file, timeout, and hooks.

Dataset Block

Datasets allow you to parameterize tests with JSON data. Each entry in the dataset generates a separate test run:

1```dataset 2file: users.json 3root: $.items 4key: name 5``` 6 7```execute 8aux4 greet --name {{name}} 9``` 10 11```expect:partial 12Hello {{name}} 13```

Fields:

  • file — Path to a JSON file
  • root — JSONPath expression to extract an array from nested JSON (optional)
  • key — Field name used for test labeling in output (optional)

Shorthand syntax for simple cases:

1```dataset:users.json 2```

Given users.json:

1[ 2 { "name": "Alice", "age": 30 }, 3 { "name": "Bob", "age": 25 } 4]

This generates two tests: one for Alice and one for Bob. Each entry's fields become available as {{fieldName}} variables.

Variable Substitution

Test files support {{variableName}} substitution in execute, expect, error, and file blocks. Variables come from:

  1. Config files — Pass --configFile config.yaml --config section to load variables
  2. Datasets — Each dataset entry's fields become variables
1> aux4 test run --configFile config.yaml --config dev

Given config.yaml:

1config: 2 dev: 3 host: localhost 4 port: 3000

You can use {{host}} and {{port}} in your tests:

1```execute 2curl http://{{host}}:{{port}}/health 3``` 4 5```expect 6ok 7```

Test Suites

Group test files into suites using test.suite.md files. Suites let you organize tests into named groups and run specific groups with the --group flag:

1## smoke 2- health.test.md 3- auth.test.md 4 5## integration 6- api.test.md 7- database.test.md 8 9## performance (optional) 10- load.test.md

Groups marked (optional) only run when explicitly requested:

1# Run all non-optional groups 2> aux4 test run 3 4# Run only smoke tests 5> aux4 test run --group smoke 6 7# Run multiple groups 8> aux4 test run --group smoke --group integration 9 10# Run optional group 11> aux4 test run --group performance

Example Test File

1# Echo Tests 2 3## Basic functionality 4 5```beforeAll 6mkdir -p test-output 7``` 8 9```afterAll 10rm -rf test-output 11``` 12 13### Exact match 14 15```execute 16echo "Hello, World!" 17``` 18 19```expect 20Hello, World! 21``` 22 23### Case insensitive matching 24 25```execute 26echo "Hello, World!" 27``` 28 29```expect:ignoreCase 30hello, world! 31``` 32 33### Partial matching 34 35```execute 36echo "The quick brown fox jumps" 37``` 38 39```expect:partial 40quick brown 41``` 42 43### Regular expression matching 44 45```execute 46echo "Version 1.2.3" 47``` 48 49```expect:regex 50Version \d+\.\d+\.\d+ 51``` 52 53## Error handling 54 55```execute 56nonexistent-command 57``` 58 59```error:partial 60command not found 61```

Adding Tests with the Add Command

The aux4 test add command allows you to programmatically add new tests to existing .test.md files. This is useful for automation or when you want to quickly scaffold new test cases.

When you run aux4 test add, it executes the command and automatically includes an expect block with the current output.

Command Syntax

1> aux4 test add --testFile <test_file> --level <heading_level> --name <test_name> [options]

Parameters

  • --testFile: Path to the .test.md file where the test should be added
  • --level: Heading level (1-6) that determines the test scope hierarchy
  • --name: Name of the test (will become the heading text)
  • --file <filename>: Add file blocks to the test (can be used multiple times). Reads the content of existing files.
  • --execute <command>: Add an execute block with the specified command

Examples

The add command generates markdown content that follows the test file structure. Here are examples of what gets generated:

Simple test with execution

1> aux4 test add --testFile my.test.md --level 2 --name "Test echo command" --execute "echo 'Hello World'"
1## Test echo command 2 3```execute 4echo 'Hello World' 5``` 6 7```expect 8Hello World 9```

Test with file setup

1> aux4 test add --testFile api.test.md --level 2 --name "Test API endpoint" --file config.json --file data.txt --execute "curl -X POST localhost:3000/api"

The --file option reads the content of existing files and adds them to the test as file blocks:

1## Test API endpoint 2 3```file:config.json 4{ 5 "apiUrl": "http://localhost:3000", 6 "timeout": 5000 7} 8``` 9 10```file:data.txt 11sample data content 12``` 13 14```execute 15curl -X POST localhost:3000/api 16``` 17 18```expect 19{"status": "ok"} 20```

Nested test

1> aux4 test add --testFile integration.test.md --level 3 --name "Error handling" --execute "invalid-command"
1### Error handling 2 3```execute 4invalid-command 5``` 6 7```expect 8command not found 9```

The add command will insert the new test at the appropriate location in the file based on the heading level, maintaining the hierarchical structure of your test file.

Testing aux4 Commands

You can test aux4 commands themselves using .test.md files. This is particularly useful for testing custom aux4 plugins or validating aux4 behavior.

Setting up aux4 Commands for Testing

To test aux4 commands, you typically need a .aux4 file that defines the command behavior. Here's an example of testing a simple greeting command:

1# aux4 Hello Command Test 2 3## Setup aux4 command 4 5```file:.aux4 6{ 7 "profiles": [ 8 { 9 "name": "main", 10 "commands": [ 11 { 12 "name": "hello", 13 "execute": [ 14 "echo \"Hello, ${name}\"" 15 ], 16 "help": { 17 "text": "Simple greeting command", 18 "variables": [ 19 { 20 "name": "name", 21 "text": "Name to greet" 22 } 23 ] 24 } 25 } 26 ] 27 } 28 ] 29} 30``` 31 32### Test greeting command 33 34```execute 35aux4 hello --name John 36``` 37 38```expect 39Hello, John 40``` 41 42### Test with different name 43 44```execute 45aux4 hello --name "Alice Smith" 46``` 47 48```expect 49Hello, Alice Smith 50```