/nixt

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

Primary LanguageTypeScriptMIT LicenseMIT

Nixt

Nixt is a unit-testing tool for Nix.

Installation

Imperatively

Using nix-env:

$ nix-env -if https://github.com/nix-community/nixt/archive/master.tar.gz

Using nix profile:

$ nix profile install github:nix-community/nixt

Declaratively

Add Nixt as a flake to your configuration:

{
  inputs.nixt = {
    url = "github:nix-community/nixt";
    inputs.nixpkgs.follows = "nixpkgs";
  };
}

Then add the package to your packages:

{
  environment.systemPackages = [
    inputs.nixt.defaultPackage.x86_64-linux
  ];
}

Help

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

Running Tests

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

$ 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?

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

$ 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?

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

Listing Tests

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

$ 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?

Or with the -v/--verbose flag:

$ 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?

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:

Block = struct "Block" {
  path = path;
  suites = list TestSuite;
};
TestSuite = struct "TestSuite" {
  name = string;
  cases = list TestCase;
};
TestCase = struct "TestCase" {
  name = string;
  expressions = list bool;
};

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.

{
  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;
        }
      ];
    };
  };
}

block

Args:

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

Creates a Block from a path and list of TestSuite.

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

block’

Args:

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

Creates a Block from a path and attrset.

{
  nixt,
  pkgs ? import <nixpkgs> {}
}:
nixt.block ./block.spec.nix {
  "nixt"."passes this test" = true;
  "nixt"."fails this test" = false;
}

describe

Args:

  • name: string
  • cases: list of TestCase

Creates a TestSuite from a string and list of TestCase

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

describe’

Args:

  • name: string
  • cases: attrset of cases

Creates a TestSuite from a string and attrset

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

it

Args:

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

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

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

inject

Args:

  • path: path to a test file

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