excel

Docs › Reference

Conformance suite

476 language-neutral test cases for validate(rows, rules). A server port in another language must pass all of them.

The dist/conformance/ folder of the 82excel npm package (npm i 82excel, then node_modules/82excel/dist/conformance/) holds 476 language-neutral test cases for validate(rows, rules): rules, input rows, and the expected errors, warnings and cleaned rows, one JSON file each. The Node implementation (82excel) passes all of them. A port to another language must pass 100% of these files, unchanged, before it can claim the same results as the browser check().

Case format

{
  "name": "types/date-dots",
  "why": "research §3 Korean dates: 2024.01.05",
  "rules": { "columns": [{ "key": "v", "type": "date" }] },
  "rows": [{ "v": "2024.01.05" }],
  "expect": {
    "ok": true,
    "errors": [],
    "warnings": [],
    "rows": [{ "$row": 2, "v": "2024-01-05" }]
  }
}
  • rules are 0.2 rules JSON passed as is; rows are input rows keyed by column key (they may carry $row). Inputs are plain JSON only.
  • expect.errors and expect.warnings are lists of { row, key?, code }; row-level issues (BLANK_ROW, ROWS_TOO_FEW, ROWS_TOO_MANY) have no key.
  • expect.rows are the cleaned result rows with $row; expect.masked gives the masked raw/value in personal data cases; expect.throws is the message text an invalid/ case must throw.
  • About a third of the cases carry a why naming the spec section, research note or ruling behind them. Expected values were written from the spec, never pasted from engine output.

Groups

FolderCovers
types/Every column type: valid, invalid, canonical re-input, Excel error values
rules/Column rules, failOn
rowrules/when / compare / uniqueWith
blank/rows.blank
injection/formulaInjection
pii/Detection, forbid/allow, masking
normalize/The normalize switches
idempotency/Cleaned rows fed back
edge/Row numbers, boundaries, rows.min/rows.max
invalid/Rules that must be rejected

Comparison rules

  • Call validate(case.rows, case.rules) with no options.
  • errors / warnings: compare the set of (row, key, code); order does not matter.
  • ok must be equal; rows must be strictly deep-equal, in order (no missing or extra keys; numbers compare as numbers).
  • throws: the message starts with 82excel: and contains the given text verbatim. That text is part of the contract.
  • Messages, rule, col, header and summary are not compared. Issues with a key also carry header (the column's header from the rules), which is not compared.

Behaviour the suite pins down

Where the spec is silent, the suite decides: result rows (a cell failing its type keeps its raw input, other failures keep the cleaned value), row numbers ($row when it is a positive integer, else index + headerRow + 1), emptiness, cleanup order, per-cell check order, issue keys, row counts (rows.min/rows.max count result rows, reported at the header row with no key), failOn, Excel error values (#REF! … are CELL_TYPE in every column), formula injection, personal data candidates and mask shapes, patterns (u flag, test() semantics — re.search in Python), Korean phone shapes and date ranges. The full list is in the README.

Out of scope

Anything that needs the file is tested in the Node package instead: file-level checks (password, encoding, hidden content, merged cells, macros, sheet choice, column mapping, totals rows), warnings about stored cells (PRECISION_LOSS, SCIENTIFIC_NOTATION), real formula cells, Excel date serials and the 1904 system, message text and locales, and JS row hooks.

Running it

Node (reference implementation):

pnpm --filter 82excel exec vitest run test/conformance.test.ts

Other languages: walk cases/**/*.json, apply the comparison rules above and report each case by name. What the server does with it is in Server second pass.