Skip to main content

Testing and Debugging Lua

The script editor runs your code against a sample without opening a port, consuming a real message, or sending anything to a destination. Use it before you start a node.

Run Test or Debug?

Run TestDebug
ButtonBlue Run TestGrey Debug, bug icon
BreakpointsIgnoredHonoured — execution pauses
ExecutionRuns to completionPauses and steps
Variables shownFinal locals of mainLocals of the paused frame
Call stackNot shownFull stack, frames selectable

Reach for Run Test first. It answers "does this parse, and what did it produce?" in one click. Switch to Debug when you need to know why a value is what it is.


Create samples first

Both modes run against a sample, so you need at least one.

  1. Open the Samples panel in the Scripting tab.
  2. Add a sample and paste the content your node would actually receive.

What a sample contains depends on the node type:

Node typeSample content
Source HTTPA complete raw HTTP request: request line, headers, blank line, body
Source LLPAn HL7 v2 message
Transform CustomThe message the upstream node produces

A Source HTTP sample looks like this — the blank line before the body is required:

POST /intake HTTP/1.1
Host: 127.0.0.1:9001
Content-Type: application/json

{"patientId":"TEST-1001","status":"active"}

Samples persist with the node, so they travel with the interface and are available to whoever maintains it next.

:::caution Use synthetic data Samples are stored with the project and are visible to anyone who can open the node. Use clearly fake identifiers — TEST000001, TEST^PATIENT, 19700101 — never real patient data. :::


Run Test

  1. Select a sample from the toolbar dropdown.
  2. Click Run Test.

The Debug panel shows every local variable as it stood at the end of main, plus anything your script printed.

Use it to confirm:

  • The script compiles.
  • Parsing produced the tree you expected.
  • Field mappings landed in the right places.
  • Your print output shows the path the script took.

Debug

  1. Click the editor gutter, left of the line numbers, to place breakpoints. Any open file works — main.lua or a module it requires.
  2. Select a sample.
  3. Click Debug.

Execution starts at main and pauses at the first breakpoint. From there:

ControlDoes
ContinueRun to the next breakpoint, or to the end
Step OverNext line in the current function
Step IntoFirst line of the function being called
Step OutRun until the current function returns
StopEnd the session immediately

The Call Stack lists the active frames, such as mapPID @ mapping.lua:16. Click a frame to inspect its variables; the editor jumps to that file and line. Step Into switches files automatically.

Variables always reflect the paused frame, not the end of main. That is the point: it is how you catch a value that is correct at the end but wrong in the middle.

Reading the variables tree

  • Branches are collapsed by default. Expand what you need.
  • Hide empty is on by default and prunes branches with no values — useful with HL7, where most of a schema is unpopulated.
  • Message trees show schema names: segments as PID, fields as [5] Name, down to the leaf value.

Turn Hide empty off when you are checking that a field really is empty rather than simply mis-navigated.


Nothing leaves a test

In both modes, linkiir.flow.push is forced into non-live mode. It validates your arguments and returns a placeholder message ID, but writes nothing. You cannot accidentally produce a real message from the editor.

This is worth knowing when reading test output: a push that "succeeded" in Run Test confirms the call is well-formed, not that delivery works. Verify delivery by starting the node.

:::warning Outbound calls are real Only queue output is contained. linkiir.link.web.post, linkiir.link.mail.send, and linkiir.store calls execute for real during a test.

Point them at test endpoints while developing, or pass live = false to the linkiir.link calls that accept it. :::


IntelliSense does not run your script

Completion, hover, and signature help come from the API definitions, your schema, and the text in the buffer. Typing never executes anything and never reads sample values or live data.

What it gives you:

TypeGet
linkiir.Sub-modules, then their functions
Msg. after linkiir.data.extractSegment names from the schema, with field documentation
Msg:Node methods
req. after linkiir.link.web.requestmethod, path, headers, body, and the rest
Inside fn{ … }Parameter hints

Runtime values appear only in the Debug panel. They are never fed back into completion.


A test set worth keeping

Test more than the happy path. Keep a sample for each:

SampleCatches
Normal messageThe baseline works
Missing required fieldUnhandled nil
Optional segment absentNavigation assuming a segment exists
Repeating field with several repeatsCode reading only the first repeat
Unsupported message typeWhether you filter or crash
Malformed inputParse failure handling
Largest expected messageSize and performance surprises
Unusual charactersEncoding assumptions

The missing-field and absent-segment samples earn their keep fastest. Most production script failures are an unhandled nil from a field that was always present in development.


When a test passes but the node fails

SymptomLikely cause
Node goes to ERRORED on startCompile error in a file you did not test, or a missing require
Works in test, fails on real trafficThe real message differs from your sample. Capture one from the logs and add it as a sample.
Test push succeeds, nothing arrives downstreamNothing is connected after the node. Check the workflow.
Outbound call works in test, fails when runningCredentials or network reachability differ for the service account

For a message that already went through a running node, open its record in log search and copy the payload into a new sample. Reproducing with the exact payload beats guessing.


Next