konacha 2.1.0 → 2.2.0

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.
data/.travis.yml CHANGED
@@ -1,9 +1,16 @@
1
+ language: ruby
1
2
  rvm:
2
3
  - 1.8.7
3
4
  - 1.9.3
5
+ gemfile:
6
+ - Gemfile
7
+ - Gemfile-rails4
4
8
  before_script:
5
9
  - sh -e /etc/init.d/xvfb start
6
10
  - export DISPLAY=:99.0
7
11
  matrix:
12
+ exclude:
13
+ - gemfile: Gemfile-rails4
14
+ rvm: 1.8.7
8
15
  allow_failures:
9
- - { rvm: 1.8.7 }
16
+ - { gemfile: Gemfile-rails4 }
data/Gemfile-rails4 ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem "railties", github: "rails/rails"
5
+ gem "activemodel", github: "rails/rails"
6
+ gem "journey", github: "rails/journey"
7
+ gem "sprockets-rails", github: "rails/sprockets-rails"
data/History.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # master
2
2
 
3
+ # 2.2.0
4
+
5
+ * Update mocha (1.8.1) and chai (1.4.2)
6
+
3
7
  # 2.1.0
4
8
 
5
9
  * Improve capybara-webkit compatibility (#79)
data/README.md CHANGED
@@ -208,8 +208,11 @@ Konacha will make all three of chai's assertion styles available to you: `expect
208
208
  `should`, and `assert`. See the chai documentation for the details.
209
209
 
210
210
  If you use jQuery, you may want to check out [chai-jquery](https://github.com/jfirebaugh/chai-jquery)
211
- for some jQuery-specific assertions. You can add it painlessly with the
212
- [chai-jquery-rails](https://github.com/wordofchristian/chai-jquery-rails) gem.
211
+ for some jQuery-specific assertions. There are a lot of interesting chai
212
+ matchers out there, see [the chai plugins page](http://chaijs.com/plugins)
213
+
214
+ To make all these available for your konacha environment, see the
215
+ [Konacha-chai-matchers gem](https://github.com/matthijsgroen/konacha-chai-matchers)
213
216
 
214
217
  ## Templates / Fixtures
215
218
 
data/Rakefile CHANGED
@@ -18,3 +18,7 @@ task :assets do
18
18
  end
19
19
 
20
20
  task :default => :spec
21
+
22
+ task :server do
23
+ sh 'rackup -p 3500 config.ru'
24
+ end
@@ -9,7 +9,7 @@
9
9
  </head>
10
10
  <body>
11
11
  <% @specs.each do |spec| %>
12
- <%= content_tag :iframe, "", :src => "/iframe/#{spec.asset_name}", :class => "test-context", "data-path" => spec.path %>
12
+ <%= content_tag :iframe, "", :src => iframe_path(spec.asset_name), :class => "test-context", "data-path" => spec.path %>
13
13
  <% end %>
14
14
  <div id="mocha"></div>
15
15
  </body>
data/config.ru ADDED
@@ -0,0 +1,2 @@
1
+ require File.expand_path("../spec/dummy/config/environment.rb", __FILE__)
2
+ run Konacha.application
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  Konacha::Engine.routes.draw do
2
- get '/iframe/*name' => 'specs#iframe'
2
+ get '/iframe/*name' => 'specs#iframe', :as => :iframe
3
3
  get '/' => 'specs#parent'
4
4
  get '*path' => 'specs#parent'
5
5
  end
data/konacha.gemspec CHANGED
@@ -17,18 +17,20 @@ the asset pipeline and engines.}
17
17
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  gem.name = "konacha"
19
19
  gem.require_paths = ["lib"]
20
- gem.version = "2.1.0"
20
+ gem.version = "2.2.0"
21
+ gem.license = "MIT"
21
22
 
22
- gem.add_dependency "railties", "~> 3.1"
23
- gem.add_dependency "actionpack", "~> 3.1"
23
+ gem.add_dependency "railties", ">= 3.1", "< 5"
24
+ gem.add_dependency "actionpack", ">= 3.1", "< 5"
24
25
  gem.add_dependency "sprockets"
25
26
  gem.add_dependency "capybara"
26
27
  gem.add_dependency "colorize"
27
28
 
28
29
  gem.add_development_dependency "jquery-rails"
29
- gem.add_development_dependency "rspec-rails"
30
+ gem.add_development_dependency "rspec-rails", "~> 2.12"
30
31
  gem.add_development_dependency "capybara-firebug", "~> 1.1"
31
32
  gem.add_development_dependency "coffee-script"
32
33
  gem.add_development_dependency "ejs"
33
34
  gem.add_development_dependency "tzinfo"
35
+ gem.add_development_dependency "poltergeist"
34
36
  end
@@ -2,6 +2,7 @@ require File.expand_path('../boot', __FILE__)
2
2
 
3
3
  require "action_controller/railtie"
4
4
  require "action_view/railtie"
5
+ require "active_model/railtie" # https://github.com/rspec/rspec-rails/pull/642
5
6
  require "sprockets/railtie"
6
7
 
7
8
  if defined?(Bundler)
@@ -6,8 +6,8 @@ Dummy::Application.configure do
6
6
  # since you don't have to restart the web server when you make code changes.
7
7
  config.cache_classes = false
8
8
 
9
- # Log error messages when you accidentally call methods on nil.
10
- config.whiny_nils = true
9
+ # Do not eager load in development.
10
+ config.eager_load = false
11
11
 
12
12
  # Show full error reports and disable caching
13
13
  config.consider_all_requests_local = true
@@ -0,0 +1,12 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rake secret` to generate a secure secret key.
9
+
10
+ # Make sure your secret_key_base is kept private
11
+ # if you're sharing your code publicly.
12
+ Dummy::Application.config.secret_key_base = '58633e8901c06c9cd6484fcc4fee564f1329e8b5c44c93101479868598ce73ffb1438ee6a0f819ab719c4724683434f7d78285ba0badd06440d64bb6417f84dc'
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Konacha, :type => :request do
3
+ describe Konacha, :type => :feature do
4
4
  before do
5
5
  Konacha.mode = :server
6
6
  end
data/spec/runner_spec.rb CHANGED
@@ -26,99 +26,115 @@ describe Konacha::Runner do
26
26
  end
27
27
  end
28
28
 
29
- describe "#run" do
30
- let(:suite) do
31
- {'event' => 'suite',
32
- 'type' => 'suite',
33
- 'data' => {
34
- 'title' => 'failure',
35
- 'fullTitle' => 'failure',
36
- 'path' => 'failing_spec.js'
37
- }}
29
+ shared_examples_for "Konacha::Runner" do |driver|
30
+ before do
31
+ Konacha.configure do |config|
32
+ config.driver = driver
33
+ end
38
34
  end
39
35
 
40
- let(:suite_end) do
41
- {'event' => 'suite end',
42
- 'type' => 'suite',
43
- 'data' => {
44
- 'title' => 'failure',
45
- 'fullTitle' => 'failure',
46
- 'path' => 'failing_spec.js'
47
- }}
48
- end
36
+ describe "#run" do
37
+ let(:suite) do
38
+ {'event' => 'suite',
39
+ 'type' => 'suite',
40
+ 'data' => {
41
+ 'title' => 'failure',
42
+ 'fullTitle' => 'failure',
43
+ 'path' => 'failing_spec.js'
44
+ }}
45
+ end
49
46
 
50
- let(:test) do
51
- {'event' => 'test',
52
- 'type' => 'test',
53
- 'data' => {
54
- 'title' => 'fails',
55
- 'fullTitle' => 'failure fails',
56
- 'parentFullTitle' => 'failure',
57
- 'path' => 'failing_spec.js'}}
58
- end
47
+ let(:suite_end) do
48
+ {'event' => 'suite end',
49
+ 'type' => 'suite',
50
+ 'data' => {
51
+ 'title' => 'failure',
52
+ 'fullTitle' => 'failure',
53
+ 'path' => 'failing_spec.js'
54
+ }}
55
+ end
59
56
 
60
- let(:failure) do
61
- {'event' => 'fail',
62
- 'type' => 'test',
63
- 'data' => {
64
- 'title' => 'fails',
65
- 'fullTitle' => 'failure fails',
66
- 'parentFullTitle' => 'failure',
67
- 'status' => 'failed',
68
- 'path' => 'failing_spec.js',
69
- 'error' => {'message' => 'expected 4 to equal 5', 'name' => 'AssertionError'}}}
70
- end
57
+ let(:test) do
58
+ {'event' => 'test',
59
+ 'type' => 'test',
60
+ 'data' => {
61
+ 'title' => 'fails',
62
+ 'fullTitle' => 'failure fails',
63
+ 'parentFullTitle' => 'failure',
64
+ 'path' => 'failing_spec.js'}}
65
+ end
71
66
 
72
- let(:error) do
73
- {'event' => 'fail',
74
- 'type' => 'test',
75
- 'data' => {
76
- 'title' => 'errors',
77
- 'fullTitle' => 'failure errors',
78
- 'parentFullTitle' => 'failure',
79
- 'status' => 'failed',
80
- 'path' => 'failing_spec.js',
81
- 'error' => {'message' => 'this one errors out', 'name' => 'Error'}}}
82
- end
67
+ let(:failure) do
68
+ {'event' => 'fail',
69
+ 'type' => 'test',
70
+ 'data' => {
71
+ 'title' => 'fails',
72
+ 'fullTitle' => 'failure fails',
73
+ 'parentFullTitle' => 'failure',
74
+ 'status' => 'failed',
75
+ 'path' => 'failing_spec.js',
76
+ 'error' => {'message' => 'expected 4 to equal 5', 'name' => 'AssertionError'}}}
77
+ end
83
78
 
84
- let(:pass) do
85
- {'event' => 'pass',
86
- 'type' => 'test',
87
- 'data' => {
88
- 'title' => 'is empty',
89
- 'fullTitle' => 'the body#konacha element is empty',
90
- 'parentFullTitle' => 'the body#konacha element',
91
- 'status' => 'passed',
92
- 'path' => 'body_spec.js.coffee',
93
- 'duration' => anything}}
94
- end
79
+ let(:error) do
80
+ {'event' => 'fail',
81
+ 'type' => 'test',
82
+ 'data' => {
83
+ 'title' => 'errors',
84
+ 'fullTitle' => 'failure errors',
85
+ 'parentFullTitle' => 'failure',
86
+ 'status' => 'failed',
87
+ 'path' => 'failing_spec.js',
88
+ 'error' => {'message' => 'this one errors out', 'name' => 'Error'}}}
89
+ end
95
90
 
96
- let(:pending) do
97
- {'event' => 'pending',
98
- 'type' => 'test',
99
- 'data' => {
100
- 'title' => 'is pending',
101
- 'fullTitle' => 'pending test is pending',
102
- 'parentFullTitle' => 'pending test',
103
- 'path' => 'pending_spec.js',
104
- 'status' => 'pending'}}
105
- end
91
+ let(:pass) do
92
+ {'event' => 'pass',
93
+ 'type' => 'test',
94
+ 'data' => {
95
+ 'title' => 'is empty',
96
+ 'fullTitle' => 'the body#konacha element is empty',
97
+ 'parentFullTitle' => 'the body#konacha element',
98
+ 'status' => 'passed',
99
+ 'path' => 'body_spec.js.coffee',
100
+ 'duration' => anything}}
101
+ end
102
+
103
+ let(:pending) do
104
+ {'event' => 'pending',
105
+ 'type' => 'test',
106
+ 'data' => {
107
+ 'title' => 'is pending',
108
+ 'fullTitle' => 'pending test is pending',
109
+ 'parentFullTitle' => 'pending test',
110
+ 'path' => 'pending_spec.js',
111
+ 'status' => 'pending'}}
112
+ end
113
+
114
+ let(:start) { {'event' => 'start', 'testCount' => kind_of(Integer), 'data' => {} } }
115
+ let(:end_event) { {'event' => 'end', 'data' => {} } }
106
116
 
107
- let(:start) { {'event' => 'start', 'testCount' => kind_of(Integer), 'data' => {} } }
108
- let(:end_event) { {'event' => 'end', 'data' => {} } }
109
-
110
- it "passes along the right events" do
111
- subject.reporter.should_receive(:process_mocha_event).with(start)
112
- subject.reporter.should_receive(:process_mocha_event).with(suite)
113
- subject.reporter.should_receive(:process_mocha_event).with(suite_end)
114
- subject.reporter.should_receive(:process_mocha_event).with(test)
115
- subject.reporter.should_receive(:process_mocha_event).with(failure)
116
- subject.reporter.should_receive(:process_mocha_event).with(error)
117
- subject.reporter.should_receive(:process_mocha_event).with(pass)
118
- subject.reporter.should_receive(:process_mocha_event).with(pending)
119
- subject.reporter.should_receive(:process_mocha_event).with(end_event)
120
- subject.reporter.should_receive(:process_mocha_event).any_number_of_times
121
- subject.run
117
+ it "passes along the right events" do
118
+ subject.reporter.should_receive(:process_mocha_event).with(start)
119
+ subject.reporter.should_receive(:process_mocha_event).with(suite)
120
+ subject.reporter.should_receive(:process_mocha_event).with(suite_end)
121
+ subject.reporter.should_receive(:process_mocha_event).with(test)
122
+ subject.reporter.should_receive(:process_mocha_event).with(failure)
123
+ subject.reporter.should_receive(:process_mocha_event).with(error)
124
+ subject.reporter.should_receive(:process_mocha_event).with(pass)
125
+ subject.reporter.should_receive(:process_mocha_event).with(pending)
126
+ subject.reporter.should_receive(:process_mocha_event).with(end_event)
127
+ subject.reporter.should_receive(:process_mocha_event).any_number_of_times
128
+ subject.run
129
+ end
122
130
  end
123
131
  end
132
+
133
+ describe "with selenium" do
134
+ it_behaves_like "Konacha::Runner", :selenium
135
+ end
136
+
137
+ describe "with poltergeist" do
138
+ it_behaves_like "Konacha::Runner", :poltergeist
139
+ end
124
140
  end
data/spec/server_spec.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Konacha::Server, :type => :request do
3
+ describe Konacha::Server, :type => :feature do
4
4
  before do
5
5
  Konacha.mode = :server
6
6
  end
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,7 @@ require "ejs"
13
13
 
14
14
  require "capybara/rails"
15
15
  require "capybara/firebug"
16
+ require "capybara/poltergeist"
16
17
 
17
18
  Capybara.configure do |config|
18
19
  config.default_selector = :css
@@ -21,7 +22,7 @@ Capybara.configure do |config|
21
22
  end
22
23
 
23
24
  module Konacha
24
- module RequestSpec
25
+ module FeatureSpec
25
26
  def app
26
27
  # Override the RSpec default of `Rails.application`.
27
28
  Konacha.application
@@ -30,7 +31,7 @@ module Konacha
30
31
  end
31
32
 
32
33
  RSpec.configure do |config|
33
- config.include Konacha::RequestSpec, :type => :request
34
+ config.include Konacha::FeatureSpec, :type => :feature
34
35
  end
35
36
 
36
37
  Konacha.configure do |config|
@@ -12,19 +12,20 @@ describe "konacha/specs/iframe" do
12
12
  it "renders a script tag for @spec" do
13
13
  assign(:spec, spec_double("a_spec"))
14
14
 
15
- render
15
+ view.stub(:javascript_include_tag)
16
+ view.should_receive(:javascript_include_tag).with("a_spec")
16
17
 
17
- rendered.should have_selector("script[src='/assets/a_spec.js']")
18
+ render
18
19
  end
19
20
 
20
21
  it "renders the stylesheets" do
21
22
  assign(:spec, spec_double("a_spec"))
22
23
  assign(:stylesheets, %w(foo bar))
23
24
 
24
- render
25
+ view.should_receive(:stylesheet_link_tag).with("foo", :debug => false)
26
+ view.should_receive(:stylesheet_link_tag).with("bar", :debug => false)
25
27
 
26
- rendered.should have_selector("link[href='/assets/foo.css']")
27
- rendered.should have_selector("link[href='/assets/bar.css']")
28
+ render
28
29
  end
29
30
 
30
31
  it "includes a path data attribute" do
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe "konacha/specs/parent" do
4
+ def spec_double(asset_name)
5
+ double("spec called '#{asset_name}'", :asset_name => asset_name, :path => "#{asset_name}.js")
6
+ end
7
+
8
+ it "renders an iframe tag for a spec" do
9
+ # https://github.com/rails/rails/issues/4364
10
+ # https://github.com/rspec/rspec-rails/pull/539
11
+ view.singleton_class.send(:include, Konacha::Engine.routes.url_helpers)
12
+
13
+ spec = spec_double("a_spec")
14
+ assign(:specs, [spec])
15
+
16
+ render
17
+
18
+ Capybara.string(rendered).find("iframe")[:src].should == "/iframe/a_spec"
19
+ end
20
+ end
@@ -74,7 +74,7 @@
74
74
  * Chai version
75
75
  */
76
76
 
77
- exports.version = '1.3.0';
77
+ exports.version = '1.4.2';
78
78
 
79
79
  /*!
80
80
  * Primary `Assertion` prototype
@@ -86,7 +86,7 @@
86
86
  * Assertion Error
87
87
  */
88
88
 
89
- exports.AssertionError = require('./chai/browser/error');
89
+ exports.AssertionError = require('./chai/error');
90
90
 
91
91
  /*!
92
92
  * Utils for plugins (not exported)
@@ -155,7 +155,7 @@
155
155
  * Module dependencies.
156
156
  */
157
157
 
158
- var AssertionError = require('./browser/error')
158
+ var AssertionError = require('./error')
159
159
  , util = require('./utils')
160
160
  , flag = util.flag;
161
161
 
@@ -228,8 +228,9 @@
228
228
  * @api private
229
229
  */
230
230
 
231
- Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual) {
231
+ Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) {
232
232
  var ok = util.test(this, arguments);
233
+ if (true !== showDiff) showDiff = false;
233
234
 
234
235
  if (!ok) {
235
236
  var msg = util.getMessage(this, arguments)
@@ -239,6 +240,7 @@
239
240
  , actual: actual
240
241
  , expected: expected
241
242
  , stackStartFunction: (Assertion.includeStack) ? this.assert : flag(this, 'ssfi')
243
+ , showDiff: showDiff
242
244
  });
243
245
  }
244
246
  };
@@ -262,38 +264,6 @@
262
264
 
263
265
  }); // module: chai/assertion.js
264
266
 
265
- require.register("chai/browser/error.js", function(module, exports, require){
266
- /*!
267
- * chai
268
- * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
269
- * MIT Licensed
270
- */
271
-
272
- module.exports = AssertionError;
273
-
274
- function AssertionError (options) {
275
- options = options || {};
276
- this.message = options.message;
277
- this.actual = options.actual;
278
- this.expected = options.expected;
279
- this.operator = options.operator;
280
-
281
- if (options.stackStartFunction && Error.captureStackTrace) {
282
- var stackStartFunction = options.stackStartFunction;
283
- Error.captureStackTrace(this, stackStartFunction);
284
- }
285
- }
286
-
287
- AssertionError.prototype = Object.create(Error.prototype);
288
- AssertionError.prototype.name = 'AssertionError';
289
- AssertionError.prototype.constructor = AssertionError;
290
-
291
- AssertionError.prototype.toString = function() {
292
- return this.message;
293
- };
294
-
295
- }); // module: chai/browser/error.js
296
-
297
267
  require.register("chai/core/assertions.js", function(module, exports, require){
298
268
  /*!
299
269
  * chai
@@ -325,6 +295,8 @@
325
295
  * - and
326
296
  * - have
327
297
  * - with
298
+ * - at
299
+ * - of
328
300
  *
329
301
  * @name language chains
330
302
  * @api public
@@ -332,7 +304,8 @@
332
304
 
333
305
  [ 'to', 'be', 'been'
334
306
  , 'is', 'and', 'have'
335
- , 'with', 'that' ].forEach(function (chain) {
307
+ , 'with', 'that', 'at'
308
+ , 'of' ].forEach(function (chain) {
336
309
  Assertion.addProperty(chain, function () {
337
310
  return this;
338
311
  });
@@ -671,6 +644,8 @@
671
644
  , 'expected #{this} to equal #{exp}'
672
645
  , 'expected #{this} to not equal #{exp}'
673
646
  , val
647
+ , this._obj
648
+ , true
674
649
  );
675
650
  }
676
651
  }
@@ -700,6 +675,8 @@
700
675
  , 'expected #{this} to deeply equal #{exp}'
701
676
  , 'expected #{this} to not deeply equal #{exp}'
702
677
  , obj
678
+ , this._obj
679
+ , true
703
680
  );
704
681
  });
705
682
 
@@ -743,7 +720,7 @@
743
720
  this.assert(
744
721
  obj > n
745
722
  , 'expected #{this} to be above ' + n
746
- , 'expected #{this} to be below ' + n
723
+ , 'expected #{this} to be at most ' + n
747
724
  );
748
725
  }
749
726
  }
@@ -752,6 +729,53 @@
752
729
  Assertion.addMethod('gt', assertAbove);
753
730
  Assertion.addMethod('greaterThan', assertAbove);
754
731
 
732
+ /**
733
+ * ### .least(value)
734
+ *
735
+ * Asserts that the target is greater than or equal to `value`.
736
+ *
737
+ * expect(10).to.be.at.least(10);
738
+ *
739
+ * Can also be used in conjunction with `length` to
740
+ * assert a minimum length. The benefit being a
741
+ * more informative error message than if the length
742
+ * was supplied directly.
743
+ *
744
+ * expect('foo').to.have.length.of.at.least(2);
745
+ * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);
746
+ *
747
+ * @name least
748
+ * @alias gte
749
+ * @param {Number} value
750
+ * @param {String} message _optional_
751
+ * @api public
752
+ */
753
+
754
+ function assertLeast (n, msg) {
755
+ if (msg) flag(this, 'message', msg);
756
+ var obj = flag(this, 'object');
757
+ if (flag(this, 'doLength')) {
758
+ new Assertion(obj, msg).to.have.property('length');
759
+ var len = obj.length;
760
+ this.assert(
761
+ len >= n
762
+ , 'expected #{this} to have a length at least #{exp} but got #{act}'
763
+ , 'expected #{this} to not have a length below #{exp}'
764
+ , n
765
+ , len
766
+ );
767
+ } else {
768
+ this.assert(
769
+ obj >= n
770
+ , 'expected #{this} to be at least ' + n
771
+ , 'expected #{this} to be below ' + n
772
+ );
773
+ }
774
+ }
775
+
776
+ Assertion.addMethod('least', assertLeast);
777
+ Assertion.addMethod('gte', assertLeast);
778
+
755
779
  /**
756
780
  * ### .below(value)
757
781
  *
@@ -792,7 +816,7 @@
792
816
  this.assert(
793
817
  obj < n
794
818
  , 'expected #{this} to be below ' + n
795
- , 'expected #{this} to be above ' + n
819
+ , 'expected #{this} to be at least ' + n
796
820
  );
797
821
  }
798
822
  }
@@ -801,6 +825,53 @@
801
825
  Assertion.addMethod('lt', assertBelow);
802
826
  Assertion.addMethod('lessThan', assertBelow);
803
827
 
828
+ /**
829
+ * ### .most(value)
830
+ *
831
+ * Asserts that the target is less than or equal to `value`.
832
+ *
833
+ * expect(5).to.be.at.most(5);
834
+ *
835
+ * Can also be used in conjunction with `length` to
836
+ * assert a maximum length. The benefit being a
837
+ * more informative error message than if the length
838
+ * was supplied directly.
839
+ *
840
+ * expect('foo').to.have.length.of.at.most(4);
841
+ * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);
842
+ *
843
+ * @name most
844
+ * @alias lte
845
+ * @param {Number} value
846
+ * @param {String} message _optional_
847
+ * @api public
848
+ */
849
+
850
+ function assertMost (n, msg) {
851
+ if (msg) flag(this, 'message', msg);
852
+ var obj = flag(this, 'object');
853
+ if (flag(this, 'doLength')) {
854
+ new Assertion(obj, msg).to.have.property('length');
855
+ var len = obj.length;
856
+ this.assert(
857
+ len <= n
858
+ , 'expected #{this} to have a length at most #{exp} but got #{act}'
859
+ , 'expected #{this} to not have a length above #{exp}'
860
+ , n
861
+ , len
862
+ );
863
+ } else {
864
+ this.assert(
865
+ obj <= n
866
+ , 'expected #{this} to be at most ' + n
867
+ , 'expected #{this} to be above ' + n
868
+ );
869
+ }
870
+ }
871
+
872
+ Assertion.addMethod('most', assertMost);
873
+ Assertion.addMethod('lte', assertMost);
874
+
804
875
  /**
805
876
  * ### .within(start, finish)
806
877
  *
@@ -1392,6 +1463,70 @@
1392
1463
 
1393
1464
  }); // module: chai/core/assertions.js
1394
1465
 
1466
+ require.register("chai/error.js", function(module, exports, require){
1467
+ /*!
1468
+ * chai
1469
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
1470
+ * MIT Licensed
1471
+ */
1472
+
1473
+ /*!
1474
+ * Main export
1475
+ */
1476
+
1477
+ module.exports = AssertionError;
1478
+
1479
+ /**
1480
+ * # AssertionError (constructor)
1481
+ *
1482
+ * Create a new assertion error based on the Javascript
1483
+ * `Error` prototype.
1484
+ *
1485
+ * **Options**
1486
+ * - message
1487
+ * - actual
1488
+ * - expected
1489
+ * - operator
1490
+ * - startStackFunction
1491
+ *
1492
+ * @param {Object} options
1493
+ * @api public
1494
+ */
1495
+
1496
+ function AssertionError (options) {
1497
+ options = options || {};
1498
+ this.message = options.message;
1499
+ this.actual = options.actual;
1500
+ this.expected = options.expected;
1501
+ this.operator = options.operator;
1502
+ this.showDiff = options.showDiff;
1503
+
1504
+ if (options.stackStartFunction && Error.captureStackTrace) {
1505
+ var stackStartFunction = options.stackStartFunction;
1506
+ Error.captureStackTrace(this, stackStartFunction);
1507
+ }
1508
+ }
1509
+
1510
+ /*!
1511
+ * Inherit from Error
1512
+ */
1513
+
1514
+ AssertionError.prototype = Object.create(Error.prototype);
1515
+ AssertionError.prototype.name = 'AssertionError';
1516
+ AssertionError.prototype.constructor = AssertionError;
1517
+
1518
+ /**
1519
+ * # toString()
1520
+ *
1521
+ * Override default to string method
1522
+ */
1523
+
1524
+ AssertionError.prototype.toString = function() {
1525
+ return this.message;
1526
+ };
1527
+
1528
+ }); // module: chai/error.js
1529
+
1395
1530
  require.register("chai/interface/assert.js", function(module, exports, require){
1396
1531
  /*!
1397
1532
  * chai
@@ -2255,13 +2390,17 @@
2255
2390
  };
2256
2391
 
2257
2392
  /**
2258
- * ### .throws(function, [constructor/regexp], [message])
2393
+ * ### .throws(function, [constructor/string/regexp], [string/regexp], [message])
2259
2394
  *
2260
2395
  * Asserts that `function` will throw an error that is an instance of
2261
2396
  * `constructor`, or alternately that it will throw an error with message
2262
2397
  * matching `regexp`.
2263
2398
  *
2399
+ * assert.throw(fn, 'function throws a reference error');
2400
+ * assert.throw(fn, /function throws a reference error/);
2401
+ * assert.throw(fn, ReferenceError);
2264
2402
  * assert.throw(fn, ReferenceError, 'function throws a reference error');
2403
+ * assert.throw(fn, ReferenceError, /function throws a reference error/);
2265
2404
  *
2266
2405
  * @name throws
2267
2406
  * @alias throw
@@ -2274,13 +2413,13 @@
2274
2413
  * @api public
2275
2414
  */
2276
2415
 
2277
- assert.Throw = function (fn, type, msg) {
2278
- if ('string' === typeof type) {
2279
- msg = type;
2280
- type = null;
2416
+ assert.Throw = function (fn, errt, errs, msg) {
2417
+ if ('string' === typeof errt || errt instanceof RegExp) {
2418
+ errs = errt;
2419
+ errt = null;
2281
2420
  }
2282
2421
 
2283
- new Assertion(fn, msg).to.Throw(type);
2422
+ new Assertion(fn, msg).to.Throw(errt, errs);
2284
2423
  };
2285
2424
 
2286
2425
  /**
@@ -2649,7 +2788,7 @@
2649
2788
  };
2650
2789
  }
2651
2790
 
2652
- function _deepEqual(actual, expected) {
2791
+ function _deepEqual(actual, expected, memos) {
2653
2792
 
2654
2793
  // 7.1. All identical values are equivalent, as determined by ===.
2655
2794
  if (actual === expected) {
@@ -2681,7 +2820,7 @@
2681
2820
  // corresponding key, and an identical 'prototype' property. Note: this
2682
2821
  // accounts for both named and indexed properties on Arrays.
2683
2822
  } else {
2684
- return objEquiv(actual, expected);
2823
+ return objEquiv(actual, expected, memos);
2685
2824
  }
2686
2825
  }
2687
2826
 
@@ -2693,11 +2832,25 @@
2693
2832
  return Object.prototype.toString.call(object) == '[object Arguments]';
2694
2833
  }
2695
2834
 
2696
- function objEquiv(a, b) {
2835
+ function objEquiv(a, b, memos) {
2697
2836
  if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
2698
2837
  return false;
2838
+
2699
2839
  // an identical 'prototype' property.
2700
2840
  if (a.prototype !== b.prototype) return false;
2841
+
2842
+ // check if we have already compared a and b
2843
+ var i;
2844
+ if (memos) {
2845
+ for(i = 0; i < memos.length; i++) {
2846
+ if ((memos[i][0] === a && memos[i][1] === b) ||
2847
+ (memos[i][0] === b && memos[i][1] === a))
2848
+ return true;
2849
+ }
2850
+ } else {
2851
+ memos = [];
2852
+ }
2853
+
2701
2854
  //~~~I've managed to break Object.keys through screwy arguments passing.
2702
2855
  // Converting to array solves the problem.
2703
2856
  if (isArguments(a)) {
@@ -2706,19 +2859,21 @@
2706
2859
  }
2707
2860
  a = pSlice.call(a);
2708
2861
  b = pSlice.call(b);
2709
- return _deepEqual(a, b);
2862
+ return _deepEqual(a, b, memos);
2710
2863
  }
2711
2864
  try {
2712
2865
  var ka = Object.keys(a),
2713
2866
  kb = Object.keys(b),
2714
- key, i;
2867
+ key;
2715
2868
  } catch (e) {//happens when one is a string literal and the other isn't
2716
2869
  return false;
2717
2870
  }
2871
+
2718
2872
  // having the same number of owned properties (keys incorporates
2719
2873
  // hasOwnProperty)
2720
2874
  if (ka.length != kb.length)
2721
2875
  return false;
2876
+
2722
2877
  //the same set of keys (although not necessarily the same order),
2723
2878
  ka.sort();
2724
2879
  kb.sort();
@@ -2727,12 +2882,17 @@
2727
2882
  if (ka[i] != kb[i])
2728
2883
  return false;
2729
2884
  }
2885
+
2886
+ // remember objects we have compared to guard against circular references
2887
+ memos.push([ a, b ]);
2888
+
2730
2889
  //equivalent values for every corresponding key, and
2731
2890
  //~~~possibly expensive deep test
2732
2891
  for (i = ka.length - 1; i >= 0; i--) {
2733
2892
  key = ka[i];
2734
- if (!_deepEqual(a[key], b[key])) return false;
2893
+ if (!_deepEqual(a[key], b[key], memos)) return false;
2735
2894
  }
2895
+
2736
2896
  return true;
2737
2897
  }
2738
2898
 
@@ -2792,7 +2952,7 @@
2792
2952
 
2793
2953
  module.exports = function (obj, args) {
2794
2954
  var actual = args[4];
2795
- return 'undefined' !== actual ? actual : obj._obj;
2955
+ return 'undefined' !== typeof actual ? actual : obj._obj;
2796
2956
  };
2797
2957
 
2798
2958
  }); // module: chai/utils/getActual.js