diff --git a/packages/jest-jasmine2/src/jest-expect.js b/packages/jest-jasmine2/src/jest-expect.js index 87958d38f348..e6105a249044 100644 --- a/packages/jest-jasmine2/src/jest-expect.js +++ b/packages/jest-jasmine2/src/jest-expect.js @@ -48,6 +48,14 @@ module.exports = (config: Config) => { }; }); - global.expect.extend(jestMatchersObject); + const expect = global.expect; + + expect.anything = jasmine.anything; + expect.any = jasmine.any; + expect.objectContaining = jasmine.objectContaining; + expect.arrayContaining = jasmine.arrayContaining; + expect.stringMatching = jasmine.stringMatching; + + expect.extend(jestMatchersObject); }; }; diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index 0c25a28f033d..e223d06d6e6b 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -12,7 +12,6 @@ const chalk = require('chalk'); const prettyFormat = require('pretty-format'); -const equals = require('./equals'); export type ValueType = | 'array' @@ -192,7 +191,6 @@ module.exports = { ensureExpectedIsNumber, ensureNoExpected, ensureNumbers, - equals, getType, matcherHint, pluralize, diff --git a/packages/jest-matchers/package.json b/packages/jest-matchers/package.json index 00374ed61e85..f2221ddb6024 100644 --- a/packages/jest-matchers/package.json +++ b/packages/jest-matchers/package.json @@ -10,7 +10,8 @@ "dependencies": { "jest-diff": "^18.0.0", "jest-matcher-utils": "^18.0.0", - "jest-util": "^18.0.0" + "jest-util": "^18.0.0", + "pretty-format": "^18.0.0" }, "scripts": { "test": "../../packages/jest-cli/bin/jest.js" diff --git a/packages/jest-matchers/src/index.js b/packages/jest-matchers/src/index.js index 7a68703a50d1..da5da68ee44b 100644 --- a/packages/jest-matchers/src/index.js +++ b/packages/jest-matchers/src/index.js @@ -26,6 +26,13 @@ const spyMatchers = require('./spyMatchers'); const toThrowMatchers = require('./toThrowMatchers'); const utils = require('jest-matcher-utils'); +const { + any, + anything, + arrayContaining, + objectContaining, + stringMatching, +} = require('./jasmine-utils'); const GLOBAL_STATE = Symbol.for('$$jest-matchers-object'); @@ -136,11 +143,11 @@ expect.extend = (matchersObj: MatchersObject): void => { Object.assign(global[GLOBAL_STATE].matchers, matchersObj); }; -expect.anything = global.jasmine.anything; -expect.any = global.jasmine.any; -expect.objectContaining = global.jasmine.objectContaining; -expect.arrayContaining = global.jasmine.arrayContaining; -expect.stringMatching = global.jasmine.stringMatching; +expect.anything = anything; +expect.any = any; +expect.objectContaining = objectContaining; +expect.arrayContaining = arrayContaining; +expect.stringMatching = stringMatching; const _validateResult = result => { if ( diff --git a/packages/jest-matcher-utils/src/equals.js b/packages/jest-matchers/src/jasmine-utils.js similarity index 63% rename from packages/jest-matcher-utils/src/equals.js rename to packages/jest-matchers/src/jasmine-utils.js index 3c6575f77c45..8868f2216e49 100644 --- a/packages/jest-matcher-utils/src/equals.js +++ b/packages/jest-matchers/src/jasmine-utils.js @@ -25,12 +25,31 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; +const prettyFormat = require('pretty-format'); + // Extracted out of jasmine 2.5.2 function equals(a, b, customTesters) { customTesters = customTesters || []; return eq(a, b, [], [], customTesters); } +function contains(haystack, needle, customTesters) { + customTesters = customTesters || []; + + if ((Object.prototype.toString.apply(haystack) === '[object Array]') || + (!!haystack && !haystack.indexOf)) + { + for (var i = 0; i < haystack.length; i++) { + if (eq(haystack[i], needle, [], [], customTesters)) { + return true; + } + } + return false; + } + + return !!haystack && haystack.indexOf(needle) >= 0; +} + function isAsymmetric(obj) { return obj && isA('Function', obj.asymmetricMatch); } @@ -252,4 +271,176 @@ function isDomNode(obj) { return obj.nodeType > 0; } -module.exports = equals; +function fnNameFor(func) { + if (func.name) { + return func.name; + } + + var matches = func.toString().match(/^\s*function\s*(\w*)\s*\(/); + return matches ? matches[1] : ''; +} + + +function Any(expectedObject) { + if (typeof expectedObject === 'undefined') { + throw new TypeError( + 'jasmine.any() expects to be passed a constructor function. ' + + 'Please pass one or use jasmine.anything() to match any object.' + ); + } + this.expectedObject = expectedObject; +} + +function any(expectedObject) { + return new Any(expectedObject); +} + +Any.prototype.asymmetricMatch = function(other) { + if (this.expectedObject == String) { + return typeof other == 'string' || other instanceof String; + } + + if (this.expectedObject == Number) { + return typeof other == 'number' || other instanceof Number; + } + + if (this.expectedObject == Function) { + return typeof other == 'function' || other instanceof Function; + } + + if (this.expectedObject == Object) { + return typeof other == 'object'; + } + + if (this.expectedObject == Boolean) { + return typeof other == 'boolean'; + } + + return other instanceof this.expectedObject; +}; + +Any.prototype.jasmineToString = function() { + return ''; +}; + + +function Anything() {} + +function anything() { + return new Anything(); +} + +Anything.prototype.asymmetricMatch = function(other) { + return !isUndefined(other) && other !== null; +}; + +Anything.prototype.jasmineToString = function() { + return ''; +}; + + +function ArrayContaining(sample) { + this.sample = sample; +} + +function arrayContaining(sample) { + return new ArrayContaining(sample); +} + +ArrayContaining.prototype.asymmetricMatch = function(other) { + var className = Object.prototype.toString.call(this.sample); + if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); } + + for (var i = 0; i < this.sample.length; i++) { + var item = this.sample[i]; + if (!contains(other, item)) { + return false; + } + } + + return true; +}; + +ArrayContaining.prototype.jasmineToString = function () { + return ''; +}; + + +function ObjectContaining(sample) { + this.sample = sample; +} + +function objectContaining(sample) { + return new ObjectContaining(sample); +} + +function getPrototype(obj) { + if (Object.getPrototypeOf) { + return Object.getPrototypeOf(obj); + } + + if (obj.constructor.prototype == obj) { + return null; + } + + return obj.constructor.prototype; +} + +function hasProperty(obj, property) { + if (!obj) { + return false; + } + + if (Object.prototype.hasOwnProperty.call(obj, property)) { + return true; + } + + return hasProperty(getPrototype(obj), property); +} + +ObjectContaining.prototype.asymmetricMatch = function(other) { + if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); } + + for (var property in this.sample) { + if (!hasProperty(other, property) || + !equals(this.sample[property], other[property])) { + return false; + } + } + + return true; +}; + +ObjectContaining.prototype.jasmineToString = function() { + return ''; +}; + + +function StringMatching(expected) { + if (!isA('String', expected) && !isA('RegExp', expected)) { + throw new Error('Expected is not a String or a RegExp'); + } + + this.regexp = new RegExp(expected); +} + +function stringMatching(expected) { + return new StringMatching(expected); +} + +StringMatching.prototype.asymmetricMatch = function(other) { + return this.regexp.test(other); +}; + +StringMatching.prototype.jasmineToString = function() { + return ''; +}; + +module.exports = { + any, + anything, + arrayContaining, + equals, + objectContaining, + stringMatching, +}; diff --git a/packages/jest-matchers/src/matchers.js b/packages/jest-matchers/src/matchers.js index 2b19fc4e5323..3885b41a7218 100644 --- a/packages/jest-matchers/src/matchers.js +++ b/packages/jest-matchers/src/matchers.js @@ -28,8 +28,10 @@ const { printReceived, printExpected, printWithType, - equals, } = require('jest-matcher-utils'); +const { + equals, +} = require('./jasmine-utils'); type ContainIterable = ( Array | diff --git a/packages/jest-matchers/src/spyMatchers.js b/packages/jest-matchers/src/spyMatchers.js index efe4b93c6b1b..61ebf140f26d 100644 --- a/packages/jest-matchers/src/spyMatchers.js +++ b/packages/jest-matchers/src/spyMatchers.js @@ -24,8 +24,10 @@ const { printReceived, printWithType, RECEIVED_COLOR, - equals, } = require('jest-matcher-utils'); +const { + equals, +} = require('./jasmine-utils'); const RECEIVED_NAME = { 'mock function': 'jest.fn()', diff --git a/packages/jest-matchers/src/toThrowMatchers.js b/packages/jest-matchers/src/toThrowMatchers.js index 2e00b78c9f92..b3268231bcb4 100644 --- a/packages/jest-matchers/src/toThrowMatchers.js +++ b/packages/jest-matchers/src/toThrowMatchers.js @@ -24,8 +24,10 @@ const { matcherHint, printExpected, printWithType, - equals, } = require('jest-matcher-utils'); +const { + equals, +} = require('./jasmine-utils'); const createMatcher = matcherName => (actual: Function, expected: string | Error | RegExp) => {