shoulda-matchers 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/.travis.yml +11 -3
  2. data/Appraisals +3 -3
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +69 -70
  5. data/MIT-LICENSE +1 -1
  6. data/NEWS.md +22 -4
  7. data/README.md +3 -1
  8. data/Rakefile +9 -5
  9. data/features/step_definitions/rails_steps.rb +7 -7
  10. data/features/support/env.rb +1 -1
  11. data/gemfiles/3.0.gemfile +1 -1
  12. data/gemfiles/3.0.gemfile.lock +25 -22
  13. data/gemfiles/3.1.gemfile +1 -1
  14. data/gemfiles/3.1.gemfile.lock +27 -24
  15. data/gemfiles/3.2.gemfile +1 -1
  16. data/gemfiles/3.2.gemfile.lock +56 -52
  17. data/lib/shoulda/matchers/action_controller.rb +3 -2
  18. data/lib/shoulda/matchers/action_controller/assign_to_matcher.rb +10 -8
  19. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +2 -4
  20. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +3 -4
  21. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +3 -4
  22. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +6 -6
  23. data/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb +5 -2
  24. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +2 -2
  25. data/lib/shoulda/matchers/action_controller/route_matcher.rb +12 -12
  26. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -4
  27. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +10 -11
  28. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +121 -0
  29. data/lib/shoulda/matchers/action_mailer/have_sent_email_matcher.rb +7 -4
  30. data/lib/shoulda/matchers/active_model.rb +1 -1
  31. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +8 -8
  32. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +5 -4
  33. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +3 -3
  34. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +2 -2
  35. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +0 -1
  36. data/lib/shoulda/matchers/active_model/helpers.rb +16 -7
  37. data/lib/shoulda/matchers/active_model/only_integer_matcher.rb +3 -3
  38. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +8 -6
  39. data/lib/shoulda/matchers/active_model/validate_format_of_matcher.rb +19 -10
  40. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +4 -4
  41. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +19 -21
  42. data/lib/shoulda/matchers/active_model/validation_matcher.rb +7 -7
  43. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +1 -1
  44. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +5 -5
  45. data/lib/shoulda/matchers/active_record/association_matcher.rb +3 -3
  46. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +11 -7
  47. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +2 -2
  48. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +5 -5
  49. data/lib/shoulda/matchers/active_record/query_the_database_matcher.rb +5 -2
  50. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +3 -3
  51. data/lib/shoulda/matchers/assertion_error.rb +4 -1
  52. data/lib/shoulda/matchers/independent/delegate_matcher.rb +17 -7
  53. data/lib/shoulda/matchers/integrations/rspec.rb +19 -33
  54. data/lib/shoulda/matchers/version.rb +1 -1
  55. data/shoulda-matchers.gemspec +6 -4
  56. data/spec/shoulda/matchers/action_controller/assign_to_matcher_spec.rb +66 -0
  57. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  58. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  59. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  60. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +58 -0
  61. data/spec/shoulda/matchers/action_controller/respond_with_content_type_matcher_spec.rb +31 -0
  62. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  63. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +65 -0
  64. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  65. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  66. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +142 -0
  67. data/spec/shoulda/matchers/action_mailer/have_sent_email_spec.rb +324 -0
  68. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  69. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +124 -0
  70. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +43 -0
  71. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +74 -0
  72. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +171 -0
  73. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +113 -0
  74. data/spec/shoulda/{active_model → matchers/active_model}/exception_message_finder_spec.rb +2 -2
  75. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  76. data/spec/shoulda/matchers/active_model/only_integer_matcher_spec.rb +52 -0
  77. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  78. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +41 -0
  79. data/spec/shoulda/matchers/active_model/validate_format_of_matcher_spec.rb +75 -0
  80. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +73 -0
  81. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +127 -0
  82. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +175 -0
  83. data/spec/shoulda/{active_model → matchers/active_model}/validation_message_finder_spec.rb +0 -1
  84. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +106 -0
  85. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +534 -0
  86. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  87. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  88. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  89. data/spec/shoulda/{active_record → matchers/active_record}/query_the_database_matcher_spec.rb +10 -10
  90. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  91. data/spec/shoulda/{independent → matchers/independent}/delegate_matcher_spec.rb +55 -34
  92. data/spec/spec_helper.rb +1 -2
  93. data/spec/support/active_model_versions.rb +4 -0
  94. data/spec/support/activemodel_helpers.rb +19 -0
  95. data/spec/support/controller_builder.rb +38 -12
  96. data/spec/support/model_builder.rb +8 -2
  97. metadata +106 -98
  98. data/spec/fixtures/addresses.yml +0 -3
  99. data/spec/fixtures/friendships.yml +0 -0
  100. data/spec/fixtures/posts.yml +0 -5
  101. data/spec/fixtures/products.yml +0 -0
  102. data/spec/fixtures/taggings.yml +0 -0
  103. data/spec/fixtures/tags.yml +0 -9
  104. data/spec/fixtures/users.yml +0 -6
  105. data/spec/shoulda/action_controller/assign_to_matcher_spec.rb +0 -63
  106. data/spec/shoulda/action_controller/filter_param_matcher_spec.rb +0 -20
  107. data/spec/shoulda/action_controller/redirect_to_matcher_spec.rb +0 -40
  108. data/spec/shoulda/action_controller/render_template_matcher_spec.rb +0 -69
  109. data/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb +0 -55
  110. data/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb +0 -28
  111. data/spec/shoulda/action_controller/respond_with_matcher_spec.rb +0 -83
  112. data/spec/shoulda/action_controller/route_matcher_spec.rb +0 -65
  113. data/spec/shoulda/action_controller/set_session_matcher_spec.rb +0 -46
  114. data/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb +0 -130
  115. data/spec/shoulda/action_mailer/have_sent_email_spec.rb +0 -333
  116. data/spec/shoulda/active_model/allow_mass_assignment_of_matcher_spec.rb +0 -115
  117. data/spec/shoulda/active_model/allow_value_matcher_spec.rb +0 -131
  118. data/spec/shoulda/active_model/disallow_value_matcher_spec.rb +0 -65
  119. data/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb +0 -79
  120. data/spec/shoulda/active_model/ensure_inclusion_of_matcher_spec.rb +0 -181
  121. data/spec/shoulda/active_model/ensure_length_of_matcher_spec.rb +0 -138
  122. data/spec/shoulda/active_model/helpers_spec.rb +0 -129
  123. data/spec/shoulda/active_model/only_integer_matcher_spec.rb +0 -69
  124. data/spec/shoulda/active_model/validate_acceptance_of_matcher_spec.rb +0 -43
  125. data/spec/shoulda/active_model/validate_confirmation_of_matcher_spec.rb +0 -48
  126. data/spec/shoulda/active_model/validate_format_of_matcher_spec.rb +0 -79
  127. data/spec/shoulda/active_model/validate_numericality_of_matcher_spec.rb +0 -112
  128. data/spec/shoulda/active_model/validate_presence_of_matcher_spec.rb +0 -135
  129. data/spec/shoulda/active_model/validate_uniqueness_of_matcher_spec.rb +0 -154
  130. data/spec/shoulda/active_record/accept_nested_attributes_for_matcher_spec.rb +0 -84
  131. data/spec/shoulda/active_record/association_matcher_spec.rb +0 -642
  132. data/spec/shoulda/active_record/have_db_column_matcher_spec.rb +0 -185
  133. data/spec/shoulda/active_record/have_db_index_matcher_spec.rb +0 -105
  134. data/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb +0 -46
  135. data/spec/shoulda/active_record/serialize_matcher_spec.rb +0 -81
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActionController do
4
+ describe ".permit" do
5
+ it "is true when the sent parameter is allowed" do
6
+ controller_class = controller_for_resource_with_strong_parameters do
7
+ params.require(:user).permit(:name)
8
+ end
9
+
10
+ controller_class.should permit(:name).for(:create)
11
+ end
12
+
13
+ it "is false when the sent parameter is not allowed" do
14
+ controller_class = controller_for_resource_with_strong_parameters do
15
+ params.require(:user).permit(:name)
16
+ end
17
+
18
+ controller_class.should_not permit(:admin).for(:create)
19
+ end
20
+
21
+ it "allows multiple attributes" do
22
+ controller_class = controller_for_resource_with_strong_parameters do
23
+ params.require(:user).permit(:name, :age)
24
+ end
25
+
26
+ controller_class.should permit(:name, :age).for(:create)
27
+ end
28
+ end
29
+ end
30
+
31
+ describe Shoulda::Matchers::ActionController::StrongParametersMatcher do
32
+ before do
33
+ controller_for_resource_with_strong_parameters do
34
+ params.require(:user).permit(:name, :age)
35
+ end
36
+ end
37
+
38
+ describe "#matches?" do
39
+ it "is true for a subset of the allowable attributes" do
40
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, self).for(:create)
41
+ matcher.matches?.should be_true
42
+ end
43
+
44
+ it "is true for all the allowable attributes" do
45
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, :age, self).for(:create)
46
+ matcher.matches?.should be_true
47
+ end
48
+
49
+ it "is false when any attributes are not allowed" do
50
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, :admin, self).for(:create)
51
+ matcher.matches?.should be_false
52
+ end
53
+
54
+ it "is false when permit is not called" do
55
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, self).for(:new, :verb => :get)
56
+ matcher.matches?.should be_false
57
+ end
58
+
59
+ it "requires an action" do
60
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, self)
61
+ expect{ matcher.matches? }.to raise_error(Shoulda::Matchers::ActionController::StrongParametersMatcher::ActionNotDefinedError)
62
+ end
63
+
64
+ it "requires a verb for non-restful action" do
65
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, self).for(:authorize)
66
+ expect{ matcher.matches? }.to raise_error(Shoulda::Matchers::ActionController::StrongParametersMatcher::VerbNotDefinedError)
67
+ end
68
+ end
69
+
70
+ describe "#does_not_match?" do
71
+ it "it is true if any of the given attributes are allowed" do
72
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, :admin, self).for(:create)
73
+ matcher.does_not_match?.should be_true
74
+ end
75
+
76
+ it "it is false if all of the given attribtues are allowed" do
77
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, :age, self).for(:create)
78
+ matcher.does_not_match?.should be_false
79
+ end
80
+ end
81
+
82
+ describe "#failure_message" do
83
+ it "includes all missing attributes" do
84
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, :age, :city, :country, self).for(:create)
85
+ matcher.matches?
86
+
87
+ matcher.failure_message.should eq("Expected controller to permit city and country, but it did not.")
88
+ end
89
+ end
90
+
91
+ describe "#negative_failure_message" do
92
+ it "includes all attributes that should not have been allowed but were" do
93
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, :age, :city, :country, self).for(:create)
94
+ matcher.does_not_match?.should be_true
95
+
96
+ matcher.negative_failure_message.should eq("Expected controller not to permit city and country, but it did.")
97
+ end
98
+ end
99
+
100
+ describe "#for" do
101
+ context "when given :create" do
102
+ it "posts to the controller" do
103
+ context = stub('context', :post => nil)
104
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, context).for(:create)
105
+
106
+ matcher.matches?
107
+ context.should have_received(:post).with(:create)
108
+ end
109
+ end
110
+
111
+ context "when given :update" do
112
+ it "puts to the controller" do
113
+ context = stub('context', :put => nil)
114
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, context).for(:update)
115
+
116
+ matcher.matches?
117
+ context.should have_received(:put).with(:update)
118
+ end
119
+ end
120
+
121
+ context "when given a custom action and verb" do
122
+ it "puts to the controller" do
123
+ context = stub('context', :delete => nil)
124
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, context).for(:hide, :verb => :delete)
125
+
126
+ matcher.matches?
127
+ context.should have_received(:delete).with(:hide)
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "#in_context" do
133
+ it 'sets the object the controller action is sent to' do
134
+ context = stub('context', :post => nil)
135
+ matcher = Shoulda::Matchers::ActionController::StrongParametersMatcher.new(:name, nil).for(:create).in_context(context)
136
+
137
+ matcher.matches?
138
+
139
+ context.should have_received(:post).with(:create)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,324 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActionMailer::HaveSentEmailMatcher do
4
+ subject { described_class.new(self) }
5
+ after { ::ActionMailer::Base.deliveries.clear }
6
+
7
+ def add_mail_to_deliveries(params = nil)
8
+ ::ActionMailer::Base.deliveries << Mailer.the_email(params)
9
+ end
10
+
11
+ context 'testing with instance variables with no multipart' do
12
+ let(:info) do
13
+ {
14
+ :from => 'do-not-reply@example.com',
15
+ :reply_to => 'reply-to-me@example.com',
16
+ :to => 'myself@me.com',
17
+ :cc => ['you@you.com', 'joe@bob.com', 'hello@goodbye.com'],
18
+ :bcc => ['test@example.com', 'sam@bob.com', 'goodbye@hello.com'],
19
+ :subject => 'This is spam',
20
+ :body => 'Every email is spam.'
21
+ }
22
+ end
23
+
24
+ before do
25
+ define_mailer(:mailer, [:the_email]) do
26
+ def the_email(params)
27
+ mail params
28
+ end
29
+ end
30
+ add_mail_to_deliveries(info)
31
+ end
32
+
33
+ it 'sends an e-mail based on subject' do
34
+ should have_sent_email.with_subject{ info[:subject] }
35
+ end
36
+
37
+ it 'sends an e-mail based on recipient' do
38
+ should have_sent_email.to(nil) { info[:to] }
39
+ end
40
+
41
+ it 'sends an e-mail based on sender' do
42
+ should have_sent_email.from{ info[:from] }
43
+ end
44
+
45
+ it 'sends an e-email based on reply_to' do
46
+ should have_sent_email.reply_to { info[:reply_to] }
47
+ end
48
+
49
+ it 'sends an e-mail based on cc' do
50
+ should have_sent_email.cc{ info[:cc][0] }
51
+ end
52
+
53
+ it 'sends an e-mail based on cc list' do
54
+ should have_sent_email.with_cc{ info[:cc] }
55
+ end
56
+
57
+ it 'sends an e-mail based on bcc' do
58
+ should have_sent_email.bcc{ info[:bcc][0] }
59
+ end
60
+
61
+ it 'sends an e-mail based on bcc list' do
62
+ should have_sent_email.with_bcc{ info[:bcc] }
63
+ end
64
+
65
+ it 'sends an e-mail based on body' do
66
+ should have_sent_email.with_body{ info[:body] }
67
+ end
68
+ end
69
+
70
+ context 'testing with instance variables with multiple parts' do
71
+ let(:info) do
72
+ {
73
+ :from => 'do-not-reply@example.com',
74
+ :to => 'myself@me.com',
75
+ :cc => ['you@you.com', 'joe@bob.com', 'hello@goodbye.com'],
76
+ :bcc => ['test@example.com', 'sam@bob.com', 'goodbye@hello.com'],
77
+ :subject => 'This is spam',
78
+ :text => 'Every email is spam.',
79
+ :html => '<h1>HTML is spam.</h1><p>Notably.</p>'
80
+ }
81
+ end
82
+
83
+ before do
84
+ define_mailer(:mailer, [:the_email]) do
85
+ def the_email(params)
86
+ mail params do |format|
87
+ format.text { render :text => params[:text] }
88
+ format.html { render :text => params[:html] }
89
+ end
90
+ end
91
+ end
92
+ add_mail_to_deliveries(info)
93
+ end
94
+
95
+ it 'sends emails with text and html parts' do
96
+ should have_sent_email.with_part('text/plain') { info[:text] }.with_part('text/html') { info[:html] }
97
+ end
98
+
99
+ it 'should have the block override the method argument' do
100
+ should have_sent_email.with_part('text/plain', 'foo') { info[:text] }.with_part('text/html', /bar/) { info[:html] }
101
+ end
102
+ end
103
+
104
+ context 'an email without multiple parts' do
105
+ before do
106
+ define_mailer :mailer, [:the_email] do
107
+ def the_email(params)
108
+ mail :from => 'do-not-reply@example.com',
109
+ :to => 'myself@me.com',
110
+ :subject => 'This is spam',
111
+ :cc => ['you@you.com', 'joe@bob.com', 'hello@goodbye.com'],
112
+ :bcc => ['test@example.com', 'sam@bob.com', 'goodbye@hello.com'],
113
+ :body => 'Every email is spam.'
114
+ end
115
+ end
116
+ add_mail_to_deliveries
117
+ end
118
+
119
+ it 'accepts sent-email when it is not multipart' do
120
+ should_not have_sent_email.multipart
121
+ matcher = have_sent_email.multipart(true)
122
+ matcher.matches?(Mailer.the_email(nil))
123
+ matcher.failure_message_for_should.should =~ /Expected sent email being multipart/
124
+ end
125
+
126
+ it 'matches the body with a regexp' do
127
+ should have_sent_email.with_body(/email is spam/)
128
+ end
129
+
130
+ it 'matches the body with a string' do
131
+ should have_sent_email.with_body('Every email is spam.')
132
+ should_not have_sent_email.with_body('emails is')
133
+ end
134
+ end
135
+
136
+ context 'an email with both a text/plain and text/html part' do
137
+ before do
138
+ define_mailer :mailer, [:the_email] do
139
+ def the_email(params)
140
+ mail :from => 'do-not-reply@example.com',
141
+ :to => 'myself@me.com',
142
+ :cc => ['you@you.com', 'joe@bob.com', 'hello@goodbye.com'],
143
+ :bcc => ['test@example.com', 'sam@bob.com', 'goodbye@hello.com'],
144
+ :subject => 'This is spam' do |format|
145
+
146
+ format.text { render :text => 'Every email is spam.' }
147
+ format.html { render :text => '<h1>HTML is spam.</h1><p>Notably.</p>' }
148
+ end
149
+ end
150
+ end
151
+ add_mail_to_deliveries
152
+ end
153
+
154
+ it 'accepts sent e-mail based on the subject' do
155
+ should have_sent_email.with_subject(/is spam$/)
156
+ matcher = have_sent_email.with_subject(/totally safe/)
157
+ matcher.matches?(nil)
158
+ matcher.failure_message_for_should.should =~ /Expected sent email with subject/
159
+ end
160
+
161
+ it 'accepts sent e-mail based on a string sender' do
162
+ should have_sent_email.from('do-not-reply@example.com')
163
+ matcher = have_sent_email.from('you@example.com')
164
+ matcher.matches?(nil)
165
+ matcher.failure_message_for_should.should =~ /Expected sent email from/
166
+ end
167
+
168
+ it 'accepts sent e-mail based on a regexp sender' do
169
+ should have_sent_email.from(/@example\.com/)
170
+ matcher = have_sent_email.from(/you@/)
171
+ matcher.matches?(nil)
172
+ matcher.failure_message_for_should.should =~ /Expected sent email from/
173
+ end
174
+
175
+ it 'accepts sent e-mail based on the body' do
176
+ should have_sent_email.with_body(/is spam\./)
177
+ matcher = have_sent_email.with_body(/totally safe/)
178
+ matcher.matches?(nil)
179
+ matcher.failure_message_for_should.should =~ /Expected sent email with body/
180
+ end
181
+
182
+ it 'accepts sent e-mail based on a text/plain part' do
183
+ should have_sent_email.with_part('text/plain', /is spam\./)
184
+ matcher = have_sent_email.with_part('text/plain', /HTML is spam/)
185
+ matcher.matches?(nil)
186
+ matcher.failure_message_for_should.should =~ /Expected sent email with a text\/plain part containing/
187
+ end
188
+
189
+ it 'accepts sent e-mail based on a text/html part' do
190
+ should have_sent_email.with_part('text/html', /HTML is spam/)
191
+ matcher = have_sent_email.with_part('text/html', /HTML is not spam\./)
192
+ matcher.matches?(nil)
193
+ matcher.failure_message_for_should.should =~ /Expected sent email with a text\/html part containing/
194
+ end
195
+
196
+ it 'accept sent e-mail based on the recipient' do
197
+ should have_sent_email.to('myself@me.com')
198
+ matcher = have_sent_email.to('you@example.com')
199
+ matcher.matches?(nil)
200
+ matcher.failure_message_for_should.should =~ /Expected sent email to/
201
+ end
202
+
203
+ it 'accepts sent e-mail based on cc string' do
204
+ should have_sent_email.cc('joe@bob.com')
205
+ matcher = have_sent_email.cc('you@example.com')
206
+ matcher.matches?(nil)
207
+ matcher.failure_message_for_should.should =~ /Expected sent email cc/
208
+ end
209
+
210
+ it 'accepts sent-email based on cc regex' do
211
+ should have_sent_email.cc(/@bob\.com/)
212
+ matcher = have_sent_email.cc(/us@/)
213
+ matcher.matches?(nil)
214
+ matcher.failure_message_for_should.should =~ /Expected sent email cc/
215
+ end
216
+
217
+ it 'accepts sent e-mail based on cc list' do
218
+ should have_sent_email.with_cc(['you@you.com', 'joe@bob.com'])
219
+ matcher = have_sent_email.with_cc(['you@example.com'])
220
+ matcher.matches?(nil)
221
+ matcher.failure_message_for_should.should =~ /Expected sent email with cc/
222
+ end
223
+
224
+ it 'accepts sent e-mail based on bcc string' do
225
+ should have_sent_email.bcc('goodbye@hello.com')
226
+ matcher = have_sent_email.bcc('test@hello.com')
227
+ matcher.matches?(nil)
228
+ matcher.failure_message_for_should.should =~ /Expected sent email bcc/
229
+ end
230
+
231
+ it 'accepts sent e-mail based on bcc regex' do
232
+ should have_sent_email.bcc(/@example\.com/)
233
+ matcher = have_sent_email.bcc(/you@/)
234
+ matcher.matches?(nil)
235
+ matcher.failure_message_for_should.should =~ /Expected sent email bcc/
236
+ end
237
+
238
+ it 'accepts sent e-mail based on bcc list' do
239
+ should have_sent_email.with_bcc(['sam@bob.com', 'test@example.com'])
240
+ matcher = have_sent_email.with_bcc(['you@you.com', 'joe@bob.com'])
241
+ matcher.matches?(nil)
242
+ matcher.failure_message_for_should.should =~ /Expected sent email with bcc/
243
+ end
244
+
245
+ it 'accepts sent-email when it is multipart' do
246
+ should have_sent_email.multipart
247
+ matcher = have_sent_email.multipart(false)
248
+ matcher.matches?(nil)
249
+ matcher.failure_message_for_should.should =~ /Expected sent email not being multipart/
250
+ end
251
+
252
+ it 'lists all the deliveries within failure message' do
253
+ add_mail_to_deliveries
254
+
255
+ matcher = have_sent_email.to('you@example.com')
256
+ matcher.matches?(nil)
257
+ matcher.failure_message_for_should.should =~ /Deliveries:\n"This is spam" to \["myself@me\.com"\]\n"This is spam" to \["myself@me\.com"\]/
258
+ end
259
+
260
+ it 'allows chaining' do
261
+ should have_sent_email.with_subject(/spam/).from('do-not-reply@example.com').with_body(/spam/).
262
+ with_part('text/plain', /is spam\./).with_part('text/html', /HTML is spam/).to('myself@me.com')
263
+ should_not have_sent_email.with_subject(/ham/).from('you@example.com').with_body(/ham/).
264
+ with_part('text/plain', /is ham/).with_part('text/html', /HTML is ham/).to('them@example.com')
265
+ end
266
+ end
267
+
268
+ context 'testing multiple email deliveries at once' do
269
+ let(:info1) do
270
+ {
271
+ :from => 'do-not-reply@example.com',
272
+ :to => 'one@me.com',
273
+ :subject => 'subject',
274
+ :body => 'body'
275
+ }
276
+ end
277
+
278
+ let(:info2) do
279
+ {
280
+ :from => 'do-not-reply@example.com',
281
+ :to => 'two@me.com',
282
+ :subject => 'subject',
283
+ :body => 'body'
284
+ }
285
+ end
286
+
287
+ before do
288
+ define_mailer(:mailer, [:the_email]) do
289
+ def the_email(params)
290
+ mail params
291
+ end
292
+ end
293
+ add_mail_to_deliveries(info1)
294
+ add_mail_to_deliveries(info2)
295
+ end
296
+
297
+ it 'sends an e-mail based on recipient 1' do
298
+ should have_sent_email.to('one@me.com')
299
+ end
300
+
301
+ it 'sends an e-mail based on recipient 2' do
302
+ should have_sent_email.to('two@me.com')
303
+ end
304
+ end
305
+
306
+ it 'provides a detailed description of the e-mail expected to be sent' do
307
+ matcher = have_sent_email
308
+ matcher.description.should == 'send an email'
309
+ matcher = matcher.with_subject('Welcome!')
310
+ matcher.description.should == %q(send an email with a subject of "Welcome!")
311
+ matcher = matcher.with_body('Welcome, human!')
312
+ matcher.description.should == %q(send an email with a subject of "Welcome!" containing "Welcome, human!")
313
+ matcher = matcher.with_part("text/plain", "plain")
314
+ matcher.description.should == %q(send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain")
315
+ matcher = matcher.with_part('text/html', 'html')
316
+ matcher.description.should == %q(send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html")
317
+ matcher = matcher.from('alien@example.com')
318
+ matcher.description.should == %q(send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html" from "alien@example.com")
319
+ matcher = matcher.to('human@example.com')
320
+ matcher.description.should == %q(send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html" from "alien@example.com" to "human@example.com")
321
+ matcher = matcher.reply_to('reply-to-me@example.com')
322
+ matcher.description.should == %q(send an email with a subject of "Welcome!" containing "Welcome, human!" having a text/plain part containing "plain" having a text/html part containing "html" from "alien@example.com" reply to "reply-to-me@example.com" to "human@example.com")
323
+ end
324
+ end