konacha 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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