peck-on-rails 0.2.1 → 0.3.0

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
+ SHA1:
3
+ metadata.gz: 983910938947f3b167357b8884551802c68f461b
4
+ data.tar.gz: 4257a34ffdab95c6d6593a5474ff4a49e42026ff
5
+ SHA512:
6
+ metadata.gz: 2da9e480923e109174e60bf29b1e9e18e944147398c1cea15f86949d45be1de947e0358b4c779493eb017b0e6ef4a19e9e7c56e001cbea87476ba2ad2b22d099
7
+ data.tar.gz: b51f97c1df464400c78878bc81dec1b8ba73cd96cd75c38a698d7777ac9a38bd42faef5835e13b145698bac105feade127aa6f9c5343b200277a9654bb0cfb0b
data/README.md CHANGED
@@ -6,6 +6,197 @@ Peck-On-Rails is an extension for Peck to make testing Rails easier.
6
6
 
7
7
  ## Getting Started
8
8
 
9
- You can install Peck On Rails as a gem.
9
+ You can install Peck-On-Rails as a gem. Note that the Peck dependency will automatically be fulfilled.
10
10
 
11
- $ gem install peck-on-rails
11
+ $ gem install peck-on-rails
12
+
13
+ You can also add it to your Rails application's `Gemfile`.
14
+
15
+ group :test do
16
+ gem 'peck-on-rails'
17
+ end
18
+
19
+ To use it in your Rails application, create or edit a file named `test/test_helper.rb`;
20
+
21
+ ENV["RAILS_ENV"] ||= "test"
22
+ require File.expand_path('../../config/environment', __FILE__)
23
+
24
+ require 'peck/flavors/vanilla'
25
+ require 'peck_on_rails'
26
+
27
+ You can read more about Peck formatting and flavors in [Peck's documentation](https://github.com/Fingertips/Peck).
28
+
29
+ Don't forget to require your test helper in your test files. We like to require relative to the file so you can use Ruby to run the tests.
30
+
31
+ require File.expand_path('../../test_helper', __FILE__)
32
+
33
+ describe AuthorsController do
34
+ should.find.get :index
35
+ end
36
+
37
+ Now just run your test:
38
+
39
+ $ ruby test/functional/authors_controller_test.rb
40
+ .
41
+ 1 spec, 0 failures, finished in 0.13 seconds.
42
+
43
+ Alternatively Peck has a CLI tool to run tests for you:
44
+
45
+ $ peck test/models/book_test.rb
46
+ .
47
+ 1 spec, 0 failures, finished in 0.0 seconds.
48
+
49
+ ## Test types
50
+
51
+ Peck-On-Rails automatically supports model, controller, and helper specs. By default it figures out what kind of test your writing by the class found in the context. For example, POR will assume you're operating on an Active Record model when Book inherits from `ActiveRecord::Base`.
52
+
53
+ describe "A new", Book do
54
+ it "does not have any pages" do
55
+ book = Book.new
56
+ book.pages.count.should == 0
57
+ end
58
+ end
59
+
60
+ If POR has trouble figuring out what you're doing, you can force it:
61
+
62
+ describe Candle, :model do
63
+ end
64
+
65
+ Supported types are `:model`, `:controller`, and `:helper`.
66
+
67
+ ## Model specs
68
+
69
+ POR loads fixtures for `:model` type tests. It also does this for `:controller` and `:helper` tests by the way. This also means it doesn't load fixtures for library specs.
70
+
71
+ There is one little matcher that you get in your model specs: a validation matcher.
72
+
73
+ describe Book do
74
+ it "requires a title" do
75
+ book = Book.new
76
+
77
+ book.should.not.validate_with(:title, nil)
78
+ book.should.not.validate_with(:title, '')
79
+
80
+ book.should.validate_with(:title, 'The Fault in Our Stars')
81
+ end
82
+ end
83
+
84
+ Note that this matcher is a bit dirty as it changes your instance:
85
+
86
+ describe Book do
87
+ it "requires a title" do
88
+ book = Book.new
89
+ book.should.not.validate_with(:title, nil)
90
+ p book.errors.full_messages
91
+ end
92
+ end
93
+
94
+ ## Helper specs
95
+
96
+ In `:helper` specs you automatically get your helper module included.
97
+
98
+ describe BooksHelper do
99
+ it "formats titles" do
100
+ book = Book.new(title: 'Little Pinguin', :number = 12)
101
+ format_book_title(book).should == "12. Little Pinguin"
102
+ end
103
+ end
104
+
105
+ ## Controller specs
106
+
107
+ For controller specs you get a `@controller` instance, a `controller` accessor, routing, and some nifty helpers.
108
+
109
+ describe "On the", BooksController, "a visitor" do
110
+ it "sees an overview of recent books" do
111
+ get :index
112
+ status.should == :ok
113
+ templates.should.include 'books/index'
114
+ body.should.match_css 'h1' # Only possible when Nokogiri is installed
115
+ body.should.match_xpath '//h1' # Only possible when Nokogiri is installed
116
+ body.document # Returns the Nokogiri Document
117
+ end
118
+
119
+ it "sees and overview of recent books in JSON" do
120
+ get :index, :format => 'json'
121
+ body.should.not.be.blank
122
+ body.json.keys.should.include 'books'
123
+ end
124
+ end
125
+
126
+ On top of that you get some macro's to generate specs which will test basic functions of the controller.
127
+
128
+ describe "On the", Manage::BooksController, "a visitor" do
129
+ should.require_login :index
130
+ end
131
+
132
+ describe "On the", Manage::BooksController, "a regular member" do
133
+ should.disallow :index
134
+ end
135
+
136
+ describe "On the", Manage::BooksController, "an admin" do
137
+ should.find :index
138
+ end
139
+
140
+ These generated specs assume there are three methods defined on the spec: `login_required?`, `disallowed?`, and `allowed?`. We usually define them as follows:
141
+
142
+ module TestHelper
143
+ module Authentication
144
+ def login_required?
145
+ if @request.format == 'text/html'
146
+ @response.location == new_session_url
147
+ else
148
+ @response.status == 401
149
+ end
150
+ end
151
+
152
+ def allowed?
153
+ @response.status == 200
154
+ end
155
+
156
+ def disallowed?
157
+ @response.status == 403
158
+ end
159
+ end
160
+ end
161
+
162
+ # Auto include these methods on all `:controller` context instances.
163
+ Peck::Context.once do |context|
164
+ case context_type
165
+ when :controller
166
+ extend TestHelper::Authentication
167
+ end
168
+ end
169
+
170
+ ## Writing matchers
171
+
172
+ Right now you have to open up the `Peck::Should` class to do this:
173
+
174
+ class Peck
175
+ class Should
176
+ def validate_with(attribute, value)
177
+ message = "Expected #{!@negated ? 'no' : ''}errors on" +
178
+ " #{attribute.inspect} with value `#{value.inspect}' after validation"
179
+
180
+ @this.send("#{attribute}=", value)
181
+ @this.valid?
182
+ if @this.errors[attribute].kind_of?(Array)
183
+ satisfy(message) { @this.errors[attribute].empty? }
184
+ else
185
+ satisfy(message) { @this.errors[attribute].nil? }
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ ## Adding before or after methods for all specs
192
+
193
+ You can use Peck's callback which is ran for each context once:
194
+
195
+ Peck::Context.once do |context|
196
+ class_eval do
197
+ before do
198
+ FileUtils.rm_rf(my_nice_directory)
199
+ FileUtils.mkdir_p(my_nice_directory)
200
+ end
201
+ end
202
+ end
data/lib/peck_on_rails.rb CHANGED
@@ -6,195 +6,25 @@ require 'active_support/core_ext/kernel/reporting'
6
6
  require 'active_support/deprecation'
7
7
  require 'rails/backtrace_cleaner'
8
8
 
9
+ require 'peck_on_rails/assertions'
10
+ require 'peck_on_rails/backtrace_cleaning'
11
+ require 'peck_on_rails/controller'
12
+ require 'peck_on_rails/helper'
13
+ require 'peck_on_rails/model'
14
+
9
15
  class Peck
10
16
  class Rails
11
- module BacktraceCleaning
12
- protected
13
-
14
- def clean_backtrace(backtrace)
15
- super Peck::Rails::BacktraceCleaning.backtrace_cleaner.clean(backtrace)
16
- end
17
-
18
- def self.backtrace_cleaner
19
- ::Rails.backtrace_cleaner
20
- end
21
- end
22
-
23
- class Context
24
- def self.init(context, context_type, subject)
25
- Peck.log("Peck::Rails::Context.init")
26
- end
27
- end
28
-
29
- class Helper
30
- def self.init(context, context_type, subject)
31
- if [:helper].include?(context_type)
32
- Peck.log("Peck::Rails::Helper.init")
33
- context.class_eval do
34
- include subject
35
- end
36
- end
37
- end
38
- end
39
-
40
- class Model
41
- def self.init(context, context_type, subject)
42
- if [:model, :controller, :helper].include?(context_type)
43
- Peck.log("Peck::Rails::Model.init")
44
- context.class_eval do
45
- include ::ActiveRecord::TestFixtures
46
- self.fixture_path = File.join(::Rails.root, 'test', 'fixtures')
47
- fixtures :all
48
- define_method(:method_name) { self.class.label }
49
- end
50
- end
51
- end
17
+ def self.dev_null
18
+ @dev_null ||= File.open('/dev/null', 'w')
52
19
  end
53
20
 
54
- class Controller
55
- def self.init(context, context_type, subject)
56
- if context_type == :controller
57
- Peck.log("Peck::Rails::Controller.init")
58
- context.class_eval do
59
- attr_accessor :controller
60
-
61
- before do
62
- @routes = ::Rails.application.routes
63
- end
64
-
65
- def self.determine_default_controller_class(name)
66
- self._controller_class = Peck::Rails.subject(self)
67
- end
68
-
69
- include ::ActionController::TestCase::Behavior
70
- include ::Peck::Rails::Controller::Helpers
71
- extend ::Peck::Rails::Controller::Fixtures
72
- end
73
- end
74
- end
75
-
76
- # Stores expression to be evaluated later in the correct context
77
- class LazyValue
78
- def initialize(expression)
79
- @expression = expression
80
- end
81
-
82
- def to_param(spec)
83
- spec.instance_eval(@expression)
84
- end
85
-
86
- def inspect
87
- @expression
88
- end
89
- end
90
-
91
- module Fixtures
92
- # Returns true when the passed name is a known table, we assume known tables also have fixtures
93
- def known_fixture?(name)
94
- respond_to?(:fixture_table_names) && fixture_table_names.include?(name.to_s)
95
- end
96
-
97
- # Filter calls to fixture methods so we can use them in the context definition
98
- def method_missing(method, *arguments, &block)
99
- if known_fixture?(method)
100
- arguments = arguments.map { |a| a.inspect }
101
- ::Peck::Rails::Controller::LazyValue.new("#{method}(#{arguments.join(', ')})")
102
- else
103
- super
104
- end
105
- end
106
- end
107
-
108
- module Helpers
109
- def status
110
- Peck::Rails::Controller::Status.new(@response)
111
- end
112
-
113
- def templates
114
- # Force body to be read in case the template is being streamed
115
- response.body
116
- (@templates || @_templates).keys
117
- end
118
-
119
- def body
120
- Peck::Rails::Controller::Body.new(@response)
121
- end
122
-
123
- # Interpret the non-immediate values in params and replace them
124
- def immediate_values(params)
125
- result = {}
126
- params.each do |key, value|
127
- result[key] = case value
128
- when Hash
129
- immediate_values(value)
130
- when ::Peck::Rails::Controller::LazyValue
131
- value.to_param(self)
132
- when Proc
133
- value.call
134
- else
135
- value
136
- end
137
- end
138
- result
139
- end
140
- end
141
-
142
- class Status
143
- def initialize(response)
144
- @response = response
145
- end
146
-
147
- def ==(other)
148
- case other
149
- when Numeric
150
- @response.status == other
151
- else
152
- code = Rack::Utils::SYMBOL_TO_STATUS_CODE[other]
153
- @response.status === code
154
- end
155
- end
156
-
157
- def inspect
158
- "#<Peck::Rails::Controller::Status:#{@response.status}>"
159
- end
160
- end
161
-
162
- class Body
163
- def initialize(response)
164
- @response = response
165
- end
166
-
167
- def document
168
- if defined?(:Nokogiri)
169
- @document ||= Nokogiri::HTML.parse(@response.body)
170
- else
171
- raise RuntimeError, "Please install Nokogiri to use the CSS or Xpath matchers (gem install nokogiri)"
172
- end
173
- end
174
-
175
- def json
176
- if defined?(:JSON)
177
- @json ||= JSON.parse(@response.body)
178
- else
179
- raise RuntimeError, "Please install a JSON gem to use the json accessor (gem install json)"
180
- end
181
- end
182
-
183
- def match_css?(query)
184
- !document.css(query).empty?
185
- end
186
-
187
- def match_xpath?(query)
188
- !document.xpath(query).empty?
189
- end
190
-
191
- def blank?
192
- @response.body.blank?
193
- end
194
-
195
- def inspect
196
- "#<html body=\"#{@response.body}\">"
197
- end
21
+ def self.silence
22
+ stdout, stderr = $stdout, $stderr
23
+ $stdout, $stderr = dev_null, dev_null
24
+ begin
25
+ yield
26
+ ensure
27
+ $stdout, $stderr = stdout, stderr
198
28
  end
199
29
  end
200
30
 
@@ -213,9 +43,9 @@ class Peck
213
43
  def self.context_type_for_subject(context, subject)
214
44
  if subject.nil?
215
45
  :plain
216
- elsif subject < ActionController::Base
46
+ elsif defined?(ActionController) && subject < ActionController::Base
217
47
  :controller
218
- elsif subject < ActiveRecord::Base
48
+ elsif defined?(ActiveRecord) && subject < ActiveRecord::Base
219
49
  :model
220
50
  elsif subject.name =~ HELPER_RE
221
51
  :helper
@@ -233,12 +63,15 @@ class Peck
233
63
  end
234
64
 
235
65
  def self.init
66
+ if defined?(ActiveRecord)
67
+ Peck.log("Migrate database if necessary")
68
+ ActiveRecord::Migration.load_schema_if_pending!
69
+ end
236
70
  Peck.log("Setting up Peck::Rails")
237
71
  proc do |context|
238
72
  subject = Peck::Rails.subject(context)
239
73
  context_type = Peck::Rails.context_type(context, subject)
240
74
  [
241
- Peck::Rails::Context,
242
75
  Peck::Rails::Helper,
243
76
  Peck::Rails::Model,
244
77
  Peck::Rails::Controller
@@ -247,132 +80,23 @@ class Peck
247
80
  end
248
81
 
249
82
  context.before do
250
- setup_fixtures if respond_to?(:setup_fixtures)
83
+ if respond_to?(:setup_fixtures)
84
+ begin
85
+ setup_fixtures
86
+ rescue ActiveRecord::ConnectionNotEstablished
87
+ end
88
+ end
251
89
  end
252
90
 
253
91
  context.after do
254
- teardown_fixtures if respond_to?(:teardown_fixtures)
255
- end
256
- end
257
- end
258
- end
259
- end
260
-
261
- class Peck
262
- class Should
263
- class ResponseRequirement < Peck::Should::Proxy
264
- SUPPORTED_VERBS = [:get, :post, :put, :delete, :options]
265
-
266
- attr_accessor :method, :exception, :expected
267
-
268
- def define_specification(verb, action, params={})
269
- _method = self.method
270
- _negated = self.negated
271
- _expected = self.expected
272
- _exception = self.exception
273
- context.it(description(verb, action, params)) do
274
- begin
275
- send(verb, action, immediate_values(params))
276
- rescue => raised_exception
277
- if _negated
278
- raised_exception.should.be.kind_of(_exception)
279
- else
280
- raised_exception.should.not.be.kind_of(_exception)
281
- end
282
- else
283
- if _negated
284
- send(_method).should.not == _expected
285
- else
286
- send(_method).should == _expected
92
+ if respond_to?(:teardown_fixtures)
93
+ begin
94
+ teardown_fixtures
95
+ rescue ActiveRecord::ConnectionNotEstablished
287
96
  end
288
97
  end
289
98
  end
290
99
  end
291
-
292
- def method_missing(method, *attributes, &block)
293
- verb = method.to_sym
294
- if self.class.supported_verbs.include?(verb)
295
- define_specification(verb, *attributes)
296
- else
297
- super
298
- end
299
- end
300
-
301
- def self.supported_verbs
302
- SUPPORTED_VERBS
303
- end
304
- end
305
-
306
- class RequireLogin < ResponseRequirement
307
- def description(verb, action, params={})
308
- description = []
309
- description << "should not" if (negated == false)
310
- description << "#{verb.upcase}s `#{action}' without logging in"
311
- description << "#{params.inspect}" unless params.blank?
312
- description.join(' ')
313
- end
314
- end
315
-
316
- class Disallow < ResponseRequirement
317
- def description(verb, action, params={})
318
- description = ["should"]
319
- description << "not" if (negated == false)
320
- description << "be allowed to #{verb.upcase}s `#{action}'"
321
- description << "#{params.inspect}" unless params.blank?
322
- description.join(' ')
323
- end
324
- end
325
-
326
- class Response < ResponseRequirement
327
- attr_accessor :verb_description
328
-
329
- def description(verb, action, params={})
330
- description = ["should"]
331
- description << "not" if (negated == false)
332
- description << "#{verb_description} `#{action}'"
333
- description << "#{params.inspect}" unless params.blank?
334
- description.join(' ')
335
- end
336
- end
337
-
338
- class Specification
339
- def require_login
340
- requirement = RequireLogin.new(context)
341
- requirement.negated = @negated
342
- requirement.method = :login_required?
343
- requirement.expected = true
344
- requirement
345
- end
346
-
347
- def disallow
348
- requirement = Disallow.new(context)
349
- requirement.negated = @negated
350
- requirement.method = :disallowed?
351
- requirement.expected = true
352
- requirement
353
- end
354
-
355
- def allow
356
- requirement = Disallow.new(context)
357
- requirement.negated = @negated
358
- requirement.method = :allowed?
359
- requirement.expected = true
360
- requirement
361
- end
362
-
363
- def find
364
- requirement = Response.new(context)
365
- requirement.negated = @negated
366
- requirement.verb_description = 'find'
367
- requirement.method = :status
368
- if @negated
369
- requirement.expected = :not_found
370
- requirement.exception = ActiveRecord::RecordNotFound
371
- else
372
- requirement.expected = :ok
373
- end
374
- requirement
375
- end
376
100
  end
377
101
  end
378
102
  end
@@ -385,20 +109,4 @@ class Peck
385
109
  end
386
110
  end
387
111
 
388
- class Peck
389
- class Should
390
- def validate_with(attribute, value)
391
- message = "Expected #{!@negated ? 'no' : ''}errors on #{attribute.inspect} with value `#{value.inspect}' after validation"
392
-
393
- @this.send("#{attribute}=", value)
394
- @this.valid?
395
- if @this.errors[attribute].kind_of?(Array)
396
- satisfy(message) { @this.errors[attribute].empty? }
397
- else
398
- satisfy(message) { @this.errors[attribute].nil? }
399
- end
400
- end
401
- end
402
- end
403
-
404
112
  Peck::Context.once(&Peck::Rails.init)
@@ -0,0 +1,182 @@
1
+ class Peck
2
+ class Should
3
+ class ResponseRequirement < Peck::Should::Proxy
4
+ SUPPORTED_VERBS = [:get, :post, :put, :delete, :options]
5
+
6
+ attr_accessor :method, :allowed_exceptions, :expected
7
+
8
+ def define_specification(verb, action, params={})
9
+ _method = self.method
10
+ _negated = self.negated
11
+ _expected = self.expected
12
+ _allowed_exceptions = self.allowed_exceptions
13
+ context.it(description(verb, action, params)) do
14
+ begin
15
+ send(verb, action, immediate_values(params))
16
+ rescue => raised_exception
17
+ if _allowed_exceptions
18
+ _allowed_exceptions.any? { |exception| raised_exception.should.be.kind_of(exception) }
19
+ true.should == true # Force the expectations counter
20
+ else
21
+ raise
22
+ end
23
+ else
24
+ if _negated
25
+ send(_method).should.not == _expected
26
+ else
27
+ send(_method).should == _expected
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def method_missing(method, *attributes, &block)
34
+ verb = method.to_sym
35
+ if self.class.supported_verbs.include?(verb)
36
+ define_specification(verb, *attributes)
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ def self.supported_verbs
43
+ SUPPORTED_VERBS
44
+ end
45
+ end
46
+
47
+ class RequireLogin < ResponseRequirement
48
+ def description(verb, action, params={})
49
+ description = []
50
+ description << "should not" if (negated == false)
51
+ description << "#{verb.upcase}s `#{action}' without logging in"
52
+ description << "#{params.inspect}" unless params.blank?
53
+ description.join(' ')
54
+ end
55
+ end
56
+
57
+ class Disallow < ResponseRequirement
58
+ def description(verb, action, params={})
59
+ description = ["should"]
60
+ description << "not" if (negated == false)
61
+ description << "be allowed to #{verb.upcase}s `#{action}'"
62
+ description << "#{params.inspect}" unless params.blank?
63
+ description.join(' ')
64
+ end
65
+ end
66
+
67
+ class Response < ResponseRequirement
68
+ attr_accessor :verb_description
69
+
70
+ def description(verb, action, params={})
71
+ description = ["should"]
72
+ description << "not" if (negated == false)
73
+ description << "#{verb_description} `#{action}'"
74
+ description << "#{params.inspect}" unless params.blank?
75
+ description.join(' ')
76
+ end
77
+ end
78
+
79
+ class Specification
80
+ def self.allowed_exceptions
81
+ allowed_exceptions = []
82
+ if defined?(ActiveRecord)
83
+ allowed_exceptions << ActiveRecord::RecordNotFound
84
+ end
85
+ if defined?(AbstractController)
86
+ allowed_exceptions << AbstractController::ActionNotFound
87
+ end
88
+ allowed_exceptions
89
+ end
90
+ ALLOWED_EXCEPTIONS = allowed_exceptions
91
+
92
+ def require_login
93
+ requirement = RequireLogin.new(context)
94
+ requirement.negated = @negated
95
+ requirement.method = :login_required?
96
+ requirement.expected = true
97
+ requirement
98
+ end
99
+
100
+ def disallow
101
+ requirement = Disallow.new(context)
102
+ requirement.negated = @negated
103
+ requirement.method = :disallowed?
104
+ requirement.expected = true
105
+ requirement
106
+ end
107
+
108
+ def allow
109
+ requirement = Disallow.new(context)
110
+ requirement.negated = @negated
111
+ requirement.method = :allowed?
112
+ requirement.expected = true
113
+ requirement
114
+ end
115
+
116
+ def find
117
+ requirement = Response.new(context)
118
+ requirement.verb_description = 'find'
119
+ requirement.method = :status
120
+ if @negated
121
+ requirement.expected = :not_found
122
+ requirement.allowed_exceptions = ALLOWED_EXCEPTIONS
123
+ else
124
+ requirement.expected = :ok
125
+ end
126
+ requirement
127
+ end
128
+ end
129
+
130
+ def equal_record_set(*others)
131
+ left = @this.flatten
132
+ right = others.flatten
133
+
134
+ message = "Expected the record set to be #{!@negated ? 'equal' : 'unequal'}: #{left.map(&:id).inspect} - #{right.map(&:id).inspect}"
135
+ satisfy(message) { Set.new(left) == Set.new(right) }
136
+ end
137
+
138
+ def equal_record_array(*others)
139
+ left = @this.flatten
140
+ right = others.flatten
141
+
142
+ message = "Expected the array of records to be #{!@negated ? 'equal' : 'unequal'}: #{left.map(&:id).inspect} - #{right.map(&:id).inspect}"
143
+ satisfy(message) { left == right }
144
+ end
145
+
146
+ def equal_set(*others)
147
+ left = @this.flatten
148
+ right = others.flatten
149
+
150
+ message = "Expected sets to be #{!@negated ? 'equal' : 'unequal'}: #{left.inspect} - #{right.inspect}"
151
+ satisfy(message) { Set.new(left) == Set.new(right) }
152
+ end
153
+
154
+ def equal_keys(other)
155
+ left = @this.keys.map(&:to_s).sort
156
+ right = other.map(&:to_s).sort
157
+
158
+ missing_from_left = left - right
159
+ missing_from_right = right - left
160
+ message = "Expected the object to #{!@negated ? 'have' : 'not have'} the same keys:\n#{left.inspect}\n#{right.inspect}\n>>> #{missing_from_left.inspect}\n<<< #{missing_from_right.inspect}"
161
+ satisfy(message) { left == right }
162
+ end
163
+
164
+ def redirect_to(somewhere)
165
+ message = "Expected to redirect to `#{somewhere}'"
166
+ response = @this.send(:response)
167
+ satisfy(message) { [301, 302].include?(response.status.to_i) && response.location == somewhere }
168
+ end
169
+
170
+ def validate_with(attribute, value)
171
+ message = "Expected #{!@negated ? 'no' : ''}errors on #{attribute.inspect} with value `#{value.inspect}' after validation"
172
+
173
+ @this.send("#{attribute}=", value)
174
+ @this.valid?
175
+ if @this.errors[attribute].kind_of?(Array)
176
+ satisfy(message) { @this.errors[attribute].empty? }
177
+ else
178
+ satisfy(message) { @this.errors[attribute].nil? }
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ class Peck
4
+ class Rails
5
+ module BacktraceCleaning
6
+ protected
7
+
8
+ def clean_backtrace(backtrace)
9
+ super Peck::Rails::BacktraceCleaning.backtrace_cleaner.clean(backtrace)
10
+ end
11
+
12
+ def self.backtrace_cleaner
13
+ ::Rails.backtrace_cleaner
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,152 @@
1
+ class Peck
2
+ class Rails
3
+ class Controller
4
+ def self.init(context, context_type, subject)
5
+ if context_type == :controller
6
+ Peck.log("Peck::Rails::Controller.init")
7
+ context.class_eval do
8
+ attr_accessor :controller
9
+
10
+ before do
11
+ @routes = ::Rails.application.routes
12
+ end
13
+
14
+ def self.determine_default_controller_class(name)
15
+ self._controller_class = Peck::Rails.subject(self)
16
+ end
17
+
18
+ Peck::Rails.silence do
19
+ include ::ActionController::TestCase::Behavior
20
+ end
21
+ include ::Peck::Rails::Controller::Helpers
22
+ extend ::Peck::Rails::Controller::Fixtures
23
+ end
24
+ end
25
+ end
26
+
27
+ # Stores expression to be evaluated later in the correct context
28
+ class LazyValue
29
+ def initialize(expression)
30
+ @expression = expression
31
+ end
32
+
33
+ def to_param(spec)
34
+ spec.instance_eval(@expression)
35
+ end
36
+
37
+ def inspect
38
+ @expression
39
+ end
40
+ end
41
+
42
+ module Fixtures
43
+ # Returns true when the passed name is a known table, we assume known tables also have fixtures
44
+ def known_fixture?(name)
45
+ respond_to?(:fixture_table_names) && fixture_table_names.include?(name.to_s)
46
+ end
47
+
48
+ # Filter calls to fixture methods so we can use them in the context definition
49
+ def method_missing(method, *arguments, &block)
50
+ if known_fixture?(method)
51
+ arguments = arguments.map { |a| a.inspect }
52
+ ::Peck::Rails::Controller::LazyValue.new("#{method}(#{arguments.join(', ')})")
53
+ else
54
+ super
55
+ end
56
+ end
57
+ end
58
+
59
+ module Helpers
60
+ def status
61
+ Peck::Rails::Controller::Status.new(@response)
62
+ end
63
+
64
+ def templates
65
+ # Force body to be read in case the template is being streamed
66
+ response.body
67
+ (@templates || @_templates).keys
68
+ end
69
+
70
+ def body
71
+ Peck::Rails::Controller::Body.new(@response)
72
+ end
73
+
74
+ # Interpret the non-immediate values in params and replace them
75
+ def immediate_values(params)
76
+ result = {}
77
+ params.each do |key, value|
78
+ result[key] = case value
79
+ when Hash
80
+ immediate_values(value)
81
+ when ::Peck::Rails::Controller::LazyValue
82
+ value.to_param(self)
83
+ when Proc
84
+ value.call
85
+ else
86
+ value
87
+ end
88
+ end
89
+ result
90
+ end
91
+ end
92
+
93
+ class Status
94
+ def initialize(response)
95
+ @response = response
96
+ end
97
+
98
+ def ==(other)
99
+ case other
100
+ when Numeric
101
+ @response.status == other
102
+ else
103
+ code = Rack::Utils::SYMBOL_TO_STATUS_CODE[other]
104
+ @response.status === code
105
+ end
106
+ end
107
+
108
+ def inspect
109
+ "#<Peck::Rails::Controller::Status:#{@response.status}>"
110
+ end
111
+ end
112
+
113
+ class Body
114
+ def initialize(response)
115
+ @response = response
116
+ end
117
+
118
+ def document
119
+ if defined?(Nokogiri)
120
+ @document ||= Nokogiri::HTML.parse(@response.body)
121
+ else
122
+ raise RuntimeError, "Please install Nokogiri to use the CSS or Xpath matchers (gem install nokogiri)"
123
+ end
124
+ end
125
+
126
+ def json
127
+ if defined?(JSON)
128
+ @json ||= JSON.parse(@response.body)
129
+ else
130
+ raise RuntimeError, "Please install a JSON gem to use the json accessor (gem install json)"
131
+ end
132
+ end
133
+
134
+ def match_css?(query)
135
+ !document.css(query).empty?
136
+ end
137
+
138
+ def match_xpath?(query)
139
+ !document.xpath(query).empty?
140
+ end
141
+
142
+ def blank?
143
+ @response.body.blank?
144
+ end
145
+
146
+ def inspect
147
+ "#<html body=\"#{@response.body}\">"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,17 @@
1
+
2
+ # encoding: utf-8
3
+
4
+ class Peck
5
+ class Rails
6
+ class Helper
7
+ def self.init(context, context_type, subject)
8
+ if [:helper].include?(context_type)
9
+ Peck.log("Peck::Rails::Helper.init")
10
+ context.class_eval do
11
+ include subject
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ class Peck
2
+ class Rails
3
+ class Model
4
+ def self.init(context, context_type, subject)
5
+ if [:model, :controller, :helper].include?(context_type)
6
+ Peck.log("Peck::Rails::Model.init")
7
+ context.class_eval do
8
+ if defined?(::ActiveRecord)
9
+ include ::ActiveRecord::TestFixtures
10
+ end
11
+ self.fixture_path = File.join(::Rails.root, 'test', 'fixtures')
12
+ fixtures :all
13
+ define_method(:method_name) { self.class.label }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,84 +1,82 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: peck-on-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Manfred Stienstra
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-07-11 00:00:00.000000000 Z
11
+ date: 2014-10-23 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: peck
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rails
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
- description: ! ' Peck-On-Rails is an extension for Peck to make testing Rails easier.
47
-
48
- '
41
+ description: |2
42
+ Peck-On-Rails is an extension for Peck to make testing Rails easier.
49
43
  email: manfred@fngtps.com
50
44
  executables: []
51
45
  extensions: []
52
46
  extra_rdoc_files:
53
47
  - COPYING
54
48
  files:
55
- - lib/peck_on_rails.rb
56
49
  - COPYING
57
50
  - README.md
51
+ - lib/peck_on_rails.rb
52
+ - lib/peck_on_rails/assertions.rb
53
+ - lib/peck_on_rails/backtrace_cleaning.rb
54
+ - lib/peck_on_rails/controller.rb
55
+ - lib/peck_on_rails/helper.rb
56
+ - lib/peck_on_rails/model.rb
58
57
  homepage:
59
58
  licenses: []
59
+ metadata: {}
60
60
  post_install_message:
61
61
  rdoc_options:
62
- - --charset=utf-8
62
+ - "--charset=utf-8"
63
63
  require_paths:
64
64
  - lib
65
65
  required_ruby_version: !ruby/object:Gem::Requirement
66
- none: false
67
66
  requirements:
68
- - - ! '>='
67
+ - - ">="
69
68
  - !ruby/object:Gem::Version
70
69
  version: '0'
71
70
  required_rubygems_version: !ruby/object:Gem::Requirement
72
- none: false
73
71
  requirements:
74
- - - ! '>='
72
+ - - ">="
75
73
  - !ruby/object:Gem::Version
76
74
  version: '0'
77
75
  requirements: []
78
76
  rubyforge_project:
79
- rubygems_version: 1.8.23
77
+ rubygems_version: 2.2.2
80
78
  signing_key:
81
- specification_version: 3
79
+ specification_version: 4
82
80
  summary: Peck-On-Rails adds useful helpers and context extensions to make testing
83
81
  Ruby on Rails apps easier.
84
82
  test_files: []