Add an automated VM test against a real Invoice Ninja instance
CI / test (push) Canceled after 0s
CI / Build on the declared MSRV (push) Canceled after 0s
CI / Latest stable (advisory) (push) Canceled after 0s

Adds an invoiceninja-nixos flake input and two things built from it:

- nixosConfigurations.invoiceninja-test-nginx/-caddy: manual test
  VMs, re-exported as-is from that repo rather than redefined here —
  same principle as this crate being a client of the SDK, not a
  second implementation of it.
- checks.invoiceninja-cli: an automated nixosTest (tests/, adapted
  from invoiceninja-nixos's own test scaffolding) that boots a real
  Invoice Ninja instance and runs the actual invoiceninja-cli binary
  against it - create/list/get/update/invoice/payment/delete across
  clients, invoices, and payments - rather than raw curl.

tests/common.nix's module import had to change from a relative
../nixos-module/invoiceninja.nix (which doesn't exist here) to a
parameter threaded from the flake input's nixosModules.invoiceninja.

Building the VM pulls from the invoiceninja-nixos cachix cache via a
nixConfig block, mirroring that repo's own.

Also fixes a wrong assumption the first version of this test's final
assertion made, caught by actually running it against a real server:
`clients list` with no `--status` does not exclude soft-deleted
records - confirmed empirically (Invoice Ninja returns everything
regardless of is_deleted unless status=active is passed explicitly).
Corrected the test to check is_deleted via `clients get` instead, and
fixed the misleadingly-incomplete --status doc comment in cli.rs that
had the same wrong assumption baked in.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 16:57:46 -04:00
co-authored by Claude Sonnet 5
parent 96fba9a303
commit c8a67b1208
10 changed files with 466 additions and 4 deletions
+59 -2
View File
@@ -1,14 +1,32 @@
{
description = "invoiceninja-cli: a command-line client for the Invoice Ninja v5 API";
# Mirrors invoiceninja-nixos's own nixConfig: without this, building
# `nixosConfigurations.invoiceninja-test-*` here rebuilds the whole PHP/UI
# app (and its chromium-headless-shell closure) from source instead of
# pulling the cached result.
nixConfig = {
extra-substituters = [ "https://invoiceninja-nixos.cachix.org" ];
extra-trusted-public-keys = [
"invoiceninja-nixos.cachix.org-1:TmRZaji8FFVjjIw9KZmvLrxMxfP+JDThOyOX04z526A="
];
};
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
# For a real Invoice Ninja instance to test the CLI against — see
# CLAUDE.md's "Testing against a real server". Not `follows`-ed to this
# flake's own `nixpkgs`: it pins its own (nixos-26.05, as of writing),
# and `nixosConfigurations.test-nginx`/`test-caddy` below are consumed
# as already-built flake outputs, not re-evaluated against our
# nixos-unstable — the two never need to agree.
invoiceninja-nixos.url = "git+ssh://gitea@gitea.awkawb.cloud/awkawb/invoiceninja-nixos.git";
};
outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }:
outputs = { self, nixpkgs, rust-overlay, flake-utils, invoiceninja-nixos, ... }:
let
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
@@ -60,7 +78,10 @@
in
{
devShells.default = pkgs.mkShell {
packages = [ rustToolchain pkgs.pkg-config pkgs.openssl ];
# jq is for parsing the /api/v1/login response when testing
# against a real server — see CLAUDE.md's "Testing against a
# real server".
packages = [ rustToolchain pkgs.pkg-config pkgs.openssl pkgs.jq ];
RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library";
};
@@ -73,6 +94,30 @@
inherit (pkgs) lib pkg-config openssl;
inherit rustPlatform;
};
# Automated: boots a real Invoice Ninja instance (invoiceninja-nixos's
# module, not a mock) and runs actual `invoiceninja-cli` commands
# against it — create/list/get/update/delete across clients,
# invoices, and payments, including that `update` preserves fields
# it wasn't told about. `tests/` is a vendored, adapted copy of
# invoiceninja-nixos's own test scaffolding; see its
# nixos-test.nix for what it does and doesn't check (it
# deliberately skips things like PDF generation and the language-
# list regression, which are that repo's own concern, not this
# CLI's). Uses invoiceninja-nixos's own pinned nixpkgs (26.05), not
# this flake's nixos-unstable, to build+evaluate the VM/module —
# matches what that module was actually tested against. The CLI
# binary itself (`self.packages.${system}.default`, built against
# our own nixos-unstable) runs fine inside it regardless: Nix
# binaries carry their own closure, so differing nixpkgs revisions
# in the same system closure is an explicitly supported case, not a
# version mismatch to work around.
checks.invoiceninja-cli = import ./tests/nixos-test.nix {
nixpkgsPath = invoiceninja-nixos.inputs.nixpkgs;
inherit system;
invoiceninjaModule = invoiceninja-nixos.nixosModules.invoiceninja;
invoiceninjaCliPkg = self.packages.${system}.default;
};
}) // {
# For a flake that wants `invoiceninja-cli` in its own `pkgs`, not for
# this flake's own `packages.default`/`devShells.default` above (those
@@ -85,5 +130,17 @@
overlays.default = final: _prev: {
invoiceninja-cli = final.callPackage mkInvoiceninjaCli { };
};
# Real Invoice Ninja instances to test this CLI against, reusing
# invoiceninja-nixos's own test VMs as-is rather than redefining them
# here — same principle as this crate being a client of the SDK, not
# a second implementation of it. Known test credentials baked into
# that repo's tests/common.nix: admin@email.com / password (from
# tests/invoice_ninja_test_password). See CLAUDE.md for how to boot
# one and get an API token from it.
nixosConfigurations = {
invoiceninja-test-nginx = invoiceninja-nixos.nixosConfigurations.test-nginx;
invoiceninja-test-caddy = invoiceninja-nixos.nixosConfigurations.test-caddy;
};
};
}