Instruction file imported from tikoci/lsp-routeros-ts (
.github/instructions/testing.instructions.md). Copyright stays with the author.
Testing Guidelines
Test vs. Script vs. Scratch
The user's expectation is that client/src/ and server/src/ hold runtime code only — what ships in dist/. Three other buckets:
| Kind | Lives in | Example | Notes |
|---|---|---|---|
| Test | tests/server/ or tests/client/ |
tokens.test.ts |
Deterministic, runs under bun test. Anchor tests preferred. |
| Tooling script | scripts/ |
capture-snapshots.ts, profile-timing.ts, assess-dataset.ts, import-discourse-*.ts |
Run by hand or from CI; not shipped. |
| Experiment | .scratch/ (gitignored) |
routeros2.js, parse-il-probe.ts |
For one-off probes and throwaway validation. If it survives, promote it into a script or test. |
Do not add new tests or one-off scripts to server/src/ or client/src/.
Test Runner & Config
bun test tests/runs all tests (~3866 tests, <600ms without CHR).bunfig.tomlpreloadstests/test-preload.tsto silencelog.*output- Test files live in
tests/server/(server tests) andtests/client/(client tests) server/tsconfig.jsonandclient/tsconfig.jsoncompile only runtime code — tests have their owntests/tsconfig.json
Test Tiers
Unit tests (no dependencies)
tokens.test.ts—HighlightTokensparsing,tokenRanges,atPosition,regexTokenrouteros.test.ts—replaceNonAscii,normalizeErrorshared.test.ts— settings CRUD,getConnectionUrl,useConnectionUrl/clearConnectionUrlcontroller.test.ts—getServerCapabilities,hasCapability,shortid
Model tests (mocked HTTP)
model.test.ts—LspDocument.diagnostics()with mockedRouterRestClient.default.inspectHighlight- Covers: clean scripts, error tokens, unchecked region warnings, 32KB truncation
Snapshot tests (offline, uses .highlight files)
snapshot.test.ts— parses.rsc.highlightfiles alongside.rscscripts- Validates: token count matches char count, all types known, contiguous ranges, regexToken length
- Generate snapshots:
bun run scripts/capture-snapshots.ts(requires live CHR)
Client tests (no VSCode dependency)
watchdog-errors.test.ts— teststoErrorInfoandgetTextFromErrorfromwatchdog-errors.ts- These are pure functions extracted from
watchdog.tsto avoid VSCode import issues
Smoke tests (tests/smoke/stdio-smoke.ts)
- Goal: per deployment context, verify the LSP boots and responds to
initialize,textDocument/didOpen, semantic tokens, diagnostics, and completion end-to-end against a mocked RouterOS HTTP server. Catches transport/packaging regressions unit tests cannot. - Currently covers two stdio contexts: the Node-bundled
server/dist/server.jsand the standalonebun build --compilebinary. Run viabun run test:smoke(also runs inci.yamlon every push/PR and inbuild.yamlbefore release). - Uses a mock RouterOS over
http://127.0.0.1:<random-port>— smoke tests must not depend on a live CHR. Integration tests cover the CHR side. - Path resolution: file/spawn paths are resolved against the module-derived repo root (
fileURLToPath(new URL('.', import.meta.url))→../..), not the runtime cwd. If you add new targets or path checks, follow the same pattern so the harness can be invoked from any cwd. - TS types around
Buffer.concat: keep theUint8Array.from()wrapping. Under TS 5.7+ with current@types/node,Buffer.alloc(0)isBuffer<ArrayBuffer>whileBuffer.concat(Buffer[])returnsBuffer<ArrayBufferLike>— the assignment fails strict typecheck. The wrapping is a deliberate coercion, not dead code; CodeQL has flagged it as "unnecessary" before. - Remaining contexts to add: web bundle (via a Worker shim), npm-installed bin (
npx --yes @tikoci/routeroslsp --stdiofrom a clean node_modules). Seedeployment.instructions.md.
Integration tests (requires live CHR)
integration.test.ts— connects to CHR, sends alltest-data/**/*.rscthroughinspectHighlight- Auto-skips when CHR is unreachable
- Override CHR address:
ROUTEROS_TEST_URL=http://... bun test tests/server/integration.test.ts - In CI, prefer
tikoci/quickchrto boot a version-pinned CHR. quickchr is the designated QEMU expert project in the tikoci stack; it handles version selection, boot-wait loops, and port forwarding so that a GitHub Actions runner gets a predictable/console/inspect. See 📋 "QEMU CHR in CI" in BACKLOG.
Assessment & Profiling Tools (not tests — standalone scripts)
Dataset assessment (assess-dataset.ts)
- Runs all
test-data/**/*.rscfiles through CHR highlight API - Reports: timing, token quality, unknown types, error tokens, CLI prompts, data signals
- Usage:
bun run scripts/assess-dataset.ts [--json] [--concurrency=N] - JSON output:
test-data/assessment-results.json(gitignored)
Corpus datastore (build-corpus-db.ts)
- Rebuilds the checked-in SQLite corpus database at
test-data/corpus.sqlitefrom committed.rscfiles and sidecars - Imports script metadata, FTS text,
.rsc.highlightsnapshots, versioned highlight summaries, parseIL.parseil/.parseil.meta.jsoncaptures, artifact provenance, and forward-compatible tables for inspect-shapes/completion-tricks research - Usage:
bun run corpus:dborbun run scripts/build-corpus-db.ts [--db test-data/corpus.sqlite] - Because
corpus.sqliteis checked in, rebuilds must be deterministic from committed inputs; prefer corpus fingerprints and source capture timestamps over wall-clock import timestamps - Future research harnesses should write normalized rows to this DB first; export JSON/Markdown only when a reviewer needs a textual diff or docs need a curated excerpt
Performance profiling (profile-timing.ts)
- Tests size→time relationship by truncating scripts at progressive sizes (128B → 32KB)
- Includes synthetic controls (pure comments, simple commands, complex scripting, mixed paths)
- Also profiles real files (eworm/global-functions.rsc, oversize-32k.rsc, complex/piano.rsc)
- Usage:
bun run scripts/profile-timing.ts - Key finding: superlinear (quadratic) scaling; sharp inflection at ~28KB; scripting syntax costs ~3× more than comments
Test Strategy: Anchor Tests
- Tests verify current behavior, not necessarily "correct" behavior
- They catch regressions and document what the code actually does
- Makes it safer for LLMs to refactor code by establishing behavioral baselines
Test Data (test-data/, committed)
*.rsc— RouterOS script samples at various complexity levels*.rsc.highlight— saved CHR highlight responses for offline snapshot testsedge-cases/— targeted: empty, comment-only, single-command, oversize-32k, unicode-heavyeworm/— scripts from eworm-de/routeros-scripts (GPL, see ATTRIBUTION.md)forum/— scripts from forum.mikrotik.com*.tikbook— TikBook notebook format filescorpus.sqlite— checked-in SQLite datastore rebuilt byscripts/build-corpus-db.ts; excluded from VSIX because.vscodeignoreexcludes alltest-data/
Adding New Tests
- Place tests in
tests/server/(for server code) ortests/client/(for client code), mirroring the source tree - For new
.rsctest scripts: add totest-data/, runscripts/capture-snapshots.tsto generate.highlight - After adding scripts or research sidecars, run
bun run corpus:dbsotest-data/corpus.sqlitereflects the corpus. - For mocking
RouterRestClient: patch the singleton instance property, not the prototype (arrow-function methods are instance-level) - If you're tempted to write a script to "try something out" — it belongs in
.scratch/, not next to a.tssource file. Promote toscripts/when it's worth keeping.