chai 2.1.0 → 2.3.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.
package/CONTRIBUTING.md CHANGED
@@ -196,3 +196,7 @@ Feel free to reach out to any of the core-contributors with you questions or con
196
196
  - GH: [@vesln](https://github.com/vesln/)
197
197
  - TW: [@vesln](http://twitter.com/vesln)
198
198
  - IRC: vesln
199
+ - Keith Cirkel
200
+ - GH: [@keithamus](https://github.com/keithamus)
201
+ - TW: [@keithamus](http://twitter.com/keithamus)
202
+ - IRC: keithamus
package/History.md CHANGED
@@ -1,3 +1,53 @@
1
+ 2.3.0 / 2015-04-26
2
+ ==================
3
+
4
+ * Merge pull request #423 from ehntoo/patch-1
5
+ * Merge pull request #422 from ljharb/fix_descriptor_tests
6
+ * Fix a small bug in the .null assertion docs
7
+ * Use a regex to account for property ordering issues across engines.
8
+ * Add `make test-firefox`
9
+ * Merge pull request #417 from astorije/astorije/minimalist-typo
10
+ * Remove trailing whitespaces
11
+ * Fix super minor typo in an example
12
+ * Merge pull request #408 from ljharb/enumerableProperty
13
+ * Add `ownPropertyDescriptor` assertion.
14
+
15
+ 2.2.0 / 2015-03-26
16
+ ==================
17
+
18
+ * Merge pull request #405 from chaijs/deep-escape-doc-tweaks
19
+ * Tweak documentation on `.deep` flag.
20
+ * Merge pull request #402 from umireon/escaping-dot-should-be-taken
21
+ * Documentation of escaping in `.deep` flag.
22
+ * take regular expression apart
23
+ * Feature: backslash-escaping in `.deep.property`
24
+ * Escaping dot should be taken in deep property
25
+
26
+ 2.1.2 / 2015-03-15
27
+ ==================
28
+
29
+ * Merge pull request #396 from chaijs/add-keith-cirkel-contributing-md
30
+ * Add Keith Cirkel to CONTRIBUTING.md
31
+ * Merge pull request #395 from cjqed/386-assert-operator-no-eval
32
+ * No longer using eval on assert operator #386
33
+ * Merge pull request #389 from chaijs/update-git-summary
34
+ * Update `git summary` in README
35
+
36
+ 2.1.1 / 2015-03-04
37
+ ==================
38
+
39
+ * Merge pull request #385 from eldritch-fossicker/master
40
+ * updates to reflect code style preference from @keithamus
41
+ * fix indexing into array with deep propery
42
+ * Merge pull request #382 from astorije/patch-2
43
+ * Merge pull request #383 from gurdiga/config-doc-wording-improvement
44
+ * config.truncateThreshold docs: simpler wording
45
+ * Add missing docstring for showDiff argument of assert
46
+ * Merge pull request #381 from astorije/patch-1
47
+ * Add a minor precision that empty asserts on strings too.
48
+ * Merge pull request #379 from dcneiner/should-primitive-fix
49
+ * Primitives now use valueOf in shouldGetter
50
+
1
51
  2.1.0 / 2015-02-23
2
52
  ==================
3
53
 
package/README.md CHANGED
@@ -25,78 +25,85 @@ Chai offers a robust Plugin architecture for extending Chai's assertions and int
25
25
  ### Contributors
26
26
 
27
27
  project : chai
28
- repo age : 3 years, 3 months
29
- active : 224 days
30
- commits : 859
28
+ repo age : 3 years, 5 months
29
+ active : 244 days
30
+ commits : 900
31
31
  files : 59
32
32
  authors :
33
- 554 Jake Luer 64.5%
34
- 79 Veselin Todorov 9.2%
35
- 43 Domenic Denicola 5.0%
36
- 29 Keith Cirkel 3.4%
33
+ 555 Jake Luer 61.7%
34
+ 79 Veselin Todorov 8.8%
35
+ 52 Keith Cirkel 5.8%
36
+ 43 Domenic Denicola 4.8%
37
37
  14 Joshua Perry 1.6%
38
38
  8 Chris Polis 0.9%
39
- 6 Ian Zamojc 0.7%
40
39
  6 Ruben Verborgh 0.7%
41
- 5 Juliusz Gonera 0.6%
40
+ 6 Ian Zamojc 0.7%
42
41
  5 George Kats 0.6%
43
- 5 Jo Liss 0.6%
44
- 5 Scott Nonnenberg 0.6%
45
42
  5 leider 0.6%
46
- 4 charlierudolph 0.5%
47
- 4 Chris Jones 0.5%
48
- 4 Max Edmands 0.5%
49
- 4 David da Silva 0.5%
50
- 4 Veselin 0.5%
51
- 4 josher19 0.5%
52
- 4 John Firebaugh 0.5%
53
- 4 Nick Heiner 0.5%
54
- 3 Andrei Neculau 0.3%
55
- 3 Duncan Beevers 0.3%
43
+ 5 Scott Nonnenberg 0.6%
44
+ 5 Juliusz Gonera 0.6%
45
+ 5 Jo Liss 0.6%
46
+ 4 Jérémie Astori 0.4%
47
+ 4 John Firebaugh 0.4%
48
+ 4 charlierudolph 0.4%
49
+ 4 Veselin 0.4%
50
+ 4 Chris Jones 0.4%
51
+ 4 Nick Heiner 0.4%
52
+ 4 Max Edmands 0.4%
53
+ 4 David da Silva 0.4%
54
+ 4 Kaito Udagawa 0.4%
55
+ 4 josher19 0.4%
56
+ 3 Jordan Harband 0.3%
56
57
  3 Ryunosuke SATO 0.3%
57
58
  3 Jake Rosoman 0.3%
59
+ 3 Duncan Beevers 0.3%
58
60
  3 Jason Karns 0.3%
59
61
  3 Jeff Barczewski 0.3%
62
+ 3 Andrei Neculau 0.3%
63
+ 2 eldritch fossicker 0.2%
64
+ 2 Bartvds 0.2%
65
+ 2 Edwin Shao 0.2%
66
+ 2 Gregg Lind 0.2%
60
67
  2 Jakub Nešetřil 0.2%
61
- 2 Teddy Cross 0.2%
62
68
  2 Roman Masek 0.2%
63
- 2 Gregg Lind 0.2%
64
- 2 Edwin Shao 0.2%
65
- 2 Bartvds 0.2%
66
- 1 toastynerd 0.1%
67
- 1 Anand Patil 0.1%
68
- 1 Benjamin Horsleben 0.1%
69
- 1 Brandon Payton 0.1%
70
- 1 Chasen Le Hara 0.1%
71
- 1 Chris Connelly 0.1%
72
- 1 Chris Thompson 0.1%
73
- 1 Christopher Hiller 0.1%
74
- 1 Chun-Yi 0.1%
75
- 1 DD 0.1%
76
- 1 Danilo Vaz 0.1%
77
- 1 Dido Arellano 0.1%
78
- 1 Jeff Welch 0.1%
69
+ 2 Teddy Cross 0.2%
79
70
  1 Jesse McCarthy 0.1%
80
- 1 Julien Wajsberg 0.1%
71
+ 1 Doug Neiner 0.1%
72
+ 1 Dido Arellano 0.1%
81
73
  1 Kilian Ciuffolo 0.1%
82
74
  1 Luís Cardoso 0.1%
83
75
  1 Martin Middel 0.1%
84
76
  1 Mathias Schreck 0.1%
77
+ 1 Danilo Vaz 0.1%
85
78
  1 Michael Lange 0.1%
79
+ 1 Mitchell Johnson 0.1%
80
+ 1 DD 0.1%
86
81
  1 Niklas Närhinen 0.1%
87
82
  1 Paul Miller 0.1%
88
83
  1 Refael Ackermann 0.1%
84
+ 1 shinnn 0.1%
85
+ 1 Chun-Yi 0.1%
86
+ 1 Christopher Hiller 0.1%
89
87
  1 Sasha Koss 0.1%
88
+ 1 Chris Thompson 0.1%
89
+ 1 toastynerd 0.1%
90
+ 1 Chris Connelly 0.1%
91
+ 1 Chasen Le Hara 0.1%
90
92
  1 Victor Costan 0.1%
91
93
  1 Vinay Pulim 0.1%
92
94
  1 Virginie BARDALES 0.1%
95
+ 1 Vlad GURDIGA 0.1%
96
+ 1 Brandon Payton 0.1%
97
+ 1 Adam Hull 0.1%
93
98
  1 ericdouglas 0.1%
99
+ 1 Benjamin Horsleben 0.1%
94
100
  1 laconbass 0.1%
101
+ 1 Anand Patil 0.1%
95
102
  1 mohayonao 0.1%
96
103
  1 piecioshka 0.1%
97
- 1 shinnn 0.1%
98
- 1 Adam Hull 0.1%
99
-
104
+ 1 root 0.1%
105
+ 1 Julien Wajsberg 0.1%
106
+ 1 Jeff Welch 0.1%
100
107
 
101
108
  ## License
102
109
 
package/ReleaseNotes.md CHANGED
@@ -1,5 +1,96 @@
1
1
  # Release Notes
2
2
 
3
+ ## 2.3.0 / 2015-04-26
4
+
5
+ Added `ownPropertyDescriptor` assertion:
6
+
7
+ ```js
8
+ expect('test').to.have.ownPropertyDescriptor('length');
9
+ expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 });
10
+ expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 });
11
+ expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false);
12
+ expect('test').ownPropertyDescriptor('length').to.have.keys('value');
13
+ ```
14
+
15
+ ### Community Contributions
16
+
17
+ #### Code Features & Fixes
18
+
19
+ * [#408](https://github.com/chaijs/chai/pull/408) Add `ownPropertyDescriptor`
20
+ assertion.
21
+ By [@ljharb](https://github.com/ljharb)
22
+ * [#422](https://github.com/chaijs/chai/pull/422) Improve ownPropertyDescriptor
23
+ tests.
24
+ By [@ljharb](https://github.com/ljharb)
25
+
26
+ #### Documentation fixes
27
+
28
+ * [#417](https://github.com/chaijs/chai/pull/417) Fix documentation typo
29
+ By [@astorije](https://github.com/astorije)
30
+ * [#423](https://github.com/chaijs/chai/pull/423) Fix inconsistency in docs.
31
+ By [@ehntoo](https://github.com/ehntoo)
32
+
33
+
34
+ ## 2.2.0 / 2015-03-26
35
+
36
+ Deep property strings can now be escaped using `\\` - for example:
37
+
38
+ ```js
39
+ var deepCss = { '.link': { '[target]': 42 }};
40
+ expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42)
41
+ ```
42
+
43
+ ### Community Contributions
44
+
45
+ #### Code Features & Fixes
46
+
47
+ * [#402](https://github.com/chaijs/chai/pull/402) Allow escaping of deep
48
+ property keys.
49
+ By [@umireon](https://github.com/umireon)
50
+
51
+ #### Documentation fixes
52
+
53
+ * [#405](https://github.com/chaijs/chai/pull/405) Tweak documentation around
54
+ deep property escaping.
55
+ By [@keithamus](https://github.com/keithamus)
56
+
57
+
58
+ ## 2.1.2 / 2015-03-15
59
+
60
+ A minor bug fix. No new features.
61
+
62
+ ### Community Contributions
63
+
64
+ #### Code Features & Fixes
65
+
66
+ * [#395](https://github.com/chaijs/chai/pull/395) Fix eval-related bugs with
67
+ assert.operator ([#386](https://github.com/chaijs/chai/pull/386)).
68
+ By [@cjqed](https://github.com/cjqed)
69
+
70
+ ## 2.1.1 / 2015-03-04
71
+
72
+ Two minor bugfixes. No new features.
73
+
74
+ ### Community Contributions
75
+
76
+ #### Code Features & Fixes
77
+
78
+ * [#385](https://github.com/chaijs/chai/pull/385) Fix a bug (also described in
79
+ [#387](https://github.com/chaijs/chai/pull/385)) where `deep.property` would not work with single
80
+ key names. By [@eldritch-fossicker](https://github.com/eldritch-fossicker)
81
+ * [#379](https://github.com/chaijs/chai/pull/379) Fix bug where tools which overwrite
82
+ primitive prototypes, such as Babel or core-js would fail.
83
+ By [@dcneiner](https://github.com/dcneiner)
84
+
85
+ #### Documentation fixes
86
+
87
+ * [#382](https://github.com/chaijs/chai/pull/382) Add doc for showDiff argument in assert.
88
+ By [@astorije](https://github.com/astorije)
89
+ * [#383](https://github.com/chaijs/chai/pull/383) Improve wording for truncateTreshold docs
90
+ By [@gurdiga](https://github.com/gurdiga)
91
+ * [#381](https://github.com/chaijs/chai/pull/381) Improve wording for assert.empty docs
92
+ By [@astorije](https://github.com/astorije)
93
+
3
94
  ## 2.1.0 / 2015-02-23
4
95
 
5
96
  Small release; fixes an issue where the Chai lib was incorrectly reporting the
package/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chai",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic.",
5
5
  "license": "MIT",
6
6
  "keywords": [
package/chai.js CHANGED
@@ -678,7 +678,7 @@ var used = []
678
678
  * Chai version
679
679
  */
680
680
 
681
- exports.version = '2.1.0';
681
+ exports.version = '2.3.0';
682
682
 
683
683
  /*!
684
684
  * Assertion Error
@@ -852,10 +852,11 @@ module.exports = function (_chai, util) {
852
852
  *
853
853
  * @name assert
854
854
  * @param {Philosophical} expression to be tested
855
- * @param {String or Function} message or function that returns message to display if fails
855
+ * @param {String or Function} message or function that returns message to display if expression fails
856
856
  * @param {String or Function} negatedMessage or function that returns negatedMessage to display if negated expression fails
857
857
  * @param {Mixed} expected value (remember to check for negation)
858
858
  * @param {Mixed} actual (optional) will default to `this.obj`
859
+ * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails
859
860
  * @api private
860
861
  */
861
862
 
@@ -932,11 +933,16 @@ module.exports = {
932
933
  * ### config.truncateThreshold
933
934
  *
934
935
  * User configurable property, sets length threshold for actual and
935
- * expected values in assertion errors. If this threshold is exceeded,
936
- * the value is truncated.
936
+ * expected values in assertion errors. If this threshold is exceeded, for
937
+ * example for large data structures, the value is replaced with something
938
+ * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`.
937
939
  *
938
940
  * Set it to zero if you want to disable truncating altogether.
939
941
  *
942
+ * This is especially userful when doing assertions on arrays: having this
943
+ * set to a reasonable large value makes the failure messages readily
944
+ * inspectable.
945
+ *
940
946
  * chai.config.truncateThreshold = 0; // disable truncating
941
947
  *
942
948
  * @param {Number}
@@ -1027,6 +1033,12 @@ module.exports = function (chai, _) {
1027
1033
  * expect({ foo: { bar: { baz: 'quux' } } })
1028
1034
  * .to.have.deep.property('foo.bar.baz', 'quux');
1029
1035
  *
1036
+ * `.deep.property` special characters can be escaped
1037
+ * by adding two slashes before the `.` or `[]`.
1038
+ *
1039
+ * var deepCss = { '.link': { '[target]': 42 }};
1040
+ * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42);
1041
+ *
1030
1042
  * @name deep
1031
1043
  * @api public
1032
1044
  */
@@ -1039,7 +1051,7 @@ module.exports = function (chai, _) {
1039
1051
  * ### .any
1040
1052
  *
1041
1053
  * Sets the `any` flag, (opposite of the `all` flag)
1042
- * later used in the `keys` assertion.
1054
+ * later used in the `keys` assertion.
1043
1055
  *
1044
1056
  * expect(foo).to.have.any.keys('bar', 'baz');
1045
1057
  *
@@ -1056,7 +1068,7 @@ module.exports = function (chai, _) {
1056
1068
  /**
1057
1069
  * ### .all
1058
1070
  *
1059
- * Sets the `all` flag (opposite of the `any` flag)
1071
+ * Sets the `all` flag (opposite of the `any` flag)
1060
1072
  * later used by the `keys` assertion.
1061
1073
  *
1062
1074
  * expect(foo).to.have.all.keys('bar', 'baz');
@@ -1237,7 +1249,7 @@ module.exports = function (chai, _) {
1237
1249
  * Asserts that the target is `null`.
1238
1250
  *
1239
1251
  * expect(null).to.be.null;
1240
- * expect(undefined).not.to.be.null;
1252
+ * expect(undefined).to.not.be.null;
1241
1253
  *
1242
1254
  * @name null
1243
1255
  * @api public
@@ -1300,7 +1312,7 @@ module.exports = function (chai, _) {
1300
1312
  /**
1301
1313
  * ### .empty
1302
1314
  *
1303
- * Asserts that the target's length is `0`. For arrays, it checks
1315
+ * Asserts that the target's length is `0`. For arrays and strings, it checks
1304
1316
  * the `length` property. For objects, it gets the count of
1305
1317
  * enumerable keys.
1306
1318
  *
@@ -1713,7 +1725,7 @@ module.exports = function (chai, _) {
1713
1725
  * green: { tea: 'matcha' }
1714
1726
  * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
1715
1727
  * };
1716
-
1728
+ *
1717
1729
  * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
1718
1730
  * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
1719
1731
  * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
@@ -1745,6 +1757,18 @@ module.exports = function (chai, _) {
1745
1757
  * .with.deep.property('[2]')
1746
1758
  * .that.deep.equals({ tea: 'konacha' });
1747
1759
  *
1760
+ * Note that dots and bracket in `name` must be backslash-escaped when
1761
+ * the `deep` flag is set, while they must NOT be escaped when the `deep`
1762
+ * flag is not set.
1763
+ *
1764
+ * // simple referencing
1765
+ * var css = { '.link[target]': 42 };
1766
+ * expect(css).to.have.property('.link[target]', 42);
1767
+ *
1768
+ * // deep referencing
1769
+ * var deepCss = { '.link': { '[target]': 42 }};
1770
+ * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42);
1771
+ *
1748
1772
  * @name property
1749
1773
  * @alias deep.property
1750
1774
  * @param {String} name
@@ -1822,6 +1846,55 @@ module.exports = function (chai, _) {
1822
1846
  Assertion.addMethod('ownProperty', assertOwnProperty);
1823
1847
  Assertion.addMethod('haveOwnProperty', assertOwnProperty);
1824
1848
 
1849
+ /**
1850
+ * ### .ownPropertyDescriptor(name[, descriptor[, message]])
1851
+ *
1852
+ * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`.
1853
+ *
1854
+ * expect('test').to.have.ownPropertyDescriptor('length');
1855
+ * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 });
1856
+ * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 });
1857
+ * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false);
1858
+ * expect('test').ownPropertyDescriptor('length').to.have.keys('value');
1859
+ *
1860
+ * @name ownPropertyDescriptor
1861
+ * @alias haveOwnPropertyDescriptor
1862
+ * @param {String} name
1863
+ * @param {Object} descriptor _optional_
1864
+ * @param {String} message _optional_
1865
+ * @api public
1866
+ */
1867
+
1868
+ function assertOwnPropertyDescriptor (name, descriptor, msg) {
1869
+ if (typeof descriptor === 'string') {
1870
+ msg = descriptor;
1871
+ descriptor = null;
1872
+ }
1873
+ if (msg) flag(this, 'message', msg);
1874
+ var obj = flag(this, 'object');
1875
+ var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
1876
+ if (actualDescriptor && descriptor) {
1877
+ this.assert(
1878
+ _.eql(descriptor, actualDescriptor)
1879
+ , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)
1880
+ , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)
1881
+ , descriptor
1882
+ , actualDescriptor
1883
+ , true
1884
+ );
1885
+ } else {
1886
+ this.assert(
1887
+ actualDescriptor
1888
+ , 'expected #{this} to have an own property descriptor for ' + _.inspect(name)
1889
+ , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name)
1890
+ );
1891
+ }
1892
+ flag(this, 'object', actualDescriptor);
1893
+ }
1894
+
1895
+ Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor);
1896
+ Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor);
1897
+
1825
1898
  /**
1826
1899
  * ### .length(value)
1827
1900
  *
@@ -1923,30 +1996,30 @@ module.exports = function (chai, _) {
1923
1996
  * ### .keys(key1, [key2], [...])
1924
1997
  *
1925
1998
  * Asserts that the target contains any or all of the passed-in keys.
1926
- * Use in combination with `any`, `all`, `contains`, or `have` will affect
1999
+ * Use in combination with `any`, `all`, `contains`, or `have` will affect
1927
2000
  * what will pass.
1928
- *
1929
- * When used in conjunction with `any`, at least one key that is passed
1930
- * in must exist in the target object. This is regardless whether or not
2001
+ *
2002
+ * When used in conjunction with `any`, at least one key that is passed
2003
+ * in must exist in the target object. This is regardless whether or not
1931
2004
  * the `have` or `contain` qualifiers are used. Note, either `any` or `all`
1932
2005
  * should be used in the assertion. If neither are used, the assertion is
1933
2006
  * defaulted to `all`.
1934
- *
1935
- * When both `all` and `contain` are used, the target object must have at
2007
+ *
2008
+ * When both `all` and `contain` are used, the target object must have at
1936
2009
  * least all of the passed-in keys but may have more keys not listed.
1937
- *
2010
+ *
1938
2011
  * When both `all` and `have` are used, the target object must both contain
1939
2012
  * all of the passed-in keys AND the number of keys in the target object must
1940
- * match the number of keys passed in (in other words, a target object must
2013
+ * match the number of keys passed in (in other words, a target object must
1941
2014
  * have all and only all of the passed-in keys).
1942
- *
2015
+ *
1943
2016
  * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz');
1944
2017
  * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo');
1945
2018
  * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz');
1946
2019
  * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']);
1947
2020
  * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6});
1948
2021
  * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']);
1949
- * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo', 7});
2022
+ * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7});
1950
2023
  * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']);
1951
2024
  * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys([{'bar': 6}}]);
1952
2025
  *
@@ -3494,10 +3567,36 @@ module.exports = function (chai, util) {
3494
3567
  */
3495
3568
 
3496
3569
  assert.operator = function (val, operator, val2, msg) {
3497
- if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) {
3498
- throw new Error('Invalid operator "' + operator + '"');
3570
+ var ok;
3571
+ switch(operator) {
3572
+ case '==':
3573
+ ok = val == val2;
3574
+ break;
3575
+ case '===':
3576
+ ok = val === val2;
3577
+ break;
3578
+ case '>':
3579
+ ok = val > val2;
3580
+ break;
3581
+ case '>=':
3582
+ ok = val >= val2;
3583
+ break;
3584
+ case '<':
3585
+ ok = val < val2;
3586
+ break;
3587
+ case '<=':
3588
+ ok = val <= val2;
3589
+ break;
3590
+ case '!=':
3591
+ ok = val != val2;
3592
+ break;
3593
+ case '!==':
3594
+ ok = val !== val2;
3595
+ break;
3596
+ default:
3597
+ throw new Error('Invalid operator "' + operator + '"');
3499
3598
  }
3500
- var test = new Assertion(eval(val + operator + val2), msg);
3599
+ var test = new Assertion(ok, msg);
3501
3600
  test.assert(
3502
3601
  true === flag(test, 'object')
3503
3602
  , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2)
@@ -3778,10 +3877,8 @@ module.exports = function (chai, util) {
3778
3877
  function loadShould () {
3779
3878
  // explicitly define this method as function as to have it's name to include as `ssfi`
3780
3879
  function shouldGetter() {
3781
- if (this instanceof String || this instanceof Number) {
3782
- return new Assertion(this.constructor(this), null, shouldGetter);
3783
- } else if (this instanceof Boolean) {
3784
- return new Assertion(this == true, null, shouldGetter);
3880
+ if (this instanceof String || this instanceof Number || this instanceof Boolean ) {
3881
+ return new Assertion(this.valueOf(), null, shouldGetter);
3785
3882
  }
3786
3883
  return new Assertion(this, null, shouldGetter);
3787
3884
  }
@@ -4321,7 +4418,7 @@ module.exports = function getPathInfo(path, obj) {
4321
4418
  last = parsed[parsed.length - 1];
4322
4419
 
4323
4420
  var info = {
4324
- parent: _getPathValue(parsed, obj, parsed.length - 1),
4421
+ parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj,
4325
4422
  name: last.p || last.i,
4326
4423
  value: _getPathValue(parsed, obj),
4327
4424
  };
@@ -4343,6 +4440,7 @@ module.exports = function getPathInfo(path, obj) {
4343
4440
  *
4344
4441
  * * Can be as near infinitely deep and nested
4345
4442
  * * Arrays are also valid using the formal `myobject.document[3].property`.
4443
+ * * Literal dots and brackets (not delimiter) must be backslash-escaped.
4346
4444
  *
4347
4445
  * @param {String} path
4348
4446
  * @returns {Object} parsed
@@ -4350,13 +4448,13 @@ module.exports = function getPathInfo(path, obj) {
4350
4448
  */
4351
4449
 
4352
4450
  function parsePath (path) {
4353
- var str = path.replace(/\[/g, '.[')
4451
+ var str = path.replace(/([^\\])\[/g, '$1.[')
4354
4452
  , parts = str.match(/(\\\.|[^.]+?)+/g);
4355
4453
  return parts.map(function (value) {
4356
- var re = /\[(\d+)\]$/
4454
+ var re = /^\[(\d+)\]$/
4357
4455
  , mArr = re.exec(value);
4358
4456
  if (mArr) return { i: parseFloat(mArr[1]) };
4359
- else return { p: value };
4457
+ else return { p: value.replace(/\\([.\[\]])/g, '$1') };
4360
4458
  });
4361
4459
  }
4362
4460
 
@@ -88,10 +88,11 @@ module.exports = function (_chai, util) {
88
88
  *
89
89
  * @name assert
90
90
  * @param {Philosophical} expression to be tested
91
- * @param {String or Function} message or function that returns message to display if fails
91
+ * @param {String or Function} message or function that returns message to display if expression fails
92
92
  * @param {String or Function} negatedMessage or function that returns negatedMessage to display if negated expression fails
93
93
  * @param {Mixed} expected value (remember to check for negation)
94
94
  * @param {Mixed} actual (optional) will default to `this.obj`
95
+ * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails
95
96
  * @api private
96
97
  */
97
98
 
@@ -34,11 +34,16 @@ module.exports = {
34
34
  * ### config.truncateThreshold
35
35
  *
36
36
  * User configurable property, sets length threshold for actual and
37
- * expected values in assertion errors. If this threshold is exceeded,
38
- * the value is truncated.
37
+ * expected values in assertion errors. If this threshold is exceeded, for
38
+ * example for large data structures, the value is replaced with something
39
+ * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`.
39
40
  *
40
41
  * Set it to zero if you want to disable truncating altogether.
41
42
  *
43
+ * This is especially userful when doing assertions on arrays: having this
44
+ * set to a reasonable large value makes the failure messages readily
45
+ * inspectable.
46
+ *
42
47
  * chai.config.truncateThreshold = 0; // disable truncating
43
48
  *
44
49
  * @param {Number}
@@ -75,6 +75,12 @@ module.exports = function (chai, _) {
75
75
  * expect({ foo: { bar: { baz: 'quux' } } })
76
76
  * .to.have.deep.property('foo.bar.baz', 'quux');
77
77
  *
78
+ * `.deep.property` special characters can be escaped
79
+ * by adding two slashes before the `.` or `[]`.
80
+ *
81
+ * var deepCss = { '.link': { '[target]': 42 }};
82
+ * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42);
83
+ *
78
84
  * @name deep
79
85
  * @api public
80
86
  */
@@ -87,7 +93,7 @@ module.exports = function (chai, _) {
87
93
  * ### .any
88
94
  *
89
95
  * Sets the `any` flag, (opposite of the `all` flag)
90
- * later used in the `keys` assertion.
96
+ * later used in the `keys` assertion.
91
97
  *
92
98
  * expect(foo).to.have.any.keys('bar', 'baz');
93
99
  *
@@ -104,7 +110,7 @@ module.exports = function (chai, _) {
104
110
  /**
105
111
  * ### .all
106
112
  *
107
- * Sets the `all` flag (opposite of the `any` flag)
113
+ * Sets the `all` flag (opposite of the `any` flag)
108
114
  * later used by the `keys` assertion.
109
115
  *
110
116
  * expect(foo).to.have.all.keys('bar', 'baz');
@@ -285,7 +291,7 @@ module.exports = function (chai, _) {
285
291
  * Asserts that the target is `null`.
286
292
  *
287
293
  * expect(null).to.be.null;
288
- * expect(undefined).not.to.be.null;
294
+ * expect(undefined).to.not.be.null;
289
295
  *
290
296
  * @name null
291
297
  * @api public
@@ -348,7 +354,7 @@ module.exports = function (chai, _) {
348
354
  /**
349
355
  * ### .empty
350
356
  *
351
- * Asserts that the target's length is `0`. For arrays, it checks
357
+ * Asserts that the target's length is `0`. For arrays and strings, it checks
352
358
  * the `length` property. For objects, it gets the count of
353
359
  * enumerable keys.
354
360
  *
@@ -761,7 +767,7 @@ module.exports = function (chai, _) {
761
767
  * green: { tea: 'matcha' }
762
768
  * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
763
769
  * };
764
-
770
+ *
765
771
  * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
766
772
  * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
767
773
  * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
@@ -793,6 +799,18 @@ module.exports = function (chai, _) {
793
799
  * .with.deep.property('[2]')
794
800
  * .that.deep.equals({ tea: 'konacha' });
795
801
  *
802
+ * Note that dots and bracket in `name` must be backslash-escaped when
803
+ * the `deep` flag is set, while they must NOT be escaped when the `deep`
804
+ * flag is not set.
805
+ *
806
+ * // simple referencing
807
+ * var css = { '.link[target]': 42 };
808
+ * expect(css).to.have.property('.link[target]', 42);
809
+ *
810
+ * // deep referencing
811
+ * var deepCss = { '.link': { '[target]': 42 }};
812
+ * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42);
813
+ *
796
814
  * @name property
797
815
  * @alias deep.property
798
816
  * @param {String} name
@@ -870,6 +888,55 @@ module.exports = function (chai, _) {
870
888
  Assertion.addMethod('ownProperty', assertOwnProperty);
871
889
  Assertion.addMethod('haveOwnProperty', assertOwnProperty);
872
890
 
891
+ /**
892
+ * ### .ownPropertyDescriptor(name[, descriptor[, message]])
893
+ *
894
+ * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`.
895
+ *
896
+ * expect('test').to.have.ownPropertyDescriptor('length');
897
+ * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 });
898
+ * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 });
899
+ * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false);
900
+ * expect('test').ownPropertyDescriptor('length').to.have.keys('value');
901
+ *
902
+ * @name ownPropertyDescriptor
903
+ * @alias haveOwnPropertyDescriptor
904
+ * @param {String} name
905
+ * @param {Object} descriptor _optional_
906
+ * @param {String} message _optional_
907
+ * @api public
908
+ */
909
+
910
+ function assertOwnPropertyDescriptor (name, descriptor, msg) {
911
+ if (typeof descriptor === 'string') {
912
+ msg = descriptor;
913
+ descriptor = null;
914
+ }
915
+ if (msg) flag(this, 'message', msg);
916
+ var obj = flag(this, 'object');
917
+ var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
918
+ if (actualDescriptor && descriptor) {
919
+ this.assert(
920
+ _.eql(descriptor, actualDescriptor)
921
+ , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)
922
+ , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)
923
+ , descriptor
924
+ , actualDescriptor
925
+ , true
926
+ );
927
+ } else {
928
+ this.assert(
929
+ actualDescriptor
930
+ , 'expected #{this} to have an own property descriptor for ' + _.inspect(name)
931
+ , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name)
932
+ );
933
+ }
934
+ flag(this, 'object', actualDescriptor);
935
+ }
936
+
937
+ Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor);
938
+ Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor);
939
+
873
940
  /**
874
941
  * ### .length(value)
875
942
  *
@@ -971,30 +1038,30 @@ module.exports = function (chai, _) {
971
1038
  * ### .keys(key1, [key2], [...])
972
1039
  *
973
1040
  * Asserts that the target contains any or all of the passed-in keys.
974
- * Use in combination with `any`, `all`, `contains`, or `have` will affect
1041
+ * Use in combination with `any`, `all`, `contains`, or `have` will affect
975
1042
  * what will pass.
976
- *
977
- * When used in conjunction with `any`, at least one key that is passed
978
- * in must exist in the target object. This is regardless whether or not
1043
+ *
1044
+ * When used in conjunction with `any`, at least one key that is passed
1045
+ * in must exist in the target object. This is regardless whether or not
979
1046
  * the `have` or `contain` qualifiers are used. Note, either `any` or `all`
980
1047
  * should be used in the assertion. If neither are used, the assertion is
981
1048
  * defaulted to `all`.
982
- *
983
- * When both `all` and `contain` are used, the target object must have at
1049
+ *
1050
+ * When both `all` and `contain` are used, the target object must have at
984
1051
  * least all of the passed-in keys but may have more keys not listed.
985
- *
1052
+ *
986
1053
  * When both `all` and `have` are used, the target object must both contain
987
1054
  * all of the passed-in keys AND the number of keys in the target object must
988
- * match the number of keys passed in (in other words, a target object must
1055
+ * match the number of keys passed in (in other words, a target object must
989
1056
  * have all and only all of the passed-in keys).
990
- *
1057
+ *
991
1058
  * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz');
992
1059
  * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo');
993
1060
  * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz');
994
1061
  * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']);
995
1062
  * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6});
996
1063
  * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']);
997
- * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo', 7});
1064
+ * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7});
998
1065
  * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']);
999
1066
  * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys([{'bar': 6}}]);
1000
1067
  *
@@ -1004,10 +1004,36 @@ module.exports = function (chai, util) {
1004
1004
  */
1005
1005
 
1006
1006
  assert.operator = function (val, operator, val2, msg) {
1007
- if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) {
1008
- throw new Error('Invalid operator "' + operator + '"');
1007
+ var ok;
1008
+ switch(operator) {
1009
+ case '==':
1010
+ ok = val == val2;
1011
+ break;
1012
+ case '===':
1013
+ ok = val === val2;
1014
+ break;
1015
+ case '>':
1016
+ ok = val > val2;
1017
+ break;
1018
+ case '>=':
1019
+ ok = val >= val2;
1020
+ break;
1021
+ case '<':
1022
+ ok = val < val2;
1023
+ break;
1024
+ case '<=':
1025
+ ok = val <= val2;
1026
+ break;
1027
+ case '!=':
1028
+ ok = val != val2;
1029
+ break;
1030
+ case '!==':
1031
+ ok = val !== val2;
1032
+ break;
1033
+ default:
1034
+ throw new Error('Invalid operator "' + operator + '"');
1009
1035
  }
1010
- var test = new Assertion(eval(val + operator + val2), msg);
1036
+ var test = new Assertion(ok, msg);
1011
1037
  test.assert(
1012
1038
  true === flag(test, 'object')
1013
1039
  , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2)
@@ -10,10 +10,8 @@ module.exports = function (chai, util) {
10
10
  function loadShould () {
11
11
  // explicitly define this method as function as to have it's name to include as `ssfi`
12
12
  function shouldGetter() {
13
- if (this instanceof String || this instanceof Number) {
14
- return new Assertion(this.constructor(this), null, shouldGetter);
15
- } else if (this instanceof Boolean) {
16
- return new Assertion(this == true, null, shouldGetter);
13
+ if (this instanceof String || this instanceof Number || this instanceof Boolean ) {
14
+ return new Assertion(this.valueOf(), null, shouldGetter);
17
15
  }
18
16
  return new Assertion(this, null, shouldGetter);
19
17
  }
@@ -32,7 +32,7 @@ module.exports = function getPathInfo(path, obj) {
32
32
  last = parsed[parsed.length - 1];
33
33
 
34
34
  var info = {
35
- parent: _getPathValue(parsed, obj, parsed.length - 1),
35
+ parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj,
36
36
  name: last.p || last.i,
37
37
  value: _getPathValue(parsed, obj),
38
38
  };
@@ -54,6 +54,7 @@ module.exports = function getPathInfo(path, obj) {
54
54
  *
55
55
  * * Can be as near infinitely deep and nested
56
56
  * * Arrays are also valid using the formal `myobject.document[3].property`.
57
+ * * Literal dots and brackets (not delimiter) must be backslash-escaped.
57
58
  *
58
59
  * @param {String} path
59
60
  * @returns {Object} parsed
@@ -61,13 +62,13 @@ module.exports = function getPathInfo(path, obj) {
61
62
  */
62
63
 
63
64
  function parsePath (path) {
64
- var str = path.replace(/\[/g, '.[')
65
+ var str = path.replace(/([^\\])\[/g, '$1.[')
65
66
  , parts = str.match(/(\\\.|[^.]+?)+/g);
66
67
  return parts.map(function (value) {
67
- var re = /\[(\d+)\]$/
68
+ var re = /^\[(\d+)\]$/
68
69
  , mArr = re.exec(value);
69
70
  if (mArr) return { i: parseFloat(mArr[1]) };
70
- else return { p: value };
71
+ else return { p: value.replace(/\\([.\[\]])/g, '$1') };
71
72
  });
72
73
  }
73
74
 
package/lib/chai.js CHANGED
@@ -11,7 +11,7 @@ var used = []
11
11
  * Chai version
12
12
  */
13
13
 
14
- exports.version = '2.1.0';
14
+ exports.version = '2.3.0';
15
15
 
16
16
  /*!
17
17
  * Assertion Error
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "Veselin Todorov <hi@vesln.com>",
18
18
  "John Firebaugh <john.firebaugh@gmail.com>"
19
19
  ],
20
- "version": "2.1.0",
20
+ "version": "2.3.0",
21
21
  "repository": {
22
22
  "type": "git",
23
23
  "url": "https://github.com/chaijs/chai"
@@ -42,6 +42,7 @@
42
42
  "karma-mocha": "*",
43
43
  "karma-sauce-launcher": "0.2.x",
44
44
  "karma-phantomjs-launcher": "0.1.1",
45
+ "karma-firefox-launcher": "^0.1.4",
45
46
  "mocha": "1.21.x",
46
47
  "istanbul": "0.2.x"
47
48
  }