Skip to content

Testing

Ductwork provides custom RSpec matchers and some helpers to simplify pipeline testing.

Use this matcher to verify that a single pipeline was triggered. It requires a block and takes one pipeline class as its argument.

expect do
MyService.call
end.to have_triggered_pipeline(MyPipeline)

You can assert that a pipeline was triggered a specific number of times:

expect do
MyService.call
end.to have_triggered_pipeline(MyPipeline).exactly(3).times

Use this matcher to verify that multiple pipelines were triggered. It takes multiple pipeline classes as arguments.

expect do
MyService.call
end.to have_triggered_pipelines(MyPipelineA, MyPipelineB, MyPipelineC)

Note: This matcher does not support count expectations, as specifying counts for multiple pipelines would be ambiguous.


Because of Reasons, Ductwork steps are built in a non-standard way. This means you need to use the following to instantiate steps:

let(:step) { FetchUserData.build_for_execution(pipeline_id, attrs) }

The first argument is the pipeline ID to which the step belongs followed by any input arguments.


To make creating pipeline objects easier you can use the pipeline_for helper which only takes a class name:

let(:pipeline) { pipeline_for(EnrichAllUsersDataPipeline) }

Likewise there is a helper to make setting global state easier:

before do
set_pipeline_context(pipeline, user_id: 1)
end

For convenience, you can use string or symbol keys to set context state.


It is useful to know if your pipeline and step classes are valid before pushing to production. There is a top-level Ductwork.validate! method that will ensure your step classes have the correct methods and arity and that each pipeline is calling transitions correctly. It is recommended to call this method in a test:

RSpec.describe "Ductwork" do
specify "valid pipelines and steps" do
Ductwork.validate!
end
end