Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
# Pretend that ActiveRecord::Rails is defined and this doesn't blow up
# with `config.use_active_record = false`.
# Trick the other spec that checks that ActiveRecord is
# *not* defined by wrapping it in RSpec::Rails namespace
# so that it's reachable from RSpec::Rails::FixtureSupport.
# NOTE: this has to be defined before requiring `rails_helper`.
module RSpec
module Rails
module ActiveRecord
module TestFixtures
end
end
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to remain, see the documentation comment, it exists to test that stuff doesn't happen when the flag is set to false and the module is defined, this is because even though we can exclude active record, it often still exists due to dependencies, but hasn't been configured...


require 'rails_helper'

RSpec.describe 'Example App', :use_fixtures, type: :model do
RSpec.describe 'Example App', type: :model do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It you revert this spec change, will the old spec still work?

If it won’t, why?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that using :use_fixtures changes anything at all.
Please look at this code:

config.include RSpec::Rails::FixtureSupport, :use_fixtures
# We'll need to create a deprecated module in order to properly report to
# gems / projects which are relying on this being loaded globally.
#
# See rspec/rspec-rails#1355 for history
#
# @deprecated Include `RSpec::Rails::RailsExampleGroup` or
# `RSpec::Rails::FixtureSupport` directly instead
config.include RSpec::Rails::FixtureSupport

It includes RSpec::Rails::FixtureSupport unconditionally, even if :use_fixtures is not provided.
So the purpose of this meta-tag is a little vague.

Thanks for the suggestion. I'll revert this change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global config.include with metadata is a conditional include as far as I recall

it "does not set up fixtures" do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means “we don’t set up fixtures even if AR is loaded and there’s a metadata tag”, right? I hat changed?

expect(defined?(fixtures)).not_to be
end
Expand Down
2 changes: 1 addition & 1 deletion features/.nav
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
- GettingStarted.md (Start from scratch)
- Generators.md (Generators)
- Transactions.md
- ActiveRecord.md
- directory_structure.feature
- backtrace_filtering.feature
- model_specs:
Expand Down
181 changes: 181 additions & 0 deletions features/ActiveRecord.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Active Record
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer it if you reverted this change, if you want to add to the documentation in another PR or in the original file thats fine, but this is really hard to review what if anything you've changed


`rspec-rails` by default injects [ActiveSupport::TestCase](https://api.rubyonrails.org/classes/ActiveSupport/TestCase.html) and exposes some of the settings to RSpec configuration.
Furthermore it adds special hooks into `before` and `after` which are essential for [Active Record Fixtures](https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html) and keeping the database in a clean state.

It provides the `fixtures` class method in the rspec context to tell Rails which fixtures to prepare before each example.

In addition to being available in the database, the fixture’s data may also be accessed by using a special dynamic method, which has the same name as the model.

```ruby
RSpec.configure do |config|
config.fixture_paths = [
Rails.root.join('spec/fixtures')
]
end

RSpec.describe Thing, type: :model do
fixtures :things

it "fixture method defined" do
expect(things(:one)).to eq(Thing.find_by(name: "one"))
end
end
```

More details on how to use fixtures are in the [Rails documentation](https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html#class-ActiveRecord::FixtureSet-label-Using+Fixtures+in+Test+Cases)

## Transactions

When you run `rails generate rspec:install`, the `spec/rails_helper.rb` file
includes the following configuration:

```ruby
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
```

The name of this setting is a bit misleading. What it really means in Rails
is "run every test method within a transaction." In the context of rspec-rails,
it means "run every example within a transaction."

The idea is to start each example with a clean database, create whatever data
is necessary for that example, and then remove that data by simply rolling back
the transaction at the end of the example.

For how this affects methods exposing transaction visibility see:
https://guides.rubyonrails.org/testing.html#transactions

### Data created in `before` are rolled back

Any data you create in a `before` hook will be rolled back at the end of
the example. This is a good thing because it means that each example is
isolated from state that would otherwise be left around by the examples that
already ran. For example:

```ruby
describe Widget do
before do
@widget = Widget.create
end

it "does something" do
expect(@widget).to do_something
end

it "does something else" do
expect(@widget).to do_something_else
end
end
```

The `@widget` is recreated in each of the two examples above, so each example
has a different object, _and_ the underlying data is rolled back so the data
backing the `@widget` in each example is new.

### Data created in `before(:context)` are _not_ rolled back

`before(:context)` hooks are invoked before the transaction is opened. You can use
this to speed things up by creating data once before any example in a group is
run, however, this introduces a number of complications and you should only do
this if you have a firm grasp of the implications. Here are a couple of
guidelines:

1. Be sure to clean up any data in an `after(:context)` hook:

```ruby
before(:context) do
@widget = Widget.create!
end

after(:context) do
@widget.destroy
end
```

If you don't do that, you'll leave data lying around that will eventually
interfere with other examples.

2. Reload the object in a `before` hook.

```ruby
before(:context) do
@widget = Widget.create!
end
before do
@widget.reload
end
```

Even though database updates in each example will be rolled back, the
object won't _know_ about those rollbacks so the object and its backing
data can easily get out of sync.
## Configuration
### Disabling Active Record support
If you prefer to manage the data yourself, or using another tool like
[database_cleaner](https://github.com/bmabey/database_cleaner) to do it for you,
simply tell RSpec to tell Rails not to manage fixtures and cleaning database.
```ruby
RSpec.configure do |config|
config.use_active_record = false # is true by default
end
```
### Fixtures path
The generator will provide the default path to the fixture, but it is possible to change it:
```ruby
RSpec.configure do |config|
config.fixture_paths = Rails.root.join('some/dir') # Rails.root.join('spec/fixtures') by default
end
```
### Instantiated fixtures
If you want to have your fixtures available as an instance variable in the example, you could use `use_instantiated_fixtures` option:
```ruby
RSpec.configure do |config|
config.use_instantiated_fixtures = true # false, by default
end
RSpec.describe Thing, type: :model do
fixtures :things
it "instantiates fixtures" do
expect(@things["one"]).to eq(@one)
end
end
```
### Global fixtures
Sometimes it is required to have some fixture in each example, and it's possible to do this via `global_fixtures` setting:

```ruby
RSpec.configure do |config|
config.global_fixtures = [:things]
end
RSpec.describe Thing, type: :model do
it "inserts fixture" do
expect(things(:one)).to be_a(Thing)
end
end
```

### Disabling transactions

If your database does not support transactions, but you still want to use Rails fixtures, it is possible to disable transactions explicitly:

```ruby
RSpec.configure do |config|
config.use_transactional_fixtures = false
end
```
99 changes: 0 additions & 99 deletions features/Transactions.md

This file was deleted.

7 changes: 3 additions & 4 deletions lib/generators/rspec/install/templates/spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,11 @@
Rails.root.join('spec/fixtures')
]
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
# If you'd prefer not to run each of your examples within a transaction,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the mention of AR here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, originally this statement is not quite correct, specifically the If you're not using ActiveRecord part.
The use_transactional_fixtures setting doesn't make any sense without the ActiveRecord, as it's a part of its configuration in specs. But you are right, it needs to mention the setting is related to the ActiveRecord.
Thanks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer it if this was reverted, you should delete this setting if you're not using ActiveRecord, thats why it's written that way.

# remove the following line or assign false instead of true.
config.use_transactional_fixtures = true
# You can uncomment this line to turn off ActiveRecord support entirely.
# You can uncomment this line to turn off ActiveRecord support entirely
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this change please.

# config.use_active_record = false
<% else -%>
Expand Down
Loading