{"id":24604601,"url":"https://github.com/vyadh/nutest","last_synced_at":"2026-01-18T04:31:31.974Z","repository":{"id":263661438,"uuid":"891095858","full_name":"vyadh/nutest","owner":"vyadh","description":"A Nushell test framework.","archived":false,"fork":false,"pushed_at":"2025-12-26T13:51:06.000Z","size":507,"stargazers_count":24,"open_issues_count":3,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-28T01:17:13.717Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Nushell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vyadh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-11-19T18:06:48.000Z","updated_at":"2025-12-26T18:54:40.000Z","dependencies_parsed_at":"2024-12-15T12:23:56.296Z","dependency_job_id":"33c8a728-bbeb-4827-adcf-91dea50f611b","html_url":"https://github.com/vyadh/nutest","commit_stats":null,"previous_names":["vyadh/nu-test","vyadh/nutest"],"tags_count":110,"template":false,"template_full_name":null,"purl":"pkg:github/vyadh/nutest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vyadh%2Fnutest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vyadh%2Fnutest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vyadh%2Fnutest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vyadh%2Fnutest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vyadh","download_url":"https://codeload.github.com/vyadh/nutest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vyadh%2Fnutest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28529649,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-24T16:00:31.338Z","updated_at":"2026-01-18T04:31:31.953Z","avatar_url":"https://github.com/vyadh.png","language":"Nushell","readme":"# Nutest\n\n![CI/CD](https://github.com/vyadh/nutest/actions/workflows/tests.yaml/badge.svg)\n![Tests](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.total\u0026label=Tests)\n![Passed](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.passed\u0026label=Passed\u0026color=%2331c654)\n![Failed](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.failed\u0026label=Failed\u0026color=red)\n![Skipped](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.skipped\u0026label=Skipped\u0026color=yellow)\n\nA [Nushell](https://www.nushell.sh) test framework.\n\n![An example nutest run](resources/test-run.png)\n\n*^ Tests are structured data that can be processed just like any other table.*\n\n![An example nutest run](resources/test-run-terminal.png)\n\n*^ Terminal mode - test results appear as they complete.*\n\n\n## Requirements\n\nNeeds Nushell 0.106.0 or later.\nIf Nushell 0.101.0+ is required, use Nutest v1.0.1.\n\n\n## Motivation\n\nWriting tests in Nushell is both powerful and expressive. Not only for testing Nushell code, but also other things, such as APIs, infrastructure, and other scripts. Nutest aims to encourage writing tests for all sorts of things by making testing more accessible.\n\n\n## Install and Run\n\n### Using [nupm](https://github.com/nushell/nupm)\n\nFirst-time installation:\n\n```nushell\ngit https://github.com/vyadh/nutest.git\ndo { cd nutest; git checkout \u003cversion\u003e } # Where \u003cversion\u003e is the latest release\nnupm install nutest --path\n```\n\nUsage:\n\n```nushell\ncd \u003cyour project\u003e\nuse nutest\nnutest run-tests\n```\n\n### Standalone\n\nFirst-time installation:\n\n```nushell\ngit https://github.com/vyadh/nutest.git\ndo { cd nutest; git checkout \u003cversion\u003e } # Where \u003cversion\u003e is the latest release\ncp -r nutest/nutest \u003ca directory referenced by NU_LIB_DIRS / $env.NU_LIB_DIRS\u003e\n```\n\nUsage:\n\n```nushell\ncd \u003cyour project\u003e\nuse nutest\nnutest run-tests\n```\n\n\n## Writing Tests\n\n### Test Suites\n\nA recognised test suite (a Nushell file containing tests) is recognised by nutest as a filename matching one of the following patterns somewhere within the search path, being the working directory tree or via `--path`:\n- `test_*.nu`\n- `test-*.nu`\n- `*_test.nu`\n- `*-test.nu`\n\n### Test Commands\n\n**Nutest** uses Nushell command attributes as a tag system for tests, test discovery will ignore non-tagged commands. It supports:\n\n| attribute      | description                             |\n|----------------|-----------------------------------------|\n| `@test`        | this is the main tag to annotate tests. | \n| `@before-all`  | this is run once before all tests.      |\n| `@before-each` | this is run before each test.           |\n| `@after-all`   | this is run once after all tests.       |\n| `@after-each`  | this is run after each test.            |\n| `@ignore`      | ignores the test but still collects it. |\n\nFor example:\n\n```nushell\nuse std assert\nuse std/testing *\n\n@before-each\ndef setup [] {\n  print \"before each\"\n  {\n    data: \"xxx\"\n  }\n}\n\n@test\ndef \"some-data is xxx\" [] {\n  let context = $in\n  print $\"Running test A: ($context.data)\"\n  assert equal \"xxx\" $context.data\n}\n\n@test\ndef \"is one equal one\" [] {\n  print $\"Running test B: ($in.data)\"\n  assert equal 1 1\n}\n\n@test\ndef \"is two equal two\" [] {\n  print $\"Running test C: ($in.data)\"\n  assert equal 2 2\n}\n\n@after-each\ndef cleanup [] {\n  let context = $in\n  print \"after each\"\n  print $context\n}\n```\n\nWill return:\n```\n╭───────────┬──────────────────┬────────┬─────────────────────╮\n│   suite   │       test       │ result │       output        │\n├───────────┼──────────────────┼────────┼─────────────────────┤\n│ test_base │ is one equal one │ PASS   │ before each         │\n│           │                  │        │ Running test B: xxx │\n│           │                  │        │ after each          │\n│           │                  │        │ {data: xxx}         │\n│ test_base │ is two equal two │ PASS   │ before each         │\n│           │                  │        │ Running test C: xxx │\n│           │                  │        │ after each          │\n│           │                  │        │ {data: xxx}         │\n│ test_base │ some-data is xxx │ PASS   │ before each         │\n│           │                  │        │ Running test A: xxx │\n│           │                  │        │ after each          │\n│           │                  │        │ {data: xxx}         │\n╰───────────┴──────────────────┴────────┴─────────────────────╯\n```\n\n\n## Current Features\n\n- [x] Supports using Nushell attributes (e.g. `@test`)\n  - Note: The previous format of `#[test]` annotations is still supported but deprecated\n- [x] Flexible test definitions\n- [x] Setup/teardown with created context available to tests\n- [x] Filtering of suites and tests\n- [x] Terminal completions for suites and tests\n- [x] Outputting test results in various ways, including queryable Nushell data tables\n- [x] Test output captured and shown against test results\n- [x] Parallel test execution and concurrency control\n- [x] CI/CD support\n  - [x] Non-zero exit code in the form of a `--fail` flag\n  - [x] Test report integration compatible with a wide array of tools\n\n### Flexible Tests\n\nSupports running various configurations of tests scripts in flexible configurations, whether defined as a \nNushell module or scripts that reference other Nushell commands.\n\nScripts being tested can either be utilised from their public interface as a module via `use \u003ctest-file\u003e.nu` or testing their private interface by `source \u003ctest-file\u003e.nu`.\n\nTests are not limited to use with just Nushell scripts. Nutest combined with the power of Nushell can be used to test command-line tools, APIs, infrastructure or bash/other scripts. Add in use of something like [WireMock](https://wiremock.org) Nushell's `http` commands and mocked HTTP endpoints can be configured for tools under tests with the convenience of Nushell records and defined with the test.   \n\n### Context and Setup/Teardown\n\nSpecify before/after stages for each test via `[before-each]` and `[after-each]` annotations, or for all tests via `[before-all]` and `[after-all]`.\n\nThese setup/teardown commands can also be used to generate contexts used by each test, see Writing Tests section for an example.\n\n### Filtering Suites and Tests\n\nAllows filter of suites and tests to run via a pattern, such as:\n```nushell\nrun-tests --match-suites api --match-tests test[0-9]\n```\nThis will run all files that include `api` in the name and tests that contain `test` followed by a digit.\n\n### Completions\n\nCompletions are available not only for normal command values, they are also available for suites and tests, making it easier to run specific suites and tests from the command line.\n\nFor example, typing the following and pressing tab will show all available suites that contain the word `api`:\n```nushell\nrun-tests --match-suites api\u003ctab\u003e\n```\n\nTyping the following and pressing tab will show all available tests that contain the word `parse`:\n```nushell\nrun-tests --match-tests parse\u003ctab\u003e\n```\n\nWhile test discovery is done concurrently and performant even with many test files, you can specify `--match-suites \u003cpattern\u003e` before `--match-tests` to greatly reduce the amount of work nutest needs to do to find the tests you want to run.\n\n### Results Output\n\nThere are several ways to output test results in nutest:\n- Displaying to the terminal\n- Returning data for pipelines\n- Reporting to file\n\n#### Terminal Display\n\nBy default, nutest displays tests in a textual format so they can be displayed as they complete, or explicitly as `--display terminal`. Results can also be displayed as a table using `--display table`, which will appear at the end of the run. Examples of these two display types can be seen in the screenshots above.\n\nTerminal output can also be turned off using `--display nothing`.\n\n#### Returning Data\n\nIn line with the Nushell philosophy, tests results are also data that can be queried and manipulated. For example, to show only tests that need attention using:\n\n```nushell\nrun-tests --returns table | where result in [SKIP, FAIL]\n```\n\nAlternatively, you can return a summary of the test run as a record using:\n```nushell\nrun-tests --returns summary\n```\n\nWhich will be shown as:\n```\n╭─────────┬────╮\n│ total   │ 54 │\n│ passed  │ 50 │\n│ failed  │ 1  │\n│ skipped │ 3  │\n╰─────────┴────╯\n```\n\nThis particular feature is used to generate the badges at the top of this README as part of the CI test run.\n\nIf a `--returns` is specified, the display report will be deactivated by default, but can be re-enabled by using a `--display` option explicitly.\n\nThe combination of `--display` and `--returns` can be used to both see the running tests and also query and manipulate the output once it is complete. It is also helpful for saving output to a file in a format not supported out of the box by the reporting functionality.\n\n#### Reporting to File\n\nLastly, tests reports can be output to file. See the CI/CD Integration for more details.\n\n\n### Test Output\n\nOutput from the `print` command to stdout and stderr will be captured and shown against test results, which is useful for debugging failing tests.\n\nOutput of external commands cannot currently be captured unless specifically handled in the tests by outputting using the `print` command.\n\n\n### Parallel Test Execution\n\nTests written in Nutest are run concurrently by default.\n\nThis is a good design constraint for self-contained tests that run efficiently. The default concurrency strategy is geared for CPU-bound tests, maximising the use of available CPU cores. However, some cases may need adjustment to run efficiently. For example, IO-bound tests may benefit from lower concurrency and tests waiting on external resources may benefit by not being limited to the available CPU cores.\n\nThe level of concurrency adjusted or even disabled by specifying the `--strategy { threads: \u003cn\u003e }` option to the `run-tests` command, where `\u003cn\u003e` is the number of concurrently executing machine threads. The default handles the concurrency level automatically based on the available hardware.\n\nSee the Concurrency section under How Does It Work? for more details.\n\nThe concurrency level can also be specified at the suite-level by way of a `strategy` annotation. For example, the following strategy will run all tests in the suite sequentially:\n\n```nushell\n#[strategy]\ndef threads []: nothing -\u003e record {\n  { threads: 1 }\n}\n```\n\nThis would be beneficial in a project where most tests should run concurrently by default, but a subset perhaps require exclusive access to a resource, or one that needs a setup/tear down cycle via `before-each` and `after-each`.\n\n\n### CI/CD Support\n\n#### Exit Codes\n\nIn normal operation the tests will be run and the results will be returned as a table with the exit code always set to 0. To avoid manually checking the results, the `--fail` flag can be used to set the exit code to 1 if any tests fail. In this mode, if a test fails, the results will only be printed in the default format and cannot be interrogated due to the need to invoke `exit 1` without a result.\n\n```nushell\nrun-tests --fail\n```\n\nThis is useful for CI/CD pipelines where it is desirable to fail the current\njob. However, note that using this directly in your shell will exit your shell session!\n\n### Test Report Integration\n\nIn order to integrate with CI/CD tools, such as the excellent [GitHub Action to Publish Test Results](https://github.com/EnricoMi/publish-unit-test-result-action), you can output the result in the JUnit XML format. The JUnit format was chosen simply as it appears to have the widest level of support by tooling. The report can be created by by specifying the `--report` option to the `run-tests` command:\n\n```nushell\nrun-tests --fail --report { type: junit, path: \"test-report.xml\" }\n```\n\n### Badges\n\n![Tests](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.total\u0026label=Tests)\n![Passed](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.passed\u0026label=Passed\u0026color=%2331c654)\n![Failed](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.failed\u0026label=Failed\u0026color=red)\n![Skipped](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgist.githubusercontent.com%2Fvyadh%2F0cbdca67f966d7ea2e6e1eaf7c9083a3%2Fraw%2Ftest-summary.json\u0026query=%24.skipped\u0026label=Skipped\u0026color=yellow)\n\nThe above badges serve as an example of how to directly leverage nutest for downstream use. In this case, these badges are generated from the last run on the main branch by saving a summary of the test run to a Gist and leveraging the [shields.io](https://shields.io) project by to query that data by generating a [Dynamic JSON Badge](https://shields.io/badges/dynamic-json-badge). You can see how that can be achieved by looking at [the GitHub Actions workflow in this repository](.github/workflows/tests.yaml).\n\n## Alternative Tools\n\nNushell has an internal runner for the standard library `testing.nu` but is not itself part of the standard library.\n\nThe Nushell package manager [Nupm](https://github.com/nushell/nupm), provides module-focused testing for exported commands.\n","funding_links":[],"categories":["Scripts"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvyadh%2Fnutest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvyadh%2Fnutest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvyadh%2Fnutest/lists"}