A small, self-contained Daml package that shows how to run Daml Script unit
tests through dpm trace test and wire it into CI/CD.
daml test runs your Script tests but only prints a coverage summary; the
transaction trees go to per-script HTML files meant for the IDE, and a failing
test gives you a verbose message with no rendered source. dpm trace test runs
the same tests and, in the terminal and as JSON:
- renders each script's transaction tree (creates, exercises, archives,
submitMustFailguard nodes, parties, arguments, source locations); - maps every failed test back to source — the test call site and the
contract invariant (
assertMsg/abort/ensure) that rejected it; - returns a non-zero exit code when any test fails, so it gates CI;
- emits a machine-readable report with
--print-jsonand standard JUnit XML with--junit.
No Canton node is involved: daml test uses the in-memory IDE ledger, so this
runs anywhere a Daml toolchain runs.
daml/Asset.daml # an IOU-style Asset contract: Transfer, Split, Burn, ensure quantity > 0
daml/Test.daml # Daml Script unit tests: happy paths + submitMustFail guards (the gate)
daml/FailureDemo.daml # one deliberately failing test, to show source-mapped failures
.github/workflows/ci.yml # GitHub Actions CI using `dpm trace test` as the gate
run-demo.sh # green run -> inject a regression -> red run -> revert
The tests mix the cases a real suite has:
| Test | What it exercises |
|---|---|
testIssue |
create, payload/observer visibility |
testTransfer |
consuming exercise → archive + child create |
testSplit |
exercise → two child creates |
testCannotIssueZero |
ensure quantity > 0 rejection (submitMustFail) |
testStrangerCannotTransfer |
authorization rejection (submitMustFail) |
testBadSplitFails |
in-choice assertMsg rejection (submitMustFail) |
# from this directory
daml build # produces .daml/dist/asset-tests-1.0.0.dar (optional but recommended)
dpm trace test . # run every Script test, render trees, gate on failures
dpm trace test . --no-trees # summary + failures only (compact CI logs)
dpm trace test . --print-json # machine-readable report
dpm trace test . -p testSplit # run a subset by patternIf the dpm plugin is not on your PATH, run the CLI directly:
PYTHONPATH=../dpm-trace/src python3 -m dpm_trace.cli test . --daml damlPass --dar .daml/dist/asset-tests-1.0.0.dar to verify failure text against the
compiled package with damlc inspect before resolving it against local sources.
./run-demo.sh shows the full story end to end: a green run, then it weakens
ensure quantity > 0 to >= 0, re-runs, and the zero-quantity guard test fails
with a source-mapped diagnostic and a non-zero exit code — then it reverts.
FAIL testCannotIssueZero
message: ... Expected submit to fail but it succeeded
daml/Test.daml:63:3
> 63 | submitMustFail issuer do
^
.github/workflows/ci.yml is a complete example. The key line is just:
dpm trace test . --junit dpm-trace-results.xml --no-treesA non-zero exit fails the job; the JUnit XML is uploaded for the test-report UI; and any failure is printed with its source location in the job log.