nixt icon indicating copy to clipboard operation
nixt copied to clipboard

Simple unit-testing for Nix [maintainer=@Lord-Valen]

#+title: Nixt

Nixt is a unit-testing tool for Nix.

  • Installation

** Imperatively Using nix-env: #+begin_src shell $ nix-env -if https://github.com/nix-community/nixt/archive/master.tar.gz #+end_src

Using nix profile: #+begin_src shell $ nix profile install github:nix-community/nixt #+end_src

** Declaratively Add Nixt as a flake to your configuration:

#+begin_src nix { inputs.nixt = { url = "path:/home/ldlework/src/nixt"; inputs.nixpkgs.follows = "nixpkgs"; }; } #+end_src

Then add the package to your packages:

#+begin_src nix { environment.systemPackages = [ inputs.nixt.defaultPackage.x86_64-linux ]; } #+end_src

  • Help #+begin_src text nixt

    Test-runner for nixlang.

Options

-p, --path string Path to the test suite -w, --watch Watch for changes at path -v, --verbose Show additional test info -l, --list List, but don't run, tests -d, --debug Show nixt-developent relevant info -h, --help Prints this usage guide #+end_src

  • Running Tests

If it does not find a registry, the =nixt= CLI discovers and runs tests located at =-p/--path=:

#+begin_src text $ nixt ./nix/

Found 14 cases in 8 suites over 3 files.

✗ 2 cases failed.

┏ /home/ldlework/src/nixt/cli/nix/get-testset.test.nix ┃ mkSuites ┃ ✗ always fails

┏ /home/ldlework/src/nixt/cli/nix/utils.test.nix ┃ broken test ┃ ✗ undefined variable

⚠ Couldn't import 1 files: - /home/ldlework/src/nixt/cli/nix/invalid.test.nix Import error: called with unexpected argument 'nixt' Did you forgot to add the 'nixt' argument to your test expression? #+end_src

Adding in the =-v/--verbose= flag will show passing cases and additional information on failed cases:

#+begin_src text $ nixt ./nix/ -v

Found 14 cases in 8 suites over 3 files.

✗ 2 cases failed.

┏ /home/ldlework/src/nixt/cli/nix/get-testset.test.nix ┃ mkSuite ┃ ✓ creates correct structure ┃ mkSuites ┃ ✗ always fails ┗ ✓ creates correct structure

┏ /home/ldlework/src/nixt/cli/nix/utils.test.nix ┃ broken test ┃ ✗ undefined variable ┃ error: undefined variable 'baz' ┃ at /home/ldlework/src/nixt/cli/nix/utils.test.nix:12:30: ┃ 11| "broken test" = { ┃ 12| "undefined variable" = baz; ┃ | ^ ┃ 13| }; ┃ (use '--show-trace' to show detailed location information) ┃ dirFiles ┃ ✓ empty list for non-existent path ┃ ✓ non-empty list for existing path ┃ findNixFiles ┃ ✓ empty list for non-existent path ┃ ✓ non-empty list for existing path ┃ getDir ┃ ✓ empty list for non-existent path ┃ ✓ non-empty list for existing path ┃ isNix ┃ ✓ false for non-nix files ┃ ✓ true for nix files ┃ isTestSuite ┃ ✓ false for non-test suites ┗ ✓ true for test suites

⚠ Couldn't import 1 files: - /home/ldlework/src/nixt/cli/nix/invalid.test.nix Import error: called with unexpected argument 'nixt' Did you forgot to add the 'nixt' argument to your test expression? #+end_src

Two =-v -v= verbose flags implies =--show-trace=.

** Listing Tests

To list discovered tests without actually evaluating their cases use the =--l/-list= flag:

#+begin_src text $ nixt ./nix/ -l

Found 14 cases in 8 suites over 3 files.

⚠ Couldn't import 1 files: - /home/ldlework/src/nixt/cli/nix/invalid.test.nix Import error: called with unexpected argument 'nixt' Did you forgot to add the 'nixt' argument to your test expression? #+end_src

Or with the =-v/--verbose= flag:

#+begin_src text $ nixt ./nix/ -l -v

Found 14 cases in 8 suites over 3 files.

┏ /home/ldlework/src/nixt/cli/nix/get-testset.test.nix ┃ mkSuite ┃ - creates correct structure ┃ mkSuites ┃ - always fails ┗ - creates correct structure

┏ /home/ldlework/src/nixt/cli/nix/utils.test.nix ┃ broken test ┃ - undefined variable ┃ dirFiles ┃ - empty list for non-existent path ┃ - non-empty list for existing path ┃ findNixFiles ┃ - empty list for non-existent path ┃ - non-empty list for existing path ┃ getDir ┃ - empty list for non-existent path ┃ - non-empty list for existing path ┃ isNix ┃ - false for non-nix files ┃ - true for nix files ┃ isTestSuite ┃ - false for non-test suites ┗ - true for test suites

⚠ Couldn't import 1 files: - /home/ldlework/src/nixt/cli/nix/invalid.test.nix Import error: called with unexpected argument 'nixt' Did you forgot to add the 'nixt' argument to your test expression? #+end_src

  • Writing Tests

Nixt tests are written in blocks. Users may use flakes or standalone testing.

With standalone testing, a block is put in its own file which:

  • Contains a function taking attrset args =nixt= and =pkgs=
  • Evaluates to a =Block=

Each block is composed of one or more suites; Each suite is composed of one or more cases. Each case should be an expression or list of expressions that evaluate to booleans.

For those curious: #+begin_src nix Block = struct "Block" { path = path; suites = list TestSuite; }; #+end_src

#+begin_src nix TestSuite = struct "TestSuite" { name = string; cases = list TestCase; }; #+end_src

#+begin_src nix TestCase = struct "TestCase" { name = string; expressions = list bool; }; #+end_src

  • Library Functions ** grow

Args:

  • =attrset= containing
    • blocks: =list= of =Block=
    • settings: Optional =attrset= of settings

Builds the nixt registry for cli consumption. Only relevant to flakes.

#+begin_src nix { inputs = { nixt.url = "github:nix-community/nixt"; };

outputs = { nixt, ... } @ inputs: { __nixt = nixt.lib.grow { blocks = [ nixt.lib.block' ./flake.nix { "nixt"."passes this test" = true; "nixt"."fails this test" = false; } ]; }; }; } #+end_src

** block

Args:

  • path: =path= to the current file
  • suites: =list= of =TestSuites=

Creates a =Block= from a =path= and =list= of =TestSuite=.

#+begin_src nix { nixt, pkgs ? import {} }: let inherit (nixt) block describe'; in block ./block.spec.nix [ (describe' "nixt" { "passes this test" = true; "fails this test" = false; }) ] #+end_src

** block'

Args:

  • path: =path= to the current file
  • suites: =attrset= of suites

Creates a =Block= from a =path= and =attrset=.

#+begin_src nix { nixt, pkgs ? import {} }: nixt.block ./block.spec.nix { "nixt"."passes this test" = true; "nixt"."fails this test" = false; } #+end_src

** describe

Args:

  • name: =string=
  • cases: =list= of =TestCase=

Creates a =TestSuite= from a =string= and =list= of =TestCase=

#+begin_src nix { nixt, pkgs ? import {} }: let inherit (nixt) block describe it; in block ./block.spec.nix [ (describe "nixt" [ (it "passes this test" true) (it "fails this test" false) ]) ] #+end_src

** describe'

Args:

  • name: =string=
  • cases: =attrset= of cases

Creates a =TestSuite= from a =string= and =attrset=

#+begin_src nix { nixt, pkgs ? import {} }: let inherit (nixt) block describe'; in block ./block.spec.nix [ (describe' "nixt" { "passes this test" = true; "fails this test" = false; }) ] #+end_src

** it

Args:

  • name: =string=
  • expressions: =bool= or =list= of =bool=

Creates a =TestCase= from a =string= and =bool= or =list= of =bool=

#+begin_src nix { nixt, pkgs ? import {} }: let inherit (nixt) block describe it; in block ./block.spec.nix [ (describe "nixt" [ (it "passes this test" true) (it "fails this test" false) ]) ] #+end_src

** inject

Args:

  • path: =path= to a test file

Provides arguments to compliant files. For standalone support and cli use.