Template: CI Tests
The CI template is Den’s comprehensive test suite. It tests every feature using nix-unit. This is the best learning resource for understanding exactly how Den behaves.
Every .nix file under modules/ is auto-imported by import-tree — the flake just hands ./modules to it. To add a test, drop a new file in; there is no central list to edit.
Structure
Section titled “Structure”Test files are grouped into four buckets by what surface they exercise:
flake.nix # evalModules + (import-tree ./modules)modules/ new-test.nix # copy-me skeleton for a new test test-support/ eval-den.nix # wires denTest + the den fixture into the flake public-api/ # tests using ONLY the documented public surface internal-api/ # tests poking pipeline internals (not for users) deprecated/ # tests pinning legacy/compat behavior deadbugs/ # one regression test per fixed bugnon-dendritic/ # plain files consumed by import-tree testsprovider/ # a separate flake exporting a namespaceWhen you want to learn the recommended way to do something, read public-api/. The other buckets exist to keep the suite honest: internal-api/ and deprecated/ are not patterns to copy.
Test Categories
Section titled “Test Categories”The tables below point at representative files in public-api/. Each file declares one flake.tests.<suite> and holds several test-* cases.
Core Features
Section titled “Core Features”| Test File | Suite | What It Tests |
|---|---|---|
| conditional-config.nix | conditional-config | Conditional imports using host/user attributes |
| default-includes.nix | default-includes | den.default applying to all hosts/users |
| host-options.nix | host-options | Custom host attributes, hostName, aspect names |
| top-level-parametric.nix | top-level-parametric | Context-aware top-level aspects |
| auto-parametric.nix | auto-parametric | Parametric aspects auto-dispatched by the pipeline |
Bidirectional & Providers
Section titled “Bidirectional & Providers”| Test File | Suite | What It Tests |
|---|---|---|
| user-host-mutual-config.nix | user-host-mutual-config | Host→user and user→host config flow |
| mutual-provider.nix | mutual-provider | Mutual provider mechanism |
| policy-provide.nix | policy-provide | Policy-driven provide effects |
Policies
Section titled “Policies”| Test File | Suite | What It Tests |
|---|---|---|
| policies.nix | policies | Policy declaration and activation |
| policy-excludes.nix | policy-excludes | Policies excluding includes |
| route.nix | route | Route effects |
Batteries
Section titled “Batteries”| Test File | Suite | What It Tests |
|---|---|---|
| define-user.nix | define-user | User definition across contexts |
| primary-user.nix | primary-user | Primary user groups |
| user-shell.nix | user-shell | Shell configuration |
| unfree.nix | unfree | Unfree package predicates |
| tty-autologin.nix | tty-autologin | TTY autologin service |
| vm-autologin.nix | vm-autologin | VM autologin service |
| import-tree.nix | (import-tree) | Auto-importing class dirs |
| flake-parts.nix | flake-parts | inputs' and self' providers |
Advanced
Section titled “Advanced”| Test File | Suite | What It Tests |
|---|---|---|
| angle-brackets.nix | angle-brackets | All bracket resolution paths |
| namespaces.nix | namespaces | Local, remote, merged namespaces |
| forward-from-custom-class.nix | forward-custom-class | Custom class forwarding |
| homes.nix | standalone-homes | Standalone Home-Manager configs |
| schema-base-modules.nix | schema-base-modules | den.schema.{host,user,home,conf} |
Bug Regressions
Section titled “Bug Regressions”Every fixed bug gets a pinned regression test in deadbugs/, named after its issue. A couple of examples:
| Test File | What It Tests |
|---|---|
| deadbugs/static-include-dup-package.nix | Deduplication for packages/lists |
| deadbugs/external-namespace-deep-aspect.nix | Deep aspect access from external flakes |
External Provider
Section titled “External Provider”The provider/ subdirectory is a separate flake that exports a namespace called provider. It is consumed by namespace tests to verify cross-flake aspect consumption. The exporting flake imports den.flakeModule and registers the namespace as an output with den.namespace "provider" true:
{ inputs, ... }:{ imports = [ inputs.den.flakeModule (inputs.den.namespace "provider" true) ];
provider.tools.provides.dev.provides.editors = { nixos.programs.vim.enable = true; };}The second argument to den.namespace (true) marks the namespace as a flake output so other flakes can import it.
Running CI Tests
Section titled “Running CI Tests”From the Den root against your local checkout:
just ciYou can run a single suite (or a sub-path below flake.tests) by passing its name:
# Any attr-path below flake.tests works, e.g. a whole suite:just ci wsl-class
# …or a single case within it:just ci wsl-class.test-wsl-forwardsThe default just ci is fast but cannot show error diffs and skips tests that assert via nix-unit expectedError. Use just ci-deep for full nix-unit output with diffs:
just ci-deep wsl-classWriting New Tests
Section titled “Writing New Tests”Copy modules/new-test.nix as a starting point, rename the suite and case, then assert with expr / expected:
{ denTest, ... }:{ flake.tests.new = { test-something = denTest ( { den, igloo, ... }: { den.hosts.x86_64-linux.igloo.users.tux = { };
den.aspects.base = { host, ... }: { nixos.networking.hostName = host.hostName; };
den.aspects.igloo.includes = [ den.aspects.base ];
expr = igloo.networking.hostName; expected = "igloo"; } ); };}denTest provides handy fixtures as function arguments: den (the live den config), igloo (nixosConfigurations.igloo.config), tuxHm (igloo.home-manager.users.tux), plus iceberg, apple, pinguHm, and a trace helper. Drop your new file under modules/ and git add it before running nix — import-tree only sees tracked files.