Flow Testing

Test your flows.
No org required.

Record-triggered flows, autolaunched flows, subflows - Nimbus executes them locally alongside your Apex code. Same order of execution, same data access, no deployment. The first local Apex test runner that tests flows.

The problem with testing against an org

Most Salesforce orgs have hundreds of flows. They handle record updates, call Apex actions, enforce business rules, and trigger on DML operations right alongside triggers. But until now, there was no way to run them locally — so you deployed first and hoped for the best.

The result: you write Apex tests, deploy to a scratch org, and watch them fail because a record-triggered flow modified the record your test was asserting on. Or a test that passes in isolation fails in the full org because an autolaunched flow was never accounted for.

Nimbus parses your flow metadata from source - the same .flow-meta.xml files in your SFDX project - and executes them as part of the same test run. No org. No deployment. Flows fire when DML fires, just like in production.

bash
# Your project structure
force-app/main/default/
├── classes/
│   ├── AccountService.cls
│   └── AccountServiceTest.cls
└── flows/
    ├── Account_Before_Save.flow-meta.xml
    └── Onboarding_Autolaunched.flow-meta.xml

# nimbus test reads both.
# Flows fire when DML fires.
# No separate setup required.

nimbus test "AccountServiceTest.*"

# ✓ AccountServiceTest.testCreateAccount  18ms
#   (Account_Before_Save flow fired, set Industry)
# ✓ AccountServiceTest.testOnboarding     24ms
#   (Onboarding_Autolaunched ran, returned status)

Supported flow types

Record-Triggered Flows

Fire automatically on insert, update, or delete - before or after save. Nimbus fires them exactly as Salesforce would: in the correct order of execution, alongside triggers, with full access to record data.

eg. Set Industry on Account insert. Stamp LastModifiedBy__c. Cascade field values to related records.
Autolaunched Flows

Called programmatically from Apex, scheduled jobs, or other flows. Test them by calling Flow.Interview directly - pass input variables, run, assert on output variables.

eg. Calculate a quote. Send a notification. Invoke a complex decision tree from Apex code.
Subflows

Flows that call other flows. Nimbus resolves the full call graph locally - subflows execute in-process, with the same isolation as the parent flow.

eg. An order flow that calls a pricing subflow and a fulfillment subflow.
Flow Formulas & Decisions

Formula fields evaluated inside flow decision elements are computed locally. Nimbus evaluates the same formula syntax Salesforce uses - no approximation.

eg. IF({!Account.AnnualRevenue} > 1000000, "Enterprise", "SMB")

Testing a record-triggered flow

A before-save flow sets Industry to "Technology" when an Account's BillingCountry is "DE". Without flow execution, your test inserts the Account and sees Industry = null. With Nimbus, the flow fires.

No changes to your test class. No annotations. No configuration. If the flow is in your project and it triggers on the DML operation you're performing, it fires.

apex
@isTest
static void testIndustryDefaultFlow() {
    // Flow: Account_Before_Save
    // Condition: BillingCountry = 'DE'
    // Action: Set Industry = 'Technology'

    Account acc = new Account(
        Name = 'Acme GmbH',
        BillingCountry = 'DE'
    );
    insert acc;

    // The flow fired during insert.
    // No separate invocation needed.
    Account result = [SELECT Industry FROM Account WHERE Id = :acc.Id];
    System.assertEquals('Technology', result.Industry);
}

Testing an autolaunched flow

Autolaunched flows are invoked with Flow.Interview - either directly in your test or from Apex code under test. Pass input variables using the map constructor, call start(), then read output variables back.

Nimbus resolves the flow from your project's flows/ directory, executes all its elements locally - decisions, assignments, loops, subflow calls - and returns the output variables you defined.

apex
@isTest
static void testOnboardingFlow() {
    // Flow: Onboarding_Autolaunched
    // Input:  AccountId (Id), Plan (String)
    // Output: Status (String), NextStepDate (Date)

    Account acc = new Account(Name = 'Acme');
    insert acc;

    Map<String, Object> inputs = new Map<String, Object>{
        'AccountId' => acc.Id,
        'Plan' => 'Enterprise'
    };

    Flow.Interview flow = Flow.Interview.createInterview(
        'Onboarding_Autolaunched', inputs
    );
    flow.start();

    String status = (String) flow.getVariableValue('Status');
    Date nextStep = (Date) flow.getVariableValue('NextStepDate');

    System.assertEquals('Active', status);
    System.assertNotEquals(null, nextStep);
}

Order of execution

Nimbus follows Salesforce's documented order of execution. When you insert a record, here's what fires - in order:

1Before-save record-triggered flowsyour flows/
2Before triggersyour triggers/
3Validation rulesschema validation
4Record saved to databaseembedded PostgreSQL
5After triggersyour triggers/
6After-save record-triggered flowsyour flows/

Test flows. No org required.

Record-triggered flows, autolaunched flows, subflows - all executing locally, in the correct order, against your seeded test data.