بنقرة واحدة
write-nix-tests
Write tests for nix scripts. Use when creating or modifying nix scripts, or generating test.nix files.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Write tests for nix scripts. Use when creating or modifying nix scripts, or generating test.nix files.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | write-nix-tests |
| description | Write tests for nix scripts. Use when creating or modifying nix scripts, or generating test.nix files. |
A nix script lives in a directory with:
nix-script-name/
├── default.nix # Main nix script
├── test.nix # Tests using pkgs.lib.runTests
Tests use nix eval -f test.nix — success when output is [ ] (empty list).
let
npinsed = import <path-to-npins>; # relative path, e.g. ../../npins
pkgs = import npinsed.nixpkgs {};
my-derivation = import ./.;
in pkgs.lib.runTests {
test-name = {
expr = <expression>;
expected = <expected value>;
};
}
Run tests with: nix eval -f test.nix
npins and luajit-proDo not use <npins> or <luajit-pro> angle brackets — they require NIX_PATH to be set and break when nix-build is run from outside the project directory.
Instead, use relative paths from each file's location to the repo root directories:
| File location | npins path | luajit-pro path |
|---|---|---|
foo/default.nix | ../npins | ../luajit-pro |
foo/bar/default.nix | ../../npins | ../../luajit-pro |
foo/bar/baz/default.nix | ../../../npins | ../../../luajit-pro |
Example for a file at depth 2 (e.g., lib/mimalloc2/default.nix):
let
npinsed = import ../../npins;
pkgs = import npinsed.nixpkgs {};
in ...
Example with luajit-pro at depth 3 (e.g., lib/lua-modules/tcc/default.nix):
let
npinsed = import ../../../npins;
pkgs = import npinsed.nixpkgs {};
luaPackages = (import ../../../luajit-pro).pkgs;
in ...
builtins.readDir to explore directory structurepkgs.lib.filterAttrs (_: v: v != null) to drop unset optional fieldspkgs.lib.mkIf to conditionally apply configbuiltins.tryEval to test code that should faildefault.nix, use import ./. instead of import ./default.nixIf default.nix takes arguments (e.g., { complete }:), import it with different argument values and test each variant. Combine all assertions into a single pkgs.lib.testAllTrue:
let
npinsed = import ../../npins;
pkgs = import npinsed.nixpkgs {};
my-derivation = import ./. { arg1 = false; };
my-derivation-complete = import ./. { arg1 = true; };
in pkgs.lib.runTests {
test-lib = pkgs.lib.testAllTrue [
((builtins.readDir "${my-derivation}/lib") ? "libfoo.so")
((builtins.readDir "${my-derivation-complete}/lib") ? "libfoocomplete.so")
];
}
Run tests with: `nix eval -f test.nix`
**Building with arguments:**
```bash
nix-build lib/lua-modules/lsqlite/default.nix --arg complete false -o result-tmp
nix-build lib/lua-modules/lsqlite/default.nix --arg complete true -o result-tmp
Before writing tests, always build the derivation first:
nix-build <path-to-default.nix> -o result-tmp
# Explore subdirectories to find actual output files
This reveals:
Then write tests for actual user-facing files: C libs (.so, .a) and Lua scripts (.lua)
Do not write trivial attribute tests (e.g. version, src, pname)
Do not write trivial folder existence tests (e.g. test whether folder lib/, bin/, lua/ exists)
For single files, use builtins.pathExists which is simpler than builtins.readDir:
test-libs = pkgs.lib.testAllTrue [
(builtins.pathExists (import ./. + /lib/libfoo.so))
];
Simple existence test:
test-executable = pkgs.lib.testAllTrue [
(builtins.pathExists (my-derivation + /bin/myexe))
];
Run executable and verify output:
test-executable-runs = let
output = pkgs.runCommand "test-myexe" {
# env is optional, only use it if needed
env = {
MY_ENV_VAR = toString npinsed.some-path;
};
} ''
${my-derivation}/bin/myexe --help > $out 2>&1 || true
'';
content = builtins.readFile output;
in pkgs.lib.testAllTrue [
(builtins.stringLength content > 100)
(pkgs.lib.hasPrefix "<some-pattern>" content)
];
Notes:
env attribute to set environment variables required by the executableenv values must be derivations, strings, booleans, or integers — use toString for paths2>&1) to capture all output|| true if the executable may return non-zero exit code (e.g., --help often does)builtins.stringLength (not pkgs.stringWidth) to check string lengthCombine all tests expecting true into a single pkgs.lib.testAllTrue:
# correct
test-lib = pkgs.lib.testAllTrue [
(dir ? "libfoo.a")
(dir ? "libfoo.so")
];
# wrong — double-wrapping
test-lib = {
expr = pkgs.lib.testAllTrue [ ... ];
expected = true;
};
npinsed for the npins attribute set to distinguish from pkgs.npinspkgs for the nixpkgs instance derived from npinsednixpkgs (or pkgs) source code: $(nix eval --impure --expr "(import $NPINS_DIRECTORY).nixpkgs.outPath")