Skip to content

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.

The tables below list representative suites. Each test file declares one flake.tests.<suite> and holds several test-* cases.

SuiteWhat It Tests
conditional-configConditional imports using host/user attributes
default-includesden.default applying to all hosts/users
host-optionsCustom host attributes, hostName, aspect names
top-level-parametricContext-aware top-level aspects
auto-parametricParametric aspects auto-dispatched by the pipeline
SuiteWhat It Tests
user-host-mutual-configHost→user and user→host config flow
mutual-providerMutual provider mechanism
policy-providePolicy-driven provide effects
SuiteWhat It Tests
policiesPolicy declaration and activation
policy-excludesPolicies excluding includes
routeRoute effects
SuiteWhat It Tests
define-userUser definition across contexts
primary-userPrimary user groups
user-shellShell configuration
unfreeUnfree package predicates
tty-autologinTTY autologin service
vm-autologinVM autologin service
import-treeAuto-importing class dirs
flake-partsinputs' and self' providers
SuiteWhat It Tests
angle-bracketsAll bracket resolution paths
namespacesLocal, remote, merged namespaces
forward-custom-classCustom class forwarding
standalone-homesStandalone Home-Manager configs
schema-base-modulesden.schema.{host,user,home,conf}

Every fixed bug gets a pinned regression test, named after its issue. A couple of examples:

SuiteWhat It Tests
deadbugs-static-include-dupsDeduplication for packages/lists
deadbugs-namespace-deep-aspectDeep aspect access from external flakes

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:

provider/modules/den.nix
{ 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.

From the Den root against your local checkout:

Terminal window
just ci

You can run a single suite (or a sub-path below flake.tests) by passing its name:

Terminal window
# Any attr-path below flake.tests works, e.g. a whole suite:
just ci c3.wsl-class
# …or a single case within it:
just ci c3.wsl-class.test-wsl-forwards

The 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:

Terminal window
just ci-deep wsl-class

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.

ContributeCommunitySponsor