|
|
|
# Guidelines for writing a spec file
|
|
|
|
|
|
|
|
## Model spec
|
|
|
|
## View spec
|
|
|
|
|
|
|
|
### Helpers
|
|
|
|
|
|
|
|
- _matcher_ `have_link_for_each_item` checks that each item in the given collection has a link to the expected URL (defined in [`spec/support/integration_spec_helper.rb`](https://github.com/af83/stif-boiv/blob/f83df1a0b39b2af7d3088db9c98365c4088bc021/spec/support/integration_spec_helper.rb#L34-L49)).
|
|
|
|
- _matcher_ `have_the_right_number_of_links` checks that each item in the given collection has the expected number of links (defined in [`spec/support/integration_spec_helper.rb`](https://github.com/af83/stif-boiv/blob/f83df1a0b39b2af7d3088db9c98365c4088bc021/spec/support/integration_spec_helper.rb#L51-L63)).
|
|
|
|
- `with_permission PERMISSION_NAME do ...` a context manager that enables view testing with the given permission activated (defined in [`spec/support/integration_spec_helper.rb`](https://github.com/af83/stif-boiv/blob/f83df1a0b39b2af7d3088db9c98365c4088bc021/spec/support/integration_spec_helper.rb#L17-L22)).
|
|
|
|
- `build_paginated_collection(:factory_name, decorator_class, factory_options, context: decorator_context)` creates a collection of decorated objects using factories, with a result similar to what would be created in the controller (defined in [`spec/support/integration_spec_helper.rb`](https://github.com/af83/stif-boiv/blob/f83df1a0b39b2af7d3088db9c98365c4088bc021/spec/support/integration_spec_helper.rb#L7-L14)).
|
|
|
|
|
|
|
|
### Tips
|
|
|
|
|
|
|
|
- to simulate a nested route (for example, `/parents/:parent_id/objects`):
|
|
|
|
|
|
|
|
controller.request.path_parameters[:parent_id] = parent.id
|
|
|
|
|
|
|
|
### Example
|
|
|
|
|
|
|
|
Here's an example `index` view spec, where we want to verify:
|
|
|
|
|
|
|
|
- the number of rows in the table
|
|
|
|
- that each row has a link (accounting for permissions)
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe "/objects/index", type: :view do
|
|
|
|
let(:parent) { assign :parent, create(:parent) }
|
|
|
|
let(:context) {
|
|
|
|
{
|
|
|
|
foo: bar,
|
|
|
|
bar: baz
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let(:objects) do
|
|
|
|
assign(
|
|
|
|
:objects,
|
|
|
|
build_paginated_collection(
|
|
|
|
:object,
|
|
|
|
ObjectDecorator,
|
|
|
|
parent: parent,
|
|
|
|
context: context
|
|
|
|
)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
before(:each) do
|
|
|
|
allow(view).to receive(:collection).and_return(objects)
|
|
|
|
allow(view).to receive(:current_referential).and_return(parent)
|
|
|
|
controller.request.path_parameters[:parent_id] = parent.id
|
|
|
|
render
|
|
|
|
end
|
|
|
|
|
|
|
|
common_items = ->{
|
|
|
|
it do
|
|
|
|
should have_link_for_each_item(
|
|
|
|
objects,
|
|
|
|
"show",
|
|
|
|
->(object) { view.parent_object_path(parent, object) }
|
|
|
|
)
|
|
|
|
end
|
|
|
|
it do
|
|
|
|
should have_link_for_each_item(
|
|
|
|
objects,
|
|
|
|
"foo",
|
|
|
|
->(object) { view.parent_foo_path(parent, object.foo) }
|
|
|
|
)
|
|
|
|
end
|
|
|
|
it do
|
|
|
|
should have_link_for_each_item(
|
|
|
|
objects,
|
|
|
|
"bar",
|
|
|
|
->(object) { view.parent_bar_path(parent, object.bar) }
|
|
|
|
)
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
common_items.call()
|
|
|
|
it { should have_the_right_number_of_links(objects, 3) }
|
|
|
|
|
|
|
|
with_permission "objects.activate" do
|
|
|
|
common_items.call()
|
|
|
|
|
|
|
|
it do
|
|
|
|
should have_link_for_each_item(
|
|
|
|
objects,
|
|
|
|
"activate",
|
|
|
|
->(object) { view.activate_parent_object_path(parent, object) }
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it { should have_the_right_number_of_links(objects, 4) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
## Controller spec
|
|
|
|
|
|
|
|
### Helpers
|
|
|
|
|
|
|
|
- `login_user` to create a `User` and authenticate it in the session
|
|
|
|
- `with_permission PERMISSION do ...` to add the given permission to the current user in the context of the block
|
|
|
|
|
|
|
|
### Example
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
RSpec.describe ObjectController, type: :controller do
|
|
|
|
login_user
|
|
|
|
|
|
|
|
let(:parent) { create :parent }
|
|
|
|
let(:object) { create :object, parent: parent }
|
|
|
|
|
|
|
|
describe 'PUT deactivate' do
|
|
|
|
let(:request){ put :deactivate, id: object.id, parent_id: parent.id }
|
|
|
|
|
|
|
|
it 'should redirect to 403' do
|
|
|
|
expect(request).to redirect_to "/403"
|
|
|
|
end
|
|
|
|
|
|
|
|
with_permission "foo.bar" do
|
|
|
|
it 'returns HTTP success' do
|
|
|
|
expect(request).to redirect_to [parent, object]
|
|
|
|
expect(object.reload).to be_deactivated
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'PUT activate' do
|
|
|
|
let(:request){ put :activate, id: object.id, parent_id: parent.id }
|
|
|
|
|
|
|
|
before(:each) do
|
|
|
|
object.deactivate!
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should redirect to 403' do
|
|
|
|
expect(request).to redirect_to "/403"
|
|
|
|
end
|
|
|
|
|
|
|
|
with_permission "objects.change_status" do
|
|
|
|
it 'returns HTTP success' do
|
|
|
|
expect(request).to redirect_to [parent, object]
|
|
|
|
expect(object.reload).to be_activated
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
``` |