diff --git a/docs/manual/contributing/tests.md b/docs/manual/contributing/tests.md index ce537aac7..c47931010 100644 --- a/docs/manual/contributing/tests.md +++ b/docs/manual/contributing/tests.md @@ -6,10 +6,162 @@ the form of \"golden tests\" where, for example, a generated configuration file is compared to a known correct file. It is relatively easy to create tests by modeling the existing tests, -found in the `tests` project directory. For a full reference to the -functions available in test scripts, you can look at NMT's +found in the `tests` project directory. + +## Writing Basic Tests {#sec-tests-basic} + +Home Manager tests use the **NMT** framework, which provides +a set of assertion functions to verify that modules generate the expected files +and configurations. Tests are written as Nix expressions that define both the +Home Manager configuration and the test assertions. + +### Test Structure {#sec-tests-structure} + +A basic test file structure looks like: + +```nix +{ + # Home Manager configuration + programs.myprogram = { + enable = true; + settings = { + option = "value"; + }; + }; + + # NMT test script with assertions + nmt.script = '' + assertFileExists "home-files/.config/myprogram/config.toml" + assertFileContent "home-files/.config/myprogram/config.toml" ${./expected-config.toml} + ''; +} +``` + +### Test Organization {#sec-tests-organization} + +Tests are organized in the `tests` directory structure: + +- `tests/modules/programs/myprogram/default.nix` - Lists all test cases for the module +- `tests/modules/programs/myprogram/basic-configuration.nix` - A basic test case +- `tests/modules/programs/myprogram/expected-config.toml` - Expected output file + +The `default.nix` file should list all test cases: + +```nix +{ + myprogram-basic-configuration = ./basic-configuration.nix; + myprogram-empty-settings = ./empty-settings.nix; +} +``` + +### Common NMT Assertions {#sec-tests-assertions} + +NMT provides several assertion functions: + +- `assertFileExists "path"` - Verify a file was created +- `assertPathNotExists "path"` - Verify a file was NOT created +- `assertFileContent "path" expected-file` - Compare file contents +- `assertFileRegex "path" "regex"` - Check file matches regex + +For a full reference to the functions available in test scripts, you can look at NMT's [bash-lib](https://git.sr.ht/~rycee/nmt/tree/master/item/bash-lib). +### Practical Examples {#sec-tests-examples} + +Here are some real-world examples of common test patterns: + +**Testing that a configuration file is generated:** +```nix +{ + programs.alacritty = { + enable = true; + settings.font.size = 12; + }; + + nmt.script = '' + assertFileExists "home-files/.config/alacritty/alacritty.yml" + assertFileContains "home-files/.config/alacritty/alacritty.yml" "size: 12" + ''; +} +``` + +**Testing that no files are created when disabled:** +```nix +{ + programs.alacritty.enable = false; + + nmt.script = '' + assertPathNotExists "home-files/.config/alacritty" + ''; +} +``` + +**Testing exact file content against expected output:** +```nix +{ + programs.fastfetch = { + enable = true; + settings.display.color = "blue"; + }; + + nmt.script = + let + configFile = "home-files/.config/fastfetch/config.jsonc"; + in + '' + assertFileExists "${configFile}" + assertFileContent "${configFile}" ${./expected-config.jsonc} + ''; +} +``` + +**Testing multiple conditions in one test:** +```nix +{ + programs.myprogram = { + enable = true; + configFile = "custom.conf"; + extraConfig = "debug = true"; + }; + + nmt.script = '' + assertFileExists "home-files/.config/myprogram/custom.conf" + assertFileRegex "home-files/.config/myprogram/custom.conf" "debug = true" + assertFileRegex "home-files/.config/myprogram/custom.conf" "^# Generated by Home Manager" + ''; +} +``` + +### Platform-Specific Tests {#sec-tests-platform-specific} + +When a module is platform-specific (Linux-only or Darwin-only), the test's `default.nix` +file should use `lib.optionalAttrs` to conditionally expose tests based on the platform. +This prevents evaluation errors on unsupported platforms during the test suite runs. + +**Linux-only module tests:** +```nix +{ lib, pkgs, ... }: + +lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { + rofi-valid-config = ./valid-config.nix; + rofi-custom-theme = ./custom-theme.nix; +} +``` + +**Darwin-only module tests:** +```nix +{ lib, pkgs, ... }: + +lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { + sketchybar-basic = ./basic-configuration.nix; + sketchybar-lua-config = ./lua-config.nix; +} +``` + +For cross-platform modules that have packages which need to be stubbed on Darwin, +add the package names to `tests/darwinScrublist.nix` to prevent build failures +during cross-platform test runs. + ## Using the tests command {#sec-tests-command} Home Manager provides a convenient `tests` command for discovering and running tests: