Skip to content

Testing

Much of what a flow does happens out of sight - it calls a service, reshapes a payload, runs a rule, and moves on. Testing is how you confirm a flow does what you intended before you rely on it. You run it against sample data and check, block by block, that each step received the right input and produced the right result. When a step is wrong, testing points you straight at which block failed and why, so you can fix it before a live run hits it.

This page follows one example flow that reviews an incoming order. It fetches the order from a partner's API, trims it down, reattaches the tidied lines, finds the most expensive item, and decides whether a manager needs to approve it - several different kinds of block, wired together. A small payment flow then shows how to test an External Callback, which waits for a call from outside.

The example flow in the editor: Start, then Get Order (an HTTP Request), Extract Properties From Product List and Set Products back to Order (two Transform Data steps), Get Top Item Total (Custom Cloud Code), and the Condition Is Top Item Total Greater than 1000?, whose No branch runs Auto Approve and whose Yes branch runs Send for Approval via Slack.

The Test Monitor

You test a flow in the Flow Editor: you run blocks right on the canvas. The Test Monitor panel across the bottom is where you enter the flow's test data and read the results. It has three tabs:

  • Flow Data - the sample input you give the flow to stand in for the data it would receive for real.
  • Block Results - what each block took in and gave back. Pick the block's tab to see its result.
  • Logging - each block starting and finishing, and any error it hit.

The Flow Editor on the example flow with Get Order selected: the canvas with both branches, the block's settings on the right with the Test Panel at the top holding run block and manage block result, and the Test Monitor docked across the bottom with its Flow Data, Block Results and Logging tabs, showing Get Order's Input and Output. The Slack block carries a red 1 because it has no connection yet.

You test on a draft version. A version that is LIVE opens on the View tab: its blocks have no run icons and there is no Test Monitor. Its toolbar's Run Instance starts a real instance, which counts as an execution. To test a LIVE flow step by step, clone the version and test the copy - see Change a flow that is already live.

The toolbar of a LIVE version, Cart Summary Version 1: Pause, Stop, Schedule, Clone, Export and a lightning icon with its tooltip Run Instance, beside the Live status, above the View, Dashboard, Performance, Instances, SLA Goals, Logs and Version Admin tabs.

Give the flow its test data

In a real run, the call that starts an instance of this flow sends the id of the cart to fetch as its Initial Data. In a test nothing sends it, so you provide it yourself on the Flow Data tab: add a row, name it, and give it a value. The example needs a cartId.

A value that looks like a number, true/false or JSON has an A icon beside it, here and in the other test dialogs on this page. Green means the value is kept as text; dark means it is kept as the number, boolean or JSON you typed. Click the icon to switch, and match what the flow will receive for real.

The Flow Data tab with a single row: property name cartId, value 123.

From here on, any block that reads Initial Data → cartId sees 123 when you test it.

Objects and lists. When the flow receives an object or a list - an order's items, say - edit the value as JSON: click the JSON Editor icon at the right of its cell, change the value in the dialog, and click APPLY CHANGES. The dialog shows the value formatted, so a long list is easy to read and check, and the Copy as JSON icon beside the property name copies the whole value, formatted, to paste elsewhere. If an edit leaves the JSON invalid, the value is saved as plain text and its A icon disappears: a block that expects a list then gets a string. In the table, a long value is cut off with …; click into the cell to see all of it.

The JSON Editor dialog for an items value: the pointer on the copy icon beside the title shows the tooltip Copy as JSON; below, a list of two order lines - Desk Lamp, quantity 1, price 450, and USB-C Cable, quantity 2, price 9.99 - shown as formatted JSON with line numbers, above CANCEL and APPLY CHANGES.

Run a block and read its result

Hover a block on the canvas to reveal a red play icon (tooltip: Run in test mode); the Test Panel at the top of the block's settings carries a matching run block button. Either one runs that single block against the current test data. The run is real: an action block performs its action, so Get Order really calls the partner's API.

The Get Order block on the canvas, hovered: a red play icon with its tooltip "Run in test mode", and a lightning icon beside it.

The settings of the Get Top Item Total block: the Custom Cloud Code heading with Delete, then the Test Panel holding two buttons, run block and manage block result, above the Name field.

A run shows its outcome on the Block Results tab: the block's Input - the values it resolved - on the left, and its Output - what it produced - on the right. Run each block after the blocks that feed it, because a block reads the results they produced.

Fetching the order. Get Order is an HTTP Request block. It calls the partner's cart address, https://dummyjson.com/carts/ followed by Initial Data → cartId, and its Output is the whole order the API returned - a nested object with a products array and the order totals.

Block Results for Get Order: the Input shows the resolved URL; the Output shows the fetched order as JSON, with a products array and totals.

Trimming it down. Extract Properties From Product List is a Transform Data block that keeps the few fields that matter. Its Input is the order's product list and the four property names to keep; its Output is a clean list of { title, quantity, price, total }.

Block Results for Extract Properties From Product List: the Input is the List of products and four Property Name rows - title, quantity, price, total; the Output is the trimmed four-field lines.

Putting it back together. That trim returns only the array of lines, without the order around it. Set Products back to Order is a second Transform Data step that writes the array onto the order's products property, so the order keeps its totals and carries the tidy line list forward. You can see it in the result: the Input is the order plus the trimmed array, and the Output is the order again, its products now the four-field lines.

Block Results for Set Products back to Order: the Input is the order and the trimmed array; the Output is the order with its products replaced by the tidy lines, totals intact.

Computing over it. Get Top Item Total, a Custom Cloud Code block, loops those lines to find the most expensive one. Its Input shows the arguments passed in and the code itself; its Output is what the code returned - { topItem, topItemTotal }.

Block Results for the Custom Cloud Code block: the code in the Input, and the returned topItem and topItemTotal in the Output.

Deciding. The Condition block, named Is Top Item Total Greater than 1000?, compares the most expensive item's total against a threshold. Its Input shows the two values - 74999.95 against 1000 - and its Output is the branch it takes, conditionResult: true.

Block Results for the condition: the Input compares 74999.95 to 1000; the Output is conditionResult true.

Change the cartId on the Flow Data tab and run the blocks again to send a different order through.

Edit an Output to test a case

The Output of each result on the Block Results tab is editable. Change a value there, and a later block that reads this block's result gets your version the next time you run it. That is how you test a case your sample data does not cover, without touching the flow or the data source.

For example, what happens to an order whose priciest line comes to exactly 1000? Open Get Top Item Total's result and change topItemTotal to 1000:

Block Results for Get Top Item Total (Custom Cloud Code) with its Output edited to topItem MotoGP CI.H1 and topItemTotal 1000, the Success badge beside it.

Run the Condition. It compares 1000 against 1000, which is not greater, so it takes the No branch:

Block Results for the Condition after the edit: the Input shows Value to Check 1000 and Value 1000; the Output is conditionResult false.

The edit is saved as you make it and is still there after a page reload, until the block runs again. It reaches only blocks that read this block's result; a block that reads the same data from somewhere else, such as a variable, does not see the edit.

Set a block's result without running it

Editing an Output needs a result to edit, so the block has to run first. Some blocks you cannot or should not run in a test:

  • a block that would send a real message or change real data
  • a block that needs a connection you have not set up yet - its run block stays disabled
  • a block whose earlier steps you have not built yet, or do not want to run again

manage block result, next to run block in the block's Test Panel, lets you type the result in instead.

In the example, the sample cart's priciest item is far above 1000, so the Condition always takes the Yes branch. To test the No branch, give Get Top Item Total a result by hand - a Desk Lamp at 450 - and run the Condition on its own. Nothing before it has to run, so Get Order never calls the partner's API:

The Manage Block Result dialog for Get Top Item Total (Custom Cloud Code): an empty Populate from Instance (optional) selector, the Form View / JSON Editor switch on Form View, and two Key / Value rows - topItemTotal 450 with a dark A icon beside the value, and topItem Desk Lamp - above Cancel and Save.

  • Add a row per property with the +. Turn the Form View / JSON Editor switch to JSON Editor to type or paste the whole value as JSON; while the JSON is not valid, SAVE stays disabled and the dialog reads Enter valid JSON to save.
  • Type 450, then click the A beside it so it turns dark: the Condition compares numbers against 1000.
  • The Populate from Instance selector (optional) fills the dialog from a real run of this version, which you can then edit. It lists runs from when a version was LIVE, so on a draft that has never been LIVE it stays empty, as it is here. For a block inside a loop, an Iteration picker chooses which pass to copy.
  • For a block whose result is a list, such as Extract Properties From Product List, Form View shows one Item row per entry: + adds an entry and the bin removes one.

The Manage Block Result dialog for Extract Properties From Product List in Form View: an Item list with a + above it and one row holding {"title":"Desk Lamp","quantity":1,"price":450,"total":450} with a bin icon on the left and the A and code icons on the right, above Cancel and Save.

SAVE records the value as the block's result, and every later block reads it as if the block had produced it. Run the Condition and it reads 450 against 1000 and returns conditionResult: false - the No branch:

Block Results for the Condition after the hand-set result: the Input shows Value to Check 450 and Value 1000; the Output is conditionResult false.

The saved result also gives the Expression Editor the block's fields to pick from, so you can wire later blocks to a block that has never run:

The Expression Editor's Block Data tab with Get Top Item Total (Custom Cloud Code) Result expanded: currency USD, topItem Desk Lamp and topItemTotal 450, the values saved by hand.

The value stays after a page reload, and Block Results always shows it as the block's Output. It is replaced when you save a new one, or when the block runs again. It is test data only - a real run of the flow still runs the block.

Run an instance from a block

Running a block tests one step. To run the rest of the flow from a chosen point - no stopping between blocks - use Run instance from this element, the lightning icon beside a block's play icon. The run starts at that block; the blocks before it do not run.

Using run instance from this element to run through the flow from a specific point.

It opens the Launch Flow Instance dialog. The dialog lists the Initial Data the flow reads and, for a block partway down the flow, the results of earlier blocks that the block reads, filled in from Block Results. Launched from the Condition, it offers Get Top Item Total's topItemTotal, here set to 2000:

The Launch Flow Instance dialog opened from the Condition: a Previous Instance (Optional) selector, the Form View / JSON Editor switch, an Initial Data table with cartId 123, an Elements Results table, a Get Top Item Total (Custom Cloud Code) Result table with topItemTotal 2000, each value with a dark A icon, and GET URL and cURL tabs with the note that a request URL is only available for flows with LIVE status, above Cancel and Launch.

Change any value, or pick a previous instance in the Previous Instance selector to reuse the data from an earlier run - including a real instance from when a version was LIVE, which is a quick way to reproduce a case that actually happened. The selector lists this version's runs, newest first. Each one shows its instance name, if an Assign Instance Name block gave it one, and its start time, with the execution ID underneath. Type part of a name into Search by instance name to find a run, for example the order it handled. The line under the list says how many runs it shows, such as Showing last 1 of 1 instance(s) of this version. Runs older than the log history of your workspace billing plan are not listed. LAUNCH starts the run. Its results appear on the Block Results and Logging tabs, and the canvas marks each block that ran.

A value you type into one of these rows is sent as the type it looks like: 123 arrives as a number, and the A beside it stays dark. The JSON Editor view shows exactly what will be sent.

Once this version is LIVE, the dialog also offers a GET URL and a cURL command that start an instance over HTTP. Every instance you start with LAUNCH counts as one execution, on a draft version as well as on a LIVE one - see What testing costs.

Find the block that failed

When a block cannot do its job, its Output on the Block Results tab shows an Error badge and the message. Give the example a cart that does not exist - cartId 99999 on the Flow Data tab - and run Get Order:

Block Results for Get Order after a failed run: the Input shows the URL https://dummyjson.com/carts/99999; the Output carries an Error badge and the message Cart with id '99999' not found.

The Logging tab shows each block starting and finishing. For the block that failed it adds the error and the line Block has no error handler. Execution will be terminated. - in a real run, that error stops the run unless a Handle Error block catches it - see Handling Errors.

The Logging tab: Show logging for set to All, a search box, the Wrap messages, Shorten IDs and Basic timestamps checkboxes, CLEAR LOG AREA and a pop-out icon, above lines for Get Top Item Total and the Condition starting and completing, then Get Order starting, an error line with the message Cart with id '99999' not found, the line saying the block has no error handler and execution will be terminated, and a WARN line repeating the error.

Show logging for narrows the list to one block, the search box finds a line, and CLEAR LOG AREA empties the log before your next test. With Basic timestamps cleared, each line carries the full date and time zone.

Test an External Callback

This section uses a small payment flow whose first step is an External Callback. Running a callback on its own shows you exactly what a caller sends, and gives the next blocks real fields to pick - without the flow being LIVE.

Run the External Callback with its red play icon or run block. It does not finish at once: it waits for a call. While it waits, the icon turns into a spinner and the Test Panel button reads stop block:

The Payment Received flow with the External Callback selected: a red spinner on the block where its play icon was, and the Test Panel at the top of its settings reading stop block beside manage block result, above the Callback URL field.

Copy the block's Callback URL. Open a terminal and enter the following command, replacing <Callback URL> with the URL you copied:

curl --request POST \
  --url "<Callback URL>" \
  --header "Content-Type: application/json" \
  --data '{
    "event": "payment.succeeded",
    "orderId": "ORD-9200",
    "amount": 2500,
    "currency": "USD"
  }'

The call is answered {"executionId": "test"} - a test run has no run id, so it gets this placeholder - and the request's data becomes the block's Output on the Block Results tab:

The Payment Received flow with the External Callback selected, and the Test Monitor's Block Results for it: the Input reads "The trigger has no input data", and the Output, marked Success, holds event payment.succeeded, orderId ORD-9200, amount 2500 and currency USD.

stop block ends the wait without a call; the button goes back to run block, and Block Results keeps whatever the last run produced. Outside a test, the Callback URL answers only while the flow is LIVE. While the block waits in a test run, a call to it reaches the block on the version you are building, and the Expression Editor lists the test call's fields for the blocks after the trigger. If you also captured a sample with Learning Mode, the test call's fields come first, and the learned sample is kept - see Waiting on an External System.

If another version of this flow is LIVE, the call reaches it too: it starts a real run of the LIVE version, the reply carries that run's id instead of test, and that run counts as an execution.

Run a LIVE callback flow without a caller

To check the LIVE version end to end without waiting for the payment provider, let the launch dialog make the call for it. On a LIVE version whose first block is an External Callback, Run Instance in the toolbar opens the Launch Flow Instance dialog with a Trigger the External Callback automatically switch. Turn it on and fill External Callback Data with what a caller would send, here amount 2500 and orderId ORD-9200.

The Launch Flow Instance dialog with Trigger the External Callback automatically switched on, its explanation below it, and under Configuration Data an External Callback Data table holding amount 2500 and orderId ORD-9200.

LAUNCH starts an instance and then calls its callback with that data, so the run goes on to the end instead of waiting at the callback. This is a real run of the LIVE version: it does everything that version does and counts as an execution. With the switch off, LAUNCH starts the instance and it waits until something calls the Callback URL. The switch works only when you click LAUNCH: the dialog's GET URL and cURL start the instance and nothing more, so it waits the same way.

What testing costs

Running blocks one at a time is free. run block in the Test Panel, or the play icon on a selected block, does not count against your monthly execution allowance, however often you use it. The exception is a SubFlow block: running it runs the whole subflow, and that counts as one execution.

Launching an instance counts as one execution, the same as a run started any other way. That covers Run Instance in the toolbar, which runs the whole flow, and the lightning icon on a block, which runs the flow from that block, on a draft version as well as on a LIVE one.

The Get Top Item Total block selected on the canvas, with its play icon and its lightning icon at the top right, and the lightning icon's tooltip: Run instance from this element.

A test call to an External Callback that also reaches a LIVE version starts a real run of that version, which counts too. Once the workspace has used its allowance, a launch from the editor is refused with the same Exceeded the limit of ... flow executions per billing period message as any other run, while run block keeps working. See Billing for what does and does not count.