Skip to content

ActiveFixtures provides the way how to populate the server state (DB, sessions) as an application user but not as programmer.

License

Notifications You must be signed in to change notification settings

Anadea/active-fixtures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ActiveFixtures

Version

ActiveFixtures provides the way how to populate the server state (DB, sessions) as an application user but not as programmer.

Why?

The correct question is why we write the tests at all?. Or even better - what does the green line means?.

Typical legacy code contains a tons of tests in isolation aka Unit Tests. Mocks, stubs, factories & terrible traits, fakers etc etc. Many smart things, so called best practices, a lot of efforts and time spent to write all of these.

And, after all - application just can't run due to the simple misspelling in routes.rb.

So, what is a really valuable reason to write the tests?

We working on the project for somebody personal. We creating the web application for web users, we write the new cool library for other programmers. The primary goal of automatic tests is to be sure that our code works right like the target user expects.

Test web application as web user plays with it. Test the public methods of your library just like other programmer will use them. Test web service endpoints just like the third-party applications will call them.

Nobody interested how exactly working the private methods in Product class. Even more, nobody interested to know that class Product exists, it mapped to some database table etc.

Single thing is matter - how the application's user thinking about your application, which entities he understand, how he affects to such entities.

In general case, tests in isolation are at least useless, at max - hurtful. Lets write acceptance tests instead!

Requirements

Currently works with Poltergeist and PostgreSQL.

Getting started

Add to your Gemfile:

group :development, :test do
  gem 'active-fixtures'
end

Add to your rails_helper.rb:

require 'active-fixtures/rspec'

Add to your .gitignore:

spec/fixtures/active

Remove Database Cleaners from your project, ActiveFixtures will take care about database cleanup in additional.

Usage

Active factory definition

Lets add the active factory in spec/active_fixtures/user.rb:

class AFUser < ActiveFixtures::Resource
  attribute :login, type: String, default: '[email protected]'
  attribute :password, type: String, default: 'p@ssw0rd'

  def self.create_initial(attrs = {})
    new(attrs).tap { |user|
      Rake::Task['user:create'].invoke(user.login, user.password)
      Rake::Task['user:create'].reenable
    }
  end

  def self.create(attrs = {})
    new(attrs).tap { |user|
      af_session(:admin) do
        click_on 'Admins'

        click_on 'Invite'
        fill_in 'Email', with: user.login
        click_on 'Send an invitation'
      end

      af_session do
        open_email(user.login)

        current_email.click_on 'Accept invitation'
        fill_in 'Password', with: user.password
        fill_in 'Password confirmation', with: user.password
        click_on 'Set my password'
        assert_text 'Your password was set successfully. You are now signed in.'
      end
    }
  end

  def sign_in
    visit '/'
    fill_in 'Email', with: login
    fill_in 'Password', with: password
    click_on 'Sign in'
    assert_text 'Signed in successfully.'
  end

end

Implement the resource factory just like the application user will do - capybara steps, rake tasks invocation, API calls etc.

Any methods available in it rspec context will be available in the factory (for example open_email helper from capybara-email gem).

ActiveFixtures::Resource includes the ActiveAttr::Model, feel free to use any it's features.

af_session helper called without parameter will provide the clean capybara session on each call. Use it in factory to avoid the influence to rspec's example default session.

af_session with parameter is a bit tricky, lets recall it later.

Now you can use factory in your tests:

describe 'Users' do
  let(:admin) { AFUser.create_initial }

  it 'should pass' do
    admin.sing_in
  end
end

Fixtures definition

Lets define active fixture in spec/active_fixtures/_fixtures.rb:

ActiveFixtures.populate(:default) do
  resource(:admin) { AFUser.create_initial }
  session(:admin) { AFUser[:admin].sign_in }
  resource(:invited_admin) { AFUser.create(login: '[email protected]') }
end

:default fixture will be loaded before each rspec example. You can play with resources like that:

it 'should pass' do
  AFUser[:invited_admin].sign_in
end

Active sessions

Once you defined the named session in factory, you can use it by af_session helper:

it 'should pass' do
  af_session(:admin) do
    # already logged as admin
  end

  # some code
  af_session(:admin) do
    # second and any further `af_session` call within the same example
    # will drop the session to the state reached right after the session initialization
    # - same current URL, same cookies. This way you don't need to keep in mind
    # what you did with named session before, but can expect the same session state each time.
  end

  af_session do
    # always clean session, with blank current URL
  end
end

Active time

Lets stop to use the magic time moments for time freezing and traveling. Use the named time moments:

ActiveFixtures.populate(:default) do
  time(:today) { Time.new(1983, 1, 2, 3, 4) }
  time(:yesterday) { af_time(:today) - 1.day }
  time(:week_ago) { af_time(:today) - 7.days }

  resource(:invited_admin) {
    af_time(:week_ago) {
      AFUser.create(login: '[email protected]')
    }
  }
end

In the tests:

describe 'Users' do
  around { |example|
    af_time(:today) { example.run }
  }

  it 'should pass' do; end
end

How it works

ActiveFixtures work fairly, but effectively.

Fixture will be populated on the first it's usage, by genuine application's user actions. For the next example it will be loaded from cache - no sense to do the same work again.

In case when you affecting the fixture creation process (making changes in fixtures, related application functionality, DB schema etc), you need to clean the fixtures cache manually before the tests run:

  $ rake active_fixtures:clean

License

MIT License. Copyright (c) 2016 Sergey Tokarenko

About

ActiveFixtures provides the way how to populate the server state (DB, sessions) as an application user but not as programmer.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages