@veridtools/dmn-fixtures
v0.3.5
Published
DMN test fixtures covering DMN 1.0 to 1.5
Downloads
1,563
Maintainers
Readme
@veridtools/dmn-fixtures
A comprehensive library of DMN/FEEL fixture files for JavaScript and TypeScript tooling. Covers 100% of the OMG DMN 1.1–1.5 and FEEL specification — every feature a FEEL runner or DMN runner needs to implement correctly.
At a glance
- 784 DMN/XML fixture files across 5 categories
- 416 companion JSON files with typed inputs and expected outputs
- ~100% coverage of OMG DMN/FEEL spec features (every function, operator, expression type, and boxed expression)
- DMN 1.1 → 1.5 with correct namespaces per version
- 0 runtime dependencies
- 100% TypeScript
- MIT licensed
Why
Building a DMN engine, FEEL evaluator, or DMN tooling in JavaScript/TypeScript requires a reliable test corpus. The official OMG TCK targets Java runtimes and focuses on volume over feature completeness. This package takes the opposite approach: every DMN/FEEL spec feature has at least one fixture designed to catch a runner bug, with companion JSON that specifies exact expected outputs.
If you're building a feel-runner or dmn-runner, this library gives you the test harness to verify correctness against the spec.
See COVERAGE.md for detailed coverage percentages by spec section.
See AUDIT.md for the running audit log that tracks how coverage was built up.
Installation
pnpm add -D @veridtools/dmn-fixtures
# or
npm install --save-dev @veridtools/dmn-fixturesFixture categories
| Category | DMN files | JSON files | What it covers |
|---|---|---|---|
| structure | 368 | — | All DMN 1.1–1.5 XML elements: decision tables, boxed expressions, DMNDI, requirements, imports, services |
| s-feel | 59 | 59 | S-FEEL unary tests, all 7 hit policies + aggregations, AllowedValues, decision chaining, edge cases (UNIQUE multi-match, dash matches null, empty table) |
| feel-types | 155 | 155 | All FEEL data types, operators, for, if, some/every, instance of, path/filter, decimal128, 3-valued null, Unicode |
| feel-functions | 144 | 144 | All built-in functions DMN 1.0→1.5 (incl. string join, list replace) with positional and named parameter syntax |
| execution | 58 | 58 | Decision table execution, BKMs, boxed conditional/filter/iterator, decision services, multi-model import |
Usage
Load a fixture file
import { loadFixture } from '@veridtools/dmn-fixtures'
const xml = loadFixture('feel/functions/string/fn-substring.dmn')Run executable fixtures against a FEEL runner
import { CATALOG, loadFixture } from '@veridtools/dmn-fixtures'
import * as fs from 'fs'
// Get all feel-functions fixtures with test cases
const cases = CATALOG
.filter(f => f.category === 'feel-functions' && f.testCasesPath)
.map(f => ({
fixture: f,
xml: loadFixture(f.path),
tests: JSON.parse(fs.readFileSync(`./fixtures/${f.testCasesPath}`, 'utf-8')).cases
}))
for (const { fixture, xml, tests } of cases) {
for (const { context, expected } of tests) {
const result = myFeelRunner.evaluate(xml, context)
assert.deepEqual(result, expected, `${fixture.path} failed`)
}
}Filter by category or group
import { CATALOG } from '@veridtools/dmn-fixtures'
// All S-FEEL fixtures
const sfeelFixtures = CATALOG.filter(f => f.category === 's-feel')
// All FEEL type fixtures with companion JSON
const typeFixtures = CATALOG.filter(f => f.category === 'feel-types' && f.testCasesPath)
// Structure fixtures for a specific group
const hitPolicyFixtures = CATALOG.filter(f => f.group === 'hit-policy')
// All executable fixtures across all categories
const executableFixtures = CATALOG.filter(f => f.testCasesPath)FixtureEntry shape
interface FixtureEntry {
path: string // relative path from fixtures/
category: string // 'structure' | 's-feel' | 'feel-types' | 'feel-functions' | 'execution'
group: string // sub-group within category (e.g. 'hit-policy', 'string', 'bkm')
format: 'dmn' | 'xml'
description: string
testCasesPath?: string // path to companion JSON (undefined for structure fixtures)
dmnVersion?: string // '1.1' | '1.2' | '1.3' | '1.4' | '1.5'
}Companion JSON format
// fixtures/feel/functions/string/fn-substring.json
{
"description": "substring(string, startPosition) ...",
"cases": [
{ "context": { "s": "hello", "start": 2 }, "expected": "ello" },
{ "context": { "s": "hello", "start": -2 }, "expected": "lo" }
]
}For fixtures where the DMN has no input data (self-contained expressions), the context is {} and expected is keyed by decision name:
{
"cases": [
{
"context": {},
"expected": { "Result": { "substring_named": "world", "contains_named": true } }
}
]
}Spec coverage highlights
FEEL built-in functions — all 80, with named parameter syntax
Every built-in function is tested positionally and with named parameters:
// Positional
substring("hello world", 7) // → "world"
floor(-1.567, 1) // → -1.6
// Named params
substring(string: "hello world", startPosition: 7)
floor(n: -1.567, scale: 1)
date and time(date: date("2024-06-15"), time: time("09:00:00"))FEEL expression types — every form
// for with partial (DMN 1.5)
for i in 1..5 return if i = 1 then 1 else partial[-1] + i // → [1, 3, 6, 10, 15]
// Context with inline function invocation
{ f: function(x) x * 2, result: f(5) }.result // → 10
// Self-recursive function
{ fact: function(n) if n <= 1 then 1 else n * fact(n - 1), r: fact(5) }.r // → 120
// instance of with complex types
[1,2,3] instance of list<number> // → true
(function(x) x+1) instance of function<number>->number // → trueTemporal arithmetic — all combinations
date("2024-01-31") + duration("P1M") // → date("2024-02-29") (end-of-month clamp)
date and time("2024-01-15T09:00:00") + duration("PT2H") // → "2024-01-15T11:00:00"
duration("PT3H") / duration("PT1H") // → 3 (duration ÷ duration → number)DMN execution — all patterns
// Multi-model import
MathLib.Double(Value) // BKM from imported DMN file
MathLib.Clamp(Value, 0, 100)
// functionDefinition as decision expression (returns callable function)
// Decision "Square Function" returns function(x) x*x
// Decision "Result" invokes Square Function(Input)
// Boxed conditional, filter, iterator (DMN 1.4+)
// All tested with companion JSONHow this compares to the DMN TCK
The DMN Technology Compatibility Kit is the official OMG conformance suite — 3,390 test cases validating FEEL and decision table evaluation.
| Dimension | DMN TCK | This package |
|---|---|---|
| Primary target | Java runtimes | JavaScript / TypeScript |
| FEEL functions | ~2,000 cases, 80 functions | ~450 cases, all 80 spec functions + named params (incl. string join DMN 1.4 and list replace DMN 1.5) |
| FEEL types/operators | ~800 cases | ~300 cases, ~100% of spec features |
| S-FEEL / Compliance L2 | ~200 cases | ~210 cases, ~100% of features |
| DMN execution patterns | ~400 cases | ~160 cases, ~100% of patterns |
| DMN structure | 0 (out of scope) | 368 fixtures — unique to this package |
| Volume vs TCK | 3,390 cases | ~1,120 executable + 368 structural |
This package prioritizes 100% spec feature coverage over combinatorial volume. If your runner handles each feature correctly, the TCK cases are variations of the same behavior.
Critical runner invariants
If your FEEL runner fails any of these, it is not spec-compliant. All have fixtures in this library:
| Invariant | Expected |
|---|---|
| 0.1 + 0.2 = 0.3 | true (decimal128, not float) |
| 5 / 2 | 2.5 (no integer division) |
| 1 / 0 | null (not exception, not infinity) |
| null = null | true (not SQL-style null) |
| "5" = 5 | false (no implicit coercion) |
| count("a") | 1 (singleton coercion) |
| [{a:1},{a:2}].a | [1, 2] (path on list) |
| all([]) | true (vacuous truth) |
| decimal(2.5, 0) | 2 (banker's rounding — half to even) |
| modulo(-5, 3) | 1 (sign of divisor, not dividend) |
| date("2024-01-31") + duration("P1M") | date("2024-02-29") (end-of-month clamp, leap) |
| string length("😀") | 1 (code points, not UTF-16 code units) |
| if true then 1 else 1/0 | 1 (dead branch short-circuits) |
| -2 ** 2 | 4 (unary minus tighter than exponent) |
| {a:1}.b | null (missing key is null, not error) |
| {a:1, b:a+1}.b | 2 (sibling references resolve in order) |
See COVERAGE.md for the complete list with fixture mappings.
Documentation
COVERAGE.md — Detailed coverage report: spec section by section (FEEL §10.3, S-FEEL §8, decision tables §9, structure §6/§7/§12), complete list of critical invariants, comparison to TCK. Updated after every expansion stage.
AUDIT.md — Audit log used to validate changes. Required reading before adding new fixtures.
DMN namespace by version
| Version | Namespace |
|---------|-----------|
| 1.1 | http://www.omg.org/spec/DMN/20151101/dmn.xsd |
| 1.2 | http://www.omg.org/spec/DMN/20180521/MODEL/ |
| 1.3 | https://www.omg.org/spec/DMN/20191111/MODEL/ |
| 1.4 | https://www.omg.org/spec/DMN/20211108/MODEL/ |
| 1.5 | https://www.omg.org/spec/DMN/20230324/MODEL/ |
All fixtures default to DMN 1.5 unless the path or fixture content targets a specific prior version.
Contributing
Before adding fixtures, read AUDIT.md (fixture authoring rules section) and COVERAGE.md (what's already covered). Run pnpm build after any addition — the build must pass before a fixture is considered complete.
See CONTRIBUTING.md for the full workflow.
License
MIT
