Purpose
The purpose of this gem is to provide a way to export the results of rspec tests to disk. In this way, a controller test can output the response body of the request, and then a front-end test can read that file in order to have predictable and maintainable front-end fixtures.
This gem currently only applies to the rspec testing framework.
Usage
The gem is require'd in the rspec loading script, and will take effect from there by using the "fixture" option. For example, the following test would record response.body to spec/fixtures/widgets/index.json"
describe "GET index" do
it "is successful", rcv: {fixture: "spec/fixtures/widgets/index.json"} do
get :index
expect(response).to be_success
end
end
The test itself does not need to do anything different, it is all in configuration.
If the file already exists, and the new content is not identical, the test will fail with a message indicating that this happened. This will prevent surprises from happening, and can be turned off in a configuration variable.
Lifecycle
The result of the exportable variable is captured at the end of the test, after everything else has run. Because this is an
outer after(:each)
, it will run after all of the other after
blocks in the suite. This means you can't use the output of
the file in an after block (not that you should need to). See the spec suite here to understand how you could use the output of
the file in the spec suite.
Configuration Options
The following options are available to override, as well as important default values:
config.exportable_proc = Proc.new { JSON.parse(response.body) }
config.compare_with # Deep ignoring comparison by default
config.codec = Codecs::PrettyJson.new
config.ignore_keys = []
config.base_path = nil
config.fail_on_changed_output = true
exportable_proc
, compare_with
must implement .call
. For exportable_proc
, the result will be written to disk
and should be a String. For compare_with
, the proc should return true when existing and new are considered equal.
exportable_proc
assumes JSON response by default, but could be override to allow for other types of responses.
codec
must implement export_with(hash)
and decode_with(str)
. There is a PrettyJson and Yaml codec included in this gem,
and PrettyJson is the default as it can be directly consumed by javascript.
What about fields that change everytime I run the specs?
There is an option called ignore_keys
which will deep ignore keys that you don't want to cause spec change. For instance,
the following hashes would not trigger a change with ignore_keys = [:id]
{
id: 1,
deep: {
id: 2,
name: "Steve"
}
}
{
id: "DIFF",
deep: {
"id" => "DIFF,
name: "Steve"
}
}
but if the name changed from "Steve", then a change would be triggered.
If you want more configuration, you can override compare_with
. For instance, here is a configuration to shallowly ignore
id, created_at, updated_at
in a Rails app:
RSpecRcv.configure do |config|
config.configure_rspec_metadata!
filters = [:id, :created_at, :updated_at]
config.compare_with = lambda do |existing, new|
existing = ActiveSupport::HashWithIndifferentAccess.new(existing)
new = ActiveSupport::HashWithIndifferentAccess.new(JSON.parse(new))
existing.except(*filters) != new.except(*filters)
end
end
What happens when fields change that shouldn't?
You will get a diff of the output to your console. Here is an example: