All Projects β†’ nepalez β†’ fixturama

nepalez / fixturama

Licence: MIT license
Collection of helpers for dealing with fixtures in RSpec

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to fixturama

full-stack-web-developer
πŸ”₯ Roadmap to become a Full Stack Web Developer. What? Why? How?
Stars: ✭ 76 (+130.3%)
Mutual labels:  rspec
solr wrapper
Wrap your tests with Solr 5+
Stars: ✭ 22 (-33.33%)
Mutual labels:  rspec
database plumber
Find leaky ActiveRecord models in your RSpec tests
Stars: ✭ 13 (-60.61%)
Mutual labels:  rspec
opal-rspec
Opal + RSpec = β™₯️
Stars: ✭ 57 (+72.73%)
Mutual labels:  rspec
j8spec
Library that allows tests written in Java to follow the BDD style introduced by RSpec and Jasmine.
Stars: ✭ 45 (+36.36%)
Mutual labels:  rspec
rspec-tap-formatters
TAP Producer for RSpec-3
Stars: ✭ 20 (-39.39%)
Mutual labels:  rspec
Apitome
Apitome: /iˈpitΙ™mΔ“/ An API documentation presentation layer for RSpec API Documentation output.
Stars: ✭ 244 (+639.39%)
Mutual labels:  rspec
ginkgo4j
A Java BDD Testing Framework (based on RSpec and Ginkgo)
Stars: ✭ 25 (-24.24%)
Mutual labels:  rspec
serverspec-extended-types
A set of extended types for ServerSpec 2.x
Stars: ✭ 28 (-15.15%)
Mutual labels:  rspec
mache
A library for writing cleaner and more expressive acceptance tests using page objects.
Stars: ✭ 40 (+21.21%)
Mutual labels:  rspec
ruby-dns-mock
DNS mock server written on πŸ’Ž Ruby. Mimic any DNS records for your test environment with fake DNS server.
Stars: ✭ 50 (+51.52%)
Mutual labels:  rspec
capybara-chromedriver-logger
Enables console.log/error/info output from Javascript feature specs running with Chromedriver
Stars: ✭ 54 (+63.64%)
Mutual labels:  rspec
saharspec
RSpec sugar to DRY your specs
Stars: ✭ 58 (+75.76%)
Mutual labels:  rspec
rspec html reporter
Rspec custom formatter to produce beautiful reports from rspec
Stars: ✭ 32 (-3.03%)
Mutual labels:  rspec
givens
Easy test setup without side effects.
Stars: ✭ 22 (-33.33%)
Mutual labels:  rspec
capybara-chrome
Chrome driver for Capybara using Chrome's remote debugging protocol
Stars: ✭ 27 (-18.18%)
Mutual labels:  rspec
r spec-clone.rb
A minimalist RSpec clone with all the essentials.
Stars: ✭ 38 (+15.15%)
Mutual labels:  rspec
wisper-rspec
RSpec matchers and stubbing for Wisper
Stars: ✭ 59 (+78.79%)
Mutual labels:  rspec
bdd
Given/When/Then/And/But output to RSpec and Minitest
Stars: ✭ 33 (+0%)
Mutual labels:  rspec
turbo tests
Run RSpec tests on multiple cores. Like parallel_tests but with incremental summarized output. Originally extracted from the Discourse and Rubygems source code.
Stars: ✭ 81 (+145.45%)
Mutual labels:  rspec

Fixturama

Collection of helpers for dealing with fixtures in RSpec

Read the post about the library on dev.to.

Sponsored by Evil Martians

Gem Version Build Status

Installation

gem "fixturama"

Configuration

On Rails add offsets to id sequences of database tables.

# spec/rails_helper.rb
RSpec.configure do |config|
  config.before(:suite) { Fixturama.start_ids_from 1_000_000 }
end

Now when you hardcode ids in fixtures (under 1_000_000), they won't conflict with authomatically created ones.

Usage

# spec/spec_helper.rb
require "fixturama/rspec"

The gem defines 3 helpers (support ERB bindings):

  • load_fixture(path, **opts) to load data from a fixture, and deserialize YAML and JSON
  • seed_fixture(path_to_yaml, **opts) to prepare database using the FactoryBot
  • stub_fixture(path_to_yaml, **opts) to stub some classes

Loading

# spec/models/user/_spec.rb
RSpec.describe "GraphQL mutation 'deleteProfile'" do
  subject { Schema.execute(mutation).to_h }

  before do
    seed_fixture("#{__dir__}/database.yml", profile_id: 42)
    stub_fixture("#{__dir__}/stubs.yml",    profile_id: 42)
  end

  let(:mutation) { load_fixture "#{__dir__}/mutation.graphql", profile_id: 42 }
  let(:result)   { load_fixture "#{__dir__}/result.yaml" }

  it { is_expected.to eq result }

  it "deletes the profile" do
    expect { subject }.to change { Profile.find_by(id: 42) }.to nil
  end

  it "sends a notification" do
    expect(Notifier)
      .to receive_message_chain(:create)
      .with("profileDeleted", 42)

    subject
  end
end

Notice, that since the v0.0.6 the gem also supports binding any ruby object, not only strings, booleans and numbers:

# ./data.yml
---
account: <%= user %>
# Bind activerecord model
subject { load_fixture "#{__dir__}/data.yml", user: user }

let(:user) { FactoryBot.create :user }

# The same object will be returned
it { is_expected.to eq account: user }

The object must be named in the options you send to the load_fixture, stub_fixture, or seed_fixture helpers.

This feature can also be useful to produce a "partially defined" fixtures with RSpec argument matchers:

subject { load_fixture "#{__dir__}/data.yml", user: kind_of(ActiveRecord::Base) }

Since the v0.5.0 we support another way to serialize PORO objects in fixtures. Just wrap them to the object() method:

---
:account: <%= object(user) %>

This time you don't need sending objects explicitly.

RSpec.describe "example" do
    subject { load_fixture "#{__dir__}/data.yml" }
    
    let(:user) { FactoryBot.create(:user) }
    
    # The same object will be returned
    it { is_expected.to eq(account: user) }
end

Under the hood we use Marshal.dump and Marshal.restore to serialize and deserialize the object back.

Notice, that deserialization creates a new instance of the object which is not equivalent to the source (user in the example above)! In most cases this is enough. For example, you can provide matchers like:

---
number: <%= object(be_positive) %>

The loaded object would contain { "number" => be_positive }.

Seeding

The seed (seed_fixture) file should be a YAML/JSON with opinionated parameters, namely:

  • type for the name of the FactoryBot factory
  • traits for the factory traits
  • params for parameters of the factory
# ./database.yml
#
# This is the same as
# `create_list :profile, 1, :active, id: profile_id`
---
- type: profile
  traits:
    - active
  params:
    id: <%= profile_id %>

Use the count: 2 key to create more objects at once.

Stubbing

The gem supports stubbing message chains, constants and http requests with the following keys.

For message chains:

  • class for stubbed class
  • chain for messages chain
  • arguments (optional) for specific arguments
  • actions for an array of actions for consecutive invocations of the chain with keys
    • return for a value to be returned
    • raise for an exception to be risen
    • repeate for a number of invocations with this action

For constants:

  • const for stubbed constant
  • value for a value of the constant

For environment variables:

  • env for the name of a variable value for a value of the variable

For http requests:

  • url or uri for the URI of the request (treats values like /.../ as regular expressions)
  • method for the specific http-method (like get or post)
  • body for the request body (treats values like /.../ as regular expressions)
  • headers for the request headers
  • query for the request query
  • basic_auth for the user and password of basic authentication
  • response or responses for consecutively envoked responses with keys:
    • status
    • body
    • headers
    • repeate for the number of times this response should be returned before switching to the next one
# ./stubs.yml
#
# The first invocation acts like
#
# allow(Notifier)
#   .to receive_message_chain(:create)
#   .with(:profileDeleted, 42)
#   .and_return true
#
# then it will act like
#
# allow(Notifier)
#   .to receive_message_chain(:create)
#   .with(:profileDeleted, 42)
#   .and_raise ActiveRecord::RecordNotFound
#
---
- class: Notifier
  chain:
    - create
  arguments:
    - :profileDeleted
    - <%= profile_id %>
  actions:
    - return: true
      repeate: 1 # this is the default value
    - raise: ActiveRecord::RecordNotFound
      arguments:
        - "Profile with id: 1 not found" # for error message

# Here we stubbing a constant
- const: NOTIFIER_TIMEOUT_SEC
  value: 10

# This is a stub for ENV['DEFAULT_EMAIL']
- env: DEFAULT_EMAIL
  value: [email protected]

# Examples for stubbing HTTP
- uri: /example.com/foo/ # regexp!
  method: delete
  basic_auth:
    user: foo
    password: bar
  responses:
    - status: 200 # for the first call
      repeate: 1   # this is the default value, but you can set another one
    - status: 404 # for any other call

- uri: htpps://example.com/foo # exact string!
  method: delete
  responses:
    - status: 401
mutation {
  deleteProfile(
    input: {
      id: "<%= profile_id %>"
    }
  ) {
    success
    errors {
      message
      fields
    }
  }
}
# ./result.yaml
---
data:
  deleteProfile:
    success: true
    errors: []

With these helpers all the concrete settings can be extracted to fixtures.

I find it especially helpful when I need to check different edge cases. Instead of polluting a specification with various parameters, I create the sub-folder with "input" and "output" fixtures for every case.

Looking at the spec I can easily figure out the "structure" of expectation, while looking at fixtures I can check the concrete corner cases.

Single Source of Changes

If you will, you can list all stubs and seeds at the one single file like

# ./changes.yml
---
- type: user
  params:
    id: 1
    name: Andrew

- const: DEFAULT_USER_ID
  value: 1

This fixture can be applied via call_fixture method just like we did above with seed_fixture and stub_fixture:

before { call_fixture "#{__dir__}/changes.yml" }

In fact, since the v0.2.0 all those methods are just the aliases of the call_fixture.

License

The gem is available as open source under the terms of the MIT License.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].