Leia is a testing utility that tests code blocks in documentation. This makes tests easy to write and also ensures documentation is up to date and working. Behind the scenes documentation is parsed and run as a series of mocha tests.
Leia will
- Consolidate code examples and tests into a single, easy to understand and write
markdownfile - Write functional tests quickly in an accessible and lowest common denominator language (eg
sh/bash/dashetc) - Pass on exit status code
0, fail on anything else - Work cross platform-ish, with some caveats, see Shell Considerations below
- Keep Lando honest so he can be a real hero who doesn't betray his friends again
Leia 1.x requires Node.js 24 or newer.
# With npm
npm install @lando/leiaA basic Leia test needs one H1 heading, at least one matching H2 test heading, and a fenced code block. Inside the code block, a comment describes the test and the following line runs its command.
# Some Example
## Testing
```bash
# Should print a greeting
echo "Hello from Leia"
```You can invoke leia as a command line tool or directly require it in a module.
npx leia
Cleverly converts markdown files into mocha cli tests
USAGE
$ leia <files> <patterns> [--cleanup-header=<cleanup-headers>] [--debug] [--help] [--ignore=<patterns>]
[--module-format=<auto|commonjs|esm>] [--retry=<count>] [--setup-header=<setup-headers>]
[--test-header=<test-headers>] [--shell=<bash|cmd|powershell|pwsh|sh|zsh>] [--stdin] [--timeout=<seconds>]
[--version]
ARGUMENTS
TESTS files or patterns to scan for test
OPTIONS
-c, --cleanup-header=cleanup-header [default: Clean,Tear,Burn] considers these h2 sections as cleanup commands
-i, --ignore=ignore files or patterns to ignore
--module-format=auto|commonjs|esm [default: auto] generates CommonJS or ESM harnesses, autodetected by default
-r, --retry=retry [default: 1] non-negative number of times to retry each test
-s, --setup-header=setup-header [default: Start,Setup,This is the dawning] considers these h2 sections as setup commands
-t, --test-header=test-header [default: Test,Validat,Verif] considers these h2 sections as tests
-v, --version shows version info
--debug shows debug output
--help shows help
--shell=bash|cmd|powershell|pwsh|sh|zsh [default: /opt/homebrew/bin/zsh] runs tests with given shell, autodetected by default
--stdin attachs stdin when the test is run
--timeout=timeout [default: 1800] non-negative whole seconds before tests time out (max 2147483)
EXAMPLES
leia README.md
leia README.md "examples/**/*.md" --retry 6 --test-header Tizzestin
leia "examples/*.md" --ignore BUTNOTYOU.md test --stdin --timeout 5
leia README.md --shell cmd
leia README.md --module-format esm--retry and --timeout accept non-negative integers. Retry counts may not exceed JavaScript's safe-integer limit;
timeouts may not exceed 2147483 seconds so their millisecond conversion remains within Node's timer range. Leia rejects
invalid, fractional, or out-of-range values before generating or loading a harness.
// Instantiate Leia, which remains a CommonJS package.
const Leia = require('@lando/leia');
const leia = new Leia();
async function main() {
const files = leia.find(['examples/**.md']);
const sources = leia.parse(files, {moduleFormat: 'auto'});
const tests = leia.generate(sources);
// runAsync loads either CommonJS or ESM harnesses before returning Mocha.
const runner = await leia.runAsync(tests);
runner.run((failures) => process.exitCode = failures ? 1 : 0);
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});The synchronous CommonJS API remains available when the format is explicitly known:
const Leia = require('@lando/leia');
const leia = new Leia();
const files = leia.find(['examples/**.md']);
const sources = leia.parse(files, {moduleFormat: 'commonjs'});
const tests = leia.generate(sources);
const runner = leia.run(tests);
runner.run((failures) => process.exitCode = failures ? 1 : 0);For more details on specific options check out the code docs
--module-format and the programmatic moduleFormat option accept auto, commonjs, or esm. The default auto
selection starts from the command's initial working directory and walks upward to the nearest package.json. A package
with "type": "module" selects ESM; "type": "commonjs", an absent type, or no package file selects CommonJS. Leia
reports an unreadable or malformed nearest package file instead of silently guessing. An explicit format always overrides
package detection, and one resolved format applies to every Markdown source in an invocation.
CommonJS harnesses use .leia.cjs; ESM harnesses use .leia.mjs. These extensions make the generated format independent
of the temporary directory's enclosing package scope. ESM harnesses load Leia's CommonJS dependencies through Node's
createRequire, so Leia's own package and source remain CommonJS. Projects that added a nested package.json containing
{"type":"commonjs"} only to protect Leia's old .leia.js output may remove that workaround after upgrading.
Use leia.run() for explicitly CommonJS harnesses. Use await leia.runAsync() for auto or ESM workflows; it supports
both formats and loads native ESM through Mocha's asynchronous loader.
For a Markdown file to be recognized as containing functional tests, it needs at least the following:
# Something to identify these testsBy default, Leia looks for sections beginning with "Testing". These sections contain your tests.
## TestingCustomize the words Leia uses to identify test sections with --test-header. Run npx leia --help to see the defaults.
Under a matching H2 heading, add a fenced code block containing at least one comment and one command. The comment becomes the human-readable test description.
Here is a basic code block that runs one test
# Should cat a file
cat test.txtFor more syntax examples, see the basic executable example.
You can also skip tests. This is useful if you want to stub out a test for later.
# Should write this test later and not forget it
skipleia will also set the following environment variables for each test that is running so you can use them for stuff.
Here are the values you would expect for the Should set envvars with the test number test in examples/environment.md running on Leia version v1.0.0 with --retry=1.
# generic vars
LEIA=true
LEIA_ENVIRONMENT=true
LEIA_VERSION=1.0.0
# test vars
LEIA_TEST_RUNNING=true
LEIA_TEST_ID=environment
LEIA_TEST_NUMBER=4
LEIA_TEST_RETRY=1
LEIA_TEST_STAGE=testNote: LEIA_TEST_STAGE can be either setup, test or cleanup and LEIA_TEST_NUMBER resets to 1 for each LEIA_TEST_STAGE.
When --shell is omitted, leia selects a shell with deterministic platform precedence:
- On Windows,
SHELLwins, followed byMSYSTEM=MINGW64usingbash.exe,COMSPEC, and finallycmd.exe. - On macOS and other Unix systems, the account shell from
os.userInfo()wins, followed bySHELL. The final fallback is/bin/zshon macOS and/bin/shelsewhere.
Unix account lookup failures are reported instead of silently changing the selected shell. An unrecognized selected shell
still uses Leia's supported sh behavior.
You can also explicitly tell leia what shell to use with the --shell option. However, currently only bash, sh, zsh, cmd, powershell and pwsh are supported options.
In most use cases it's best to just let leia decide the shell to use automatically.
Leia also allows you to specify additional h2 sections in your markdown for setup and cleanup commands that run before and after your core tests. You can tell leia what words these headers should start with in order to be flagged as setup and cleanup commands using the --setup-header and --cleanup-header options.
Here is an example of a markdown file with Setup, Testing and Cleanup sections. And here is a whole directory of examples that we test on every commit.
If you have a question or would like some community support we recommend you join us on Slack. Note that this is the Slack community for Lando but we are more than happy to help with this module as well!
If you'd like to report a bug or submit a feature request then please use the issue queue in this repo.
User- and developer-visible changes are recorded in the changelog and published release notes.
Leia development requires Node 24 LTS. The root .node-version is the runtime
authority for version-aware local tooling and GitHub Actions. See CONTRIBUTING.md for local setup,
Lando-based setup, validation, and pull request guidance.
To deploy and publish a new version of the package to the npm registry, create a release on GitHub with a semver tag. Every GitHub release publishes to the edge npm tag. Releases not marked as prereleases also move npm's latest tag to the same version, regardless of the version string.
The @lando/leia package must trust the lando/leia GitHub Actions publisher using release.yml. Package publication uses OIDC without an npm token. NPM_DEPLOY_TOKEN is a granular package token used only to update the latest dist-tag, while prepare-release-action synchronizes the version and changelog.
Made with contributors-img.
You can still install the older version of Leia eg leia-parser.
npm install leia-parserAnd its documentation lives on here.