rao-shoulda_matchers 0.0.13.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []