Skip to content

Scripting in Flows

Declarative extractions and assertions (body path / header / status, equals/contains/exists/…) cover most flows. When you need something they can't express — a computed value, a hash, a loop over the response body, a multi-field check — drop down to JavaScript using the same Scripting engine and pro.* API the rest of Probe uses.

A Script node runs a JS snippet through Probe's embedded QuickJS engine — the same sandbox, limits, and pro global documented in Scripting and the API Reference. It has one in-port and one out-port, and its inspector is a plain code editor.

Reading upstream data: every upstream node's outputs are flattened into the script's variable scope as <nodeName>.<key>, alongside the active environment/globals and (inside a loop body) the current loop scope. Read them with pro.variables.get(...):

const token = pro.variables.get('login.outputs.token');
const cartTotal = pro.variables.get('getCart.body.total');

Publishing outputs: anything you set with pro.environment.set(...) becomes one of the node's outputs, readable downstream exactly like a declared extraction — {{scriptNode.outputs.key}}:

pro.environment.set('signature', pro.crypto.sha256(token + ':' + Date.now()));

console.log (and warn/error/table/etc.) calls inside the script show up as console logs in that node's row of the run report — handy for debugging without adding extra extractions just to inspect a value.

On a Request node, each assertion can be either Value (the declarative source/operator/expected form) or Script. A script assertion runs in test mode against that node's response, after any declarative assertions on the same node, using pro.test/pro.expect:

pro.test('id is a positive integer', () => {
const id = pro.response.json().data.id;
pro.expect(id).to.be.above(0);
});

A failing pro.test fails the node the same way a failing declarative assertion does — downstream nodes that depend on it are skipped.

Script nodes and script assertions need the app's embedded JavaScript engine, which only exists inside the running Probe UI. When a flow runs headlessly — the probe_flow CLI, or a bare dart VM — there is no engine wired up, so a script node fails with script engine unavailable and script assertions produce a failed outcome with the same message, rather than throwing or silently passing. See Running in CI for what that means for flows you plan to automate.