From 2173e6378cccf7cdf6a64b3b27acdaf11dd244c9 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Thu, 26 Mar 2015 18:03:02 +0000 Subject: [PATCH] Release v2.2.0 --- History.md | 11 ++++++ ReleaseNotes.md | 24 +++++++++++++ bower.json | 2 +- chai.js | 93 ++++++++++++++++++++++++++++++++++++------------- component.json | 2 +- lib/chai.js | 2 +- package.json | 2 +- 7 files changed, 108 insertions(+), 28 deletions(-) diff --git a/History.md b/History.md index a6c9d2686..45e352e25 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,14 @@ +2.2.0 / 2015-03-26 +================== + + * Merge pull request #405 from chaijs/deep-escape-doc-tweaks + * Tweak documentation on `.deep` flag. + * Merge pull request #402 from umireon/escaping-dot-should-be-taken + * Documentation of escaping in `.deep` flag. + * take regular expression apart + * Feature: backslash-escaping in `.deep.property` + * Escaping dot should be taken in deep property + 2.1.2 / 2015-03-15 ================== diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 0fb641935..ffa6027f3 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,29 @@ # Release Notes +## 2.2.0 / 2015-03-26 + +Deep property strings can now be escaped using `\\` - for example: + +```js +var deepCss = { '.link': { '[target]': 42 }}; +expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42) +``` + +### Community Contributions + +#### Code Features & Fixes + + * [#402](https://github.com/chaijs/chai/pull/402) Allow escaping of deep + property keys. + By [@umireon](https://github.com/umireon) + +#### Documentation fixes + + * [#405](https://github.com/chaijs/chai/pull/405) Tweak documentation around + deep property escaping. + By [@keithamus](https://github.com/keithamus) + + ## 2.1.2 / 2015-03-15 A minor bug fix. No new features. diff --git a/bower.json b/bower.json index 8f50f57ac..8465f5d9d 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "chai", - "version": "2.1.2", + "version": "2.2.0", "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic.", "license": "MIT", "keywords": [ diff --git a/chai.js b/chai.js index fb6b55da2..8139cd164 100644 --- a/chai.js +++ b/chai.js @@ -56,11 +56,11 @@ require.helper.semVerSort = function(a, b) { /** * Find and require a module which name starts with the provided name. - * If multiple modules exists, the highest semver is used. + * If multiple modules exists, the highest semver is used. * This function can only be used for remote dependencies. * @param {String} name - module name: `user~repo` - * @param {Boolean} returnPath - returns the canonical require path if true, + * @param {Boolean} returnPath - returns the canonical require path if true, * otherwise it returns the epxorted module */ require.latest = function (name, returnPath) { @@ -83,7 +83,7 @@ require.latest = function (name, returnPath) { semVerCandidates.push({version: version, name: moduleName}); } else { otherCandidates.push({version: version, name: moduleName}); - } + } } } if (semVerCandidates.concat(otherCandidates).length === 0) { @@ -678,7 +678,7 @@ var used = [] * Chai version */ -exports.version = '2.1.2'; +exports.version = '2.2.0'; /*! * Assertion Error @@ -1033,6 +1033,12 @@ module.exports = function (chai, _) { * expect({ foo: { bar: { baz: 'quux' } } }) * .to.have.deep.property('foo.bar.baz', 'quux'); * + * `.deep.property` special characters can be escaped + * by adding two slashes before the `.` or `[]`. + * + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * * @name deep * @api public */ @@ -1045,7 +1051,7 @@ module.exports = function (chai, _) { * ### .any * * Sets the `any` flag, (opposite of the `all` flag) - * later used in the `keys` assertion. + * later used in the `keys` assertion. * * expect(foo).to.have.any.keys('bar', 'baz'); * @@ -1062,7 +1068,7 @@ module.exports = function (chai, _) { /** * ### .all * - * Sets the `all` flag (opposite of the `any` flag) + * Sets the `all` flag (opposite of the `any` flag) * later used by the `keys` assertion. * * expect(foo).to.have.all.keys('bar', 'baz'); @@ -1719,7 +1725,7 @@ module.exports = function (chai, _) { * green: { tea: 'matcha' } * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] * }; - + * * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); @@ -1751,6 +1757,18 @@ module.exports = function (chai, _) { * .with.deep.property('[2]') * .that.deep.equals({ tea: 'konacha' }); * + * Note that dots and bracket in `name` must be backslash-escaped when + * the `deep` flag is set, while they must NOT be escaped when the `deep` + * flag is not set. + * + * // simple referencing + * var css = { '.link[target]': 42 }; + * expect(css).to.have.property('.link[target]', 42); + * + * // deep referencing + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * * @name property * @alias deep.property * @param {String} name @@ -1929,23 +1947,23 @@ module.exports = function (chai, _) { * ### .keys(key1, [key2], [...]) * * Asserts that the target contains any or all of the passed-in keys. - * Use in combination with `any`, `all`, `contains`, or `have` will affect + * Use in combination with `any`, `all`, `contains`, or `have` will affect * what will pass. - * - * When used in conjunction with `any`, at least one key that is passed - * in must exist in the target object. This is regardless whether or not + * + * When used in conjunction with `any`, at least one key that is passed + * in must exist in the target object. This is regardless whether or not * the `have` or `contain` qualifiers are used. Note, either `any` or `all` * should be used in the assertion. If neither are used, the assertion is * defaulted to `all`. - * - * When both `all` and `contain` are used, the target object must have at + * + * When both `all` and `contain` are used, the target object must have at * least all of the passed-in keys but may have more keys not listed. - * + * * When both `all` and `have` are used, the target object must both contain * all of the passed-in keys AND the number of keys in the target object must - * match the number of keys passed in (in other words, a target object must + * match the number of keys passed in (in other words, a target object must * have all and only all of the passed-in keys). - * + * * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); @@ -3500,10 +3518,36 @@ module.exports = function (chai, util) { */ assert.operator = function (val, operator, val2, msg) { - if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) { - throw new Error('Invalid operator "' + operator + '"'); + var ok; + switch(operator) { + case '==': + ok = val == val2; + break; + case '===': + ok = val === val2; + break; + case '>': + ok = val > val2; + break; + case '>=': + ok = val >= val2; + break; + case '<': + ok = val < val2; + break; + case '<=': + ok = val <= val2; + break; + case '!=': + ok = val != val2; + break; + case '!==': + ok = val !== val2; + break; + default: + throw new Error('Invalid operator "' + operator + '"'); } - var test = new Assertion(eval(val + operator + val2), msg); + var test = new Assertion(ok, msg); test.assert( true === flag(test, 'object') , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) @@ -4286,7 +4330,7 @@ var getPathInfo = require('chai/lib/chai/utils/getPathInfo.js'); module.exports = function(path, obj) { var info = getPathInfo(path, obj); return info.value; -}; +}; }); @@ -4347,6 +4391,7 @@ module.exports = function getPathInfo(path, obj) { * * * Can be as near infinitely deep and nested * * Arrays are also valid using the formal `myobject.document[3].property`. + * * Literal dots and brackets (not delimiter) must be backslash-escaped. * * @param {String} path * @returns {Object} parsed @@ -4354,13 +4399,13 @@ module.exports = function getPathInfo(path, obj) { */ function parsePath (path) { - var str = path.replace(/\[/g, '.[') + var str = path.replace(/([^\\])\[/g, '$1.[') , parts = str.match(/(\\\.|[^.]+?)+/g); return parts.map(function (value) { - var re = /\[(\d+)\]$/ + var re = /^\[(\d+)\]$/ , mArr = re.exec(value); if (mArr) return { i: parseFloat(mArr[1]) }; - else return { p: value }; + else return { p: value.replace(/\\([.\[\]])/g, '$1') }; }); } @@ -4432,7 +4477,7 @@ var type = require('chai/lib/chai/utils/type.js'); * hasProperty('str', obj); // true * hasProperty('constructor', obj); // true * hasProperty('bar', obj); // false - * + * * hasProperty('length', obj.str); // true * hasProperty(1, obj.str); // true * hasProperty(5, obj.str); // false diff --git a/component.json b/component.json index 1248bbfb1..744a7868a 100644 --- a/component.json +++ b/component.json @@ -1,7 +1,7 @@ { "name": "chai" , "repo": "chaijs/chai" - , "version": "2.1.2" + , "version": "2.2.0" , "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic." , "license": "MIT" , "keywords": [ diff --git a/lib/chai.js b/lib/chai.js index 0afc4ced4..4a9ae2403 100644 --- a/lib/chai.js +++ b/lib/chai.js @@ -11,7 +11,7 @@ var used = [] * Chai version */ -exports.version = '2.1.2'; +exports.version = '2.2.0'; /*! * Assertion Error diff --git a/package.json b/package.json index d569139aa..5d4640d2f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "Veselin Todorov ", "John Firebaugh " ], - "version": "2.1.2", + "version": "2.2.0", "repository": { "type": "git", "url": "https://github.com/chaijs/chai"