rao-shoulda_matchers 0.0.13.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5f0735c773f33792ea5d48359b15bc611216be4e457ec09897332e282745faaa
4
+ data.tar.gz: f18fcc17da38fc31211bfec30e1058d574a2854fbabeeb250ef9460af62c5b4e
5
+ SHA512:
6
+ metadata.gz: 30fd2cd6f4a930f22599a00b25576825918d240edbdd146f2112f4f02269500fec3033acaf8bf9c4f2b897b3cd743fcf2e1bdb65055bf35206b9fe22e31ec91c
7
+ data.tar.gz: 5444accb9e0bbe8fe4c95b704eab293ef1a29ff07ede9dbefeaf58891e7decc6473b4bec3e97004ed894e1b76b6c62e36013f20acc28622e3e960389f83d55c1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Roberto Vasquez Angel
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Rao Shoulda Matchers'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rails/dummy/tasks'
@@ -0,0 +1,55 @@
1
+ module Rao
2
+ module ShouldaMatchers
3
+ # This will generate specs for create, read, update, delete and list.
4
+ #
5
+ # Example:
6
+ #
7
+ # rails g rao:shoulda_matchers:resources_controller --uri /de/backend/uploads
8
+ # create spec/features/de/backend/uploads_feature_spec.rb
9
+ #
10
+ # If your resource class does not match the last part of your url (i.e.
11
+ # /de/posts would guess the resource class to Post) you can specify the resource
12
+ # name like this:
13
+ #
14
+ # RESOURCE_CLASS=Blog::Post rails g rails:add_ons:resources_controller_spec --uri /de/posts
15
+ # create spec/features/de/posts_feature_spec.rb
16
+ #
17
+ class ResourcesControllerGenerator < Rails::Generators::Base
18
+ desc 'Generates CRUDL specs for REST resources'
19
+
20
+ source_root File.expand_path('../templates', __FILE__)
21
+
22
+ class_option :uri, type: :string, required: true
23
+ class_option :resource_class, type: :string
24
+
25
+ def uri
26
+ @uri ||= options['uri']
27
+ end
28
+
29
+ def edit_form_dom_selector
30
+ ".edit_#{resource_class.demodulize.underscore}"
31
+ end
32
+
33
+ def new_form_dom_selector
34
+ "#new_#{resource_class.demodulize.underscore}"
35
+ end
36
+
37
+ def resource_class
38
+ # @resource_class ||= ENV.fetch('RESOURCE_CLASS') { @uri.split('/').last.camelize.singularize }
39
+ @resource_class ||= options['resource_class'] ||= @uri.split('/').last.camelize.singularize
40
+ end
41
+
42
+ def factory_name
43
+ underscored_resource_class
44
+ end
45
+
46
+ def underscored_resource_class
47
+ @undescored_resource_class ||= resource_class.underscore.gsub('/', '_')
48
+ end
49
+
50
+ def generate_spec
51
+ template 'resources_controller_spec.rb', "spec/features#{uri}_feature_spec.rb"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,53 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe '<%= uri %>', type: :feature do
4
+ let(:resource_class) { <%= resource_class %> }
5
+ let(:resource) { create(:<%= factory_name %>) }
6
+ let(:resources) { create_list(:<%= factory_name %>, 3) }
7
+
8
+ # List
9
+ it { resources; expect(subject).to implement_index_action(self) }
10
+
11
+ # Create
12
+ it {
13
+ expect(subject).to implement_create_action(self)
14
+ .for(resource_class)
15
+ .within_form('<%= new_form_dom_selector %>') {
16
+ # fill the needed form inputs via capybara here
17
+ #
18
+ # Example:
19
+ #
20
+ # select 'de', from: 'slider[locale]'
21
+ # fill_in 'slider[name]', with: 'My first slider'
22
+ # check 'slider[auto_start]'
23
+ # fill_in 'slider[interval]', with: '3'
24
+ }
25
+ .increasing{ <%= resource_class %>.count }.by(1)
26
+ }
27
+
28
+ # Read
29
+ it { expect(subject).to implement_show_action(self).for(resource) }
30
+
31
+ # Update
32
+ it {
33
+ expect(subject).to implement_update_action(self)
34
+ .for(resource)
35
+ .within_form('<%= edit_form_dom_selector %>') {
36
+ # fill the needed form inputs via capybara here
37
+ #
38
+ # Example:
39
+ #
40
+ # fill_in 'slider[name]', with: 'New name'
41
+ }
42
+ .updating
43
+ .from(resource.attributes)
44
+ .to({ }) # Example: .to({ 'name' => 'New name' })
45
+ }
46
+
47
+ # Delete
48
+ it {
49
+ expect(subject).to implement_delete_action(self)
50
+ .for(resource)
51
+ .reducing{ resource_class.count }.by(1)
52
+ }
53
+ end
@@ -0,0 +1,161 @@
1
+ module Rao
2
+ module Shoulda
3
+ module Matchers
4
+ # Example:
5
+ #
6
+ # RSpec.describe '/posts', type: :feature do
7
+ # it {
8
+ # expect(subject).to implement_create_action(self)
9
+ # .for(Post)
10
+ # .within_form('#new_post') {
11
+ # fill_in 'post[title]', with: 'My first post'
12
+ # }
13
+ # .increasing{ |resource_class| resource_class.count }.by(1)
14
+ # }
15
+ # end
16
+ #
17
+ # The newly created resource is found by calling @resource_class.last.
18
+ # If you need to change this you can call #finding_created_resource_with.
19
+ #
20
+ # Example:
21
+ #
22
+ # RSpec.describe '/posts', type: :feature do
23
+ # it {
24
+ # expect(subject).to implement_create_action(self)
25
+ # .for(resource_class)
26
+ # .within_form('#new_user') {
27
+ # # fill the needed form inputs via capybara here
28
+ # #
29
+ # # Example:
30
+ # #
31
+ # # select 'de', from: 'slider[locale]'
32
+ # # fill_in 'slider[name]', with: 'My first slider'
33
+ # # check 'slider[auto_start]'
34
+ # # fill_in 'slider[interval]', with: '3'
35
+ # fill_in 'user[email]', with: 'jane.doe@local.domain'
36
+ # fill_in 'user[password]', with: 'password'
37
+ # fill_in 'user[password_confirmation]', with: 'password'
38
+ # }
39
+ # .finding_created_resource_with{ Ecm::UserArea::User.order(created_at: :desc).first }
40
+ # .increasing{ Ecm::UserArea::User.count }.by(1)
41
+ # }
42
+ # end
43
+ #
44
+ def implement_create_action(spec)
45
+ ImplementCreateActionMatcher.new(spec)
46
+ end
47
+
48
+ class ImplementCreateActionMatcher
49
+ include RSpec::Matchers
50
+
51
+ def initialize(spec)
52
+ @spec = spec
53
+ end
54
+
55
+ def id(id)
56
+ @id = id
57
+ self
58
+ end
59
+
60
+ def increasing(&block)
61
+ @block = block
62
+ self
63
+ end
64
+
65
+ def by(expected_increase)
66
+ @expected_increase = expected_increase
67
+ self
68
+ end
69
+
70
+ # Resource class that will be created
71
+ def for(resource_class)
72
+ @resource_class = resource_class
73
+ self
74
+ end
75
+
76
+ # Specifies the form css id to fill to create the resource.
77
+ def within_form(id, &block)
78
+ @form_id = id
79
+ @form_block = block
80
+ self
81
+ end
82
+
83
+ def finding_created_resource_with(&block)
84
+ @created_resource_finder_block = block
85
+ self
86
+ end
87
+
88
+ def matches?(base_path)
89
+ @base_path = @spec.class.name.split('::')[0..2].join('::').constantize.description
90
+ # @base_path = base_path
91
+ @new_path = "#{@base_path}/new"
92
+
93
+ @spec.visit(@new_path)
94
+
95
+ @before_count = @block.call(@resource_class)
96
+ @spec.within(@form_id) do
97
+ @form_block.call
98
+ @spec.find('input[name="commit"]').click
99
+ end
100
+ @after_count = @block.call(@resource_class)
101
+
102
+ has_correct_status_code && has_increased_resource_count && has_correct_current_path
103
+ end
104
+
105
+ def created_resource
106
+ @created_resource ||= @created_resource_finder_block.present? ? @created_resource_finder_block.call : @resource_class.last
107
+ end
108
+
109
+ def expected_path
110
+ @expected_path ||= "#{@base_path}/#{created_resource.to_param}"
111
+ end
112
+
113
+ def has_correct_status_code
114
+ begin
115
+ if @spec.status_code == 200
116
+ true
117
+ else
118
+ @error = "Wrong status code [#{@spec.status_code}] instead of [200]"
119
+ false
120
+ end
121
+ rescue Capybara::NotSupportedByDriverError => e
122
+ puts "[Warning] Skipping status code check as it is not supported by your driver [#{@spec.driver.instance_variable_get(:@name)}]."
123
+ return true
124
+ end
125
+ end
126
+
127
+ def has_increased_resource_count
128
+ if (@after_count - @before_count) == @expected_increase
129
+ true
130
+ else
131
+ @error = "Did not increase by expected [#{@expected_increase}] but by [#{@after_count - @before_count}]"
132
+ false
133
+ end
134
+ end
135
+
136
+ def has_correct_current_path
137
+ if @spec.current_path == expected_path
138
+ true
139
+ else
140
+ @error = "Wrong current path [#{@spec.current_path}] instead of [#{expected_path}]"
141
+ false
142
+ end
143
+ end
144
+
145
+ def failure_message
146
+ "Should expose create action on #{@new_path}. Error: #{@error}"
147
+ end
148
+
149
+ def failure_message_when_negated
150
+ "Should not expose create action on #{@new_path}. Error: #{@error}"
151
+ end
152
+
153
+ alias negative_failure_message failure_message_when_negated
154
+
155
+ def description
156
+ "expose create action on #{@new_path}"
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,115 @@
1
+ module Rao
2
+ module Shoulda
3
+ module Matchers
4
+ # Example:
5
+ #
6
+ # RSpec.describe '/posts', type: :feature do
7
+ # let(:resource_class) { Post }
8
+ # let(:resource) { create(:post) }
9
+ #
10
+ # it {
11
+ # expect(subject).to implement_delete_action(self)
12
+ # .for(resource)
13
+ # .reducing{ resource_class.count }.by(1)
14
+ # }
15
+ # end
16
+ #
17
+ def implement_delete_action(spec)
18
+ ImplementDeleteActionMatcher.new(spec)
19
+ end
20
+
21
+ class ImplementDeleteActionMatcher
22
+ include RSpec::Matchers
23
+
24
+ def initialize(spec)
25
+ @spec = spec
26
+ end
27
+
28
+ # Resource that will be deleted
29
+ def for(resource)
30
+ @resource = resource
31
+ self
32
+ end
33
+
34
+ def id
35
+ @resource.to_param
36
+ end
37
+
38
+ def reducing(&block)
39
+ @block = block
40
+ self
41
+ end
42
+
43
+ def by(expected_reduction)
44
+ @expected_reduction = expected_reduction
45
+ self
46
+ end
47
+
48
+ def matches?(base_path)
49
+ @base_path = @spec.class.name.split('::')[0..2].join('::').constantize.description
50
+ # @base_path = base_path
51
+ @expected_path = @base_path
52
+ @show_path = "#{@base_path}/#{id}"
53
+
54
+ @spec.visit(@show_path)
55
+
56
+ @before_delete_count = @block.call
57
+ @spec.find(delete_link_matcher).click
58
+ @after_delete_count = @block.call
59
+
60
+ has_correct_status_code && has_correct_current_path && has_reduced_resource_count
61
+ end
62
+
63
+ def has_correct_status_code
64
+ begin
65
+ if @spec.status_code == 200
66
+ true
67
+ else
68
+ @error = "Wrong status code [#{@spec.status_code}] instead of [200]"
69
+ false
70
+ end
71
+ rescue Capybara::NotSupportedByDriverError => e
72
+ puts "[Warning] Skipping status code check as it is not supported by your driver [#{@spec.driver.instance_variable_get(:@name)}]."
73
+ return true
74
+ end
75
+ end
76
+
77
+ def has_reduced_resource_count
78
+ if (@before_delete_count - @after_delete_count) == @expected_reduction
79
+ true
80
+ else
81
+ @error = "Did not reduce by expected [#{@expected_reduction}] but by [#{@before_delete_count - @after_delete_count}]"
82
+ false
83
+ end
84
+ end
85
+
86
+ def has_correct_current_path
87
+ if @spec.current_path == @expected_path
88
+ true
89
+ else
90
+ @error = "Wrong current path [#{@spec.current_path}] instead of [#{@expected_path}]"
91
+ false
92
+ end
93
+ end
94
+
95
+ def failure_message
96
+ "Should expose delete action on #{@base_path} [#{delete_link_matcher}], clicking on #{delete_link_matcher}. Error: #{@error}"
97
+ end
98
+
99
+ def failure_message_when_negated
100
+ "Should not expose delete action on #{@base_path} [#{delete_link_matcher}], clicking on #{delete_link_matcher}. Error: #{@error}"
101
+ end
102
+
103
+ alias negative_failure_message failure_message_when_negated
104
+
105
+ def description
106
+ "expose delete action on #{@base_path} [#{delete_link_matcher}]"
107
+ end
108
+
109
+ def delete_link_matcher
110
+ 'a[data-method="delete"]'
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,70 @@
1
+ module Rao
2
+ module Shoulda
3
+ module Matchers
4
+ # Example:
5
+ #
6
+ # RSpec.describe '/posts', type: :feature do
7
+ # before(:each) { create_list(:post, 3) }
8
+ #
9
+ # it { expect(subject).to implement_index_action(self) }
10
+ # end
11
+ #
12
+ def implement_index_action(spec)
13
+ ImplementIndexActionMatcher.new(spec)
14
+ end
15
+
16
+ class ImplementIndexActionMatcher
17
+ include RSpec::Matchers
18
+
19
+ def initialize(spec)
20
+ @spec = spec
21
+ end
22
+
23
+ def matches?(base_path)
24
+ @base_path = @spec.class.name.split('::')[0..2].join('::').constantize.description
25
+ # @base_path = base_path
26
+
27
+ @spec.visit(@base_path)
28
+ has_correct_status_code && has_correct_current_path
29
+ end
30
+
31
+ def has_correct_status_code
32
+ begin
33
+ if @spec.status_code == 200
34
+ true
35
+ else
36
+ @error = "Wrong status code [#{@spec.status_code}] instead of [200]"
37
+ false
38
+ end
39
+ rescue Capybara::NotSupportedByDriverError => e
40
+ puts "[Warning] Skipping status code check as it is not supported by your driver [#{@spec.driver.instance_variable_get(:@name)}]."
41
+ return true
42
+ end
43
+ end
44
+
45
+ def has_correct_current_path
46
+ if @spec.current_path == @base_path
47
+ true
48
+ else
49
+ @error = "Wrong current path [#{@spec.current_path}] instead of [#{@base_path}]"
50
+ false
51
+ end
52
+ end
53
+
54
+ def failure_message
55
+ "Should expose index action on #{@base_path}. Error: #{@error}"
56
+ end
57
+
58
+ def failure_message_when_negated
59
+ "Should not expose index action on #{@base_path}. Error: #{@error}"
60
+ end
61
+
62
+ alias negative_failure_message failure_message_when_negated
63
+
64
+ def description
65
+ "expose index action on #{@base_path}"
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,81 @@
1
+ module Rao
2
+ module Shoulda
3
+ module Matchers
4
+ # Example:
5
+ #
6
+ # RSpec.describe '/posts', type: :feature do
7
+ # let(:resource) { create(:post) }
8
+ #
9
+ # it { expect(subject).to implement_show_action(self).for(resource) }
10
+ # end
11
+ #
12
+ def implement_show_action(spec)
13
+ ImplementShowActionMatcher.new(spec)
14
+ end
15
+
16
+ class ImplementShowActionMatcher
17
+ include RSpec::Matchers
18
+
19
+ def initialize(spec)
20
+ @spec = spec
21
+ end
22
+
23
+ # Resource that will be updated
24
+ def for(resource)
25
+ @resource = resource
26
+ self
27
+ end
28
+
29
+ def id
30
+ @resource.to_param
31
+ end
32
+
33
+ def matches?(base_path)
34
+ @base_path = @spec.class.name.split('::')[0..2].join('::').constantize.description
35
+ # @base_path = base_path
36
+ @expected_path = "#{@base_path}/#{id}"
37
+
38
+ @spec.visit(@expected_path)
39
+ has_correct_status_code && has_correct_current_path
40
+ end
41
+
42
+ def has_correct_status_code
43
+ begin
44
+ if @spec.status_code == 200
45
+ true
46
+ else
47
+ @error = "Wrong status code [#{@spec.status_code}] instead of [200]"
48
+ false
49
+ end
50
+ rescue Capybara::NotSupportedByDriverError => e
51
+ puts "[Warning] Skipping status code check as it is not supported by your driver [#{@spec.driver.instance_variable_get(:@name)}]."
52
+ return true
53
+ end
54
+ end
55
+
56
+ def has_correct_current_path
57
+ if @spec.current_path == @expected_path
58
+ true
59
+ else
60
+ @error = "Wrong current path [#{@spec.current_path}] instead of [#{@expected_path}]"
61
+ false
62
+ end
63
+ end
64
+
65
+ def failure_message
66
+ "Should expose show action on #{@expected_path}. Error: #{@error}"
67
+ end
68
+
69
+ def failure_message_when_negated
70
+ "Should not expose show action on #{@expected_path}. Error: #{@error}"
71
+ end
72
+
73
+ alias negative_failure_message failure_message_when_negated
74
+
75
+ def description
76
+ "expose show action on #{@expected_path}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,188 @@
1
+ module Rao
2
+ module Shoulda
3
+ module Matchers
4
+ # Example checking for changed resource attributes:
5
+ #
6
+ # RSpec.describe '/posts', type: :feature do
7
+ # let(:post) { create(:post) }
8
+ # it {
9
+ # expect(subject).to implement_update_action(self)
10
+ # .for(post)
11
+ # .within_form('.edit_post') {
12
+ # fill_in 'post[title]', with: 'New title'
13
+ # fill_in 'post[body]', with: 'New body'
14
+ # }
15
+ # .updating
16
+ # .from(post.attributes)
17
+ # .to({ 'title' => 'New title', 'body' => 'New body' })
18
+ # }
19
+ # end
20
+ #
21
+ # Example checking for changed state:
22
+ #
23
+ # RSpec.describe '/posts', type: :feature do
24
+ # let(:post) { create(:post) }
25
+ # it {
26
+ # expect(subject).to implement_update_action(self)
27
+ # .for(post)
28
+ # .within_form('.edit_post') {
29
+ # fill_in 'post[title]', with: 'New title'
30
+ # fill_in 'post[body]', with: 'New body'
31
+ # }
32
+ # .updating{ |resource| resource.updated_by }
33
+ # .from(nil)
34
+ # .to(User.current)
35
+ # }
36
+ # end
37
+ #
38
+ def implement_update_action(spec)
39
+ ImplementUpdateActionMatcher.new(spec)
40
+ end
41
+
42
+ class ImplementUpdateActionMatcher
43
+ include RSpec::Matchers
44
+
45
+ def initialize(spec)
46
+ @spec = spec
47
+ end
48
+
49
+ # Resource that will be updated
50
+ def for(resource)
51
+ @resource = resource
52
+ self
53
+ end
54
+
55
+ def from(value)
56
+ @from = value
57
+ self
58
+ end
59
+
60
+ def to(value)
61
+ @to = value
62
+ self
63
+ end
64
+
65
+ # Specifies the form css id to fill to create the resource.
66
+ def within_form(id, &block)
67
+ @form_id = id
68
+ @form_block = block
69
+ self
70
+ end
71
+
72
+ def updating(&block)
73
+ @updating_block = block if block_given?
74
+ self
75
+ end
76
+
77
+ def id
78
+ @resource.to_param
79
+ end
80
+
81
+ def matches?(base_path)
82
+ @base_path = @spec.class.name.split('::')[0..2].join('::').constantize.description
83
+ # @base_path = base_path
84
+ @show_path = "#{@base_path}/#{id}"
85
+ @edit_path = "#{@base_path}/#{id}/edit"
86
+
87
+ @expected_path = @show_path
88
+
89
+ @spec.visit(@edit_path)
90
+
91
+ return unless has_correct_attributes_before if @expected_before_attributes.present?
92
+
93
+ @spec.within(@form_id) do
94
+ @form_block.call
95
+ @spec.find('input[name="commit"]').click
96
+ end
97
+
98
+ @resource.reload
99
+
100
+ has_correct_status_code && has_correct_current_path && has_correct_attributes_after
101
+ end
102
+
103
+ def has_correct_status_code
104
+ begin
105
+ if @spec.status_code == 200
106
+ true
107
+ else
108
+ @error = "Wrong status code [#{@spec.status_code}] instead of [200]"
109
+ false
110
+ end
111
+ rescue Capybara::NotSupportedByDriverError => e
112
+ puts "[Warning] Skipping status code check as it is not supported by your driver [#{@spec.driver.instance_variable_get(:@name)}]."
113
+ return true
114
+ end
115
+ end
116
+
117
+ def has_correct_current_path
118
+ if @spec.current_path == @expected_path
119
+ true
120
+ else
121
+ @error = "Wrong current path [#{@spec.current_path}] instead of [#{@expected_path}]"
122
+ false
123
+ end
124
+ end
125
+
126
+ def has_correct_attributes_before
127
+ expected = @from
128
+ if @updating_block.present?
129
+ given = @updating_block.call(@resource)
130
+
131
+ if given == expected
132
+ return true
133
+ else
134
+ @error = "Before update state [#{given.inspect}] did not match expected [#{expected.inspect}]"
135
+ return false
136
+ end
137
+ else
138
+ given = @resource.attributes.with_indifferent_access.slice(*@expected_before_attributes.keys)
139
+
140
+ if given == expected
141
+ true
142
+ else
143
+ @error = "Attributes before update [#{given}] did not match expected attributes [#{@expected_before_attributes}]"
144
+ false
145
+ end
146
+ end
147
+ end
148
+
149
+ def has_correct_attributes_after
150
+ expected = @to
151
+ if @updating_block.present?
152
+ given = @updating_block.call(@resource)
153
+
154
+ if given == expected
155
+ return true
156
+ else
157
+ @error = "After update state [#{given.inspect}] did not match expected [#{expected.inspect}]"
158
+ return false
159
+ end
160
+ else
161
+ given = @resource.attributes.with_indifferent_access.slice(*@to.keys)
162
+
163
+ if given == expected
164
+ true
165
+ else
166
+ @error = "Attributes after update [#{given}] did not match expected attributes [#{@expected_before_attributes}]"
167
+ false
168
+ end
169
+ end
170
+ end
171
+
172
+ def failure_message
173
+ "Should expose update action on #{@edit_path}. Error: #{@error}"
174
+ end
175
+
176
+ def failure_message_when_negated
177
+ "Should not expose update action on #{@edit_path}. Error: #{@error}"
178
+ end
179
+
180
+ alias negative_failure_message failure_message_when_negated
181
+
182
+ def description
183
+ "expose update action on #{@edit_path}"
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,12 @@
1
+ require 'rao/shoulda/matchers/implement_create_action_matcher'
2
+ require 'rao/shoulda/matchers/implement_show_action_matcher'
3
+ require 'rao/shoulda/matchers/implement_update_action_matcher'
4
+ require 'rao/shoulda/matchers/implement_delete_action_matcher'
5
+ require 'rao/shoulda/matchers/implement_index_action_matcher'
6
+
7
+ module Rao
8
+ module Shoulda
9
+ module Matchers
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'rao/version'
2
+
3
+ module Rao
4
+ module ShouldaMatchers
5
+ VERSION = ::Rao::VERSION
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require 'rao'
2
+
3
+ module Rao
4
+ # Adding the matchers to rspec:
5
+ #
6
+ # # spec/rails_helper or spec/support/rao-shoulda_matchers.rb
7
+ # require 'rao/shoulda/matchers'
8
+ #
9
+ # RSpec.configure do |config|
10
+ # config.include Rao::Shoulda::Matchers, type: :feature
11
+ # end
12
+ module ShouldaMatchers
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ require 'rao'
2
+
3
+ require 'rao/shoulda_matchers'
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rao-shoulda_matchers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.13.pre
5
+ platform: ruby
6
+ authors:
7
+ - Roberto Vasquez Angel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rao
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.6
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails-dummy
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description:
112
+ email:
113
+ - roberto@vasquez-angel.de
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - MIT-LICENSE
119
+ - Rakefile
120
+ - lib/generators/rao/shoulda_matchers/resources_controller_generator.rb
121
+ - lib/generators/rao/shoulda_matchers/templates/resources_controller_spec.rb
122
+ - lib/rao-shoulda_matchers.rb
123
+ - lib/rao/shoulda/matchers.rb
124
+ - lib/rao/shoulda/matchers/implement_create_action_matcher.rb
125
+ - lib/rao/shoulda/matchers/implement_delete_action_matcher.rb
126
+ - lib/rao/shoulda/matchers/implement_index_action_matcher.rb
127
+ - lib/rao/shoulda/matchers/implement_show_action_matcher.rb
128
+ - lib/rao/shoulda/matchers/implement_update_action_matcher.rb
129
+ - lib/rao/shoulda_matchers.rb
130
+ - lib/rao/shoulda_matchers/version.rb
131
+ homepage: https://github.com/rao
132
+ licenses:
133
+ - MIT
134
+ metadata: {}
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">"
147
+ - !ruby/object:Gem::Version
148
+ version: 1.3.1
149
+ requirements: []
150
+ rubygems_version: 3.0.2
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Additional shoulda matchers for Ruby on Rails.
154
+ test_files: []