UNPKG

e-lado

Version:

[![CircleCI](https://circleci.com/gh/sharetribe/sharetribe/tree/master.svg?style=svg)](https://circleci.com/gh/sharetribe/sharetribe/tree/master) [![Dependency Status](https://gemnasium.com/sharetribe/sharetribe.png)](https://gemnasium.com/sharetribe/shar

670 lines (553 loc) 22.2 kB
/** * Copyright (c) 2014, Facebook, Inc. All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * */ /* eslint-disable max-len */ 'use strict'; const diff = require('jest-diff');var _require = require('jest-util');const escapeStrForRegex = _require.escapeStrForRegex;var _require2 = require('./utils');const getPath = _require2.getPath;var _require3 = require('jest-matcher-utils');const EXPECTED_COLOR = _require3.EXPECTED_COLOR,RECEIVED_COLOR = _require3.RECEIVED_COLOR,ensureNoExpected = _require3.ensureNoExpected,ensureNumbers = _require3.ensureNumbers,getType = _require3.getType,matcherHint = _require3.matcherHint,printReceived = _require3.printReceived,printExpected = _require3.printExpected,printWithType = _require3.printWithType;var _require4 = require('./jasmine-utils');const equals = _require4.equals; const IteratorSymbol = Symbol.iterator; const hasIterator = object => !!(object != null && object[IteratorSymbol]); const iterableEquality = (a, b) => { if ( typeof a !== 'object' || typeof b !== 'object' || Array.isArray(a) || Array.isArray(b) || !hasIterator(a) || !hasIterator(b)) { return undefined; } if (a.constructor !== b.constructor) { return false; } const bIterator = b[IteratorSymbol](); for (const aValue of a) { const nextB = bIterator.next(); if ( nextB.done || !equals( aValue, nextB.value, [iterableEquality])) { return false; } } if (!bIterator.next().done) { return false; } return true; }; const matchers = { toBe(received, expected) { const pass = received === expected; const message = pass ? () => matcherHint('.not.toBe') + '\n\n' + `Expected value to not be (using ===):\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(received) }` : () => { const diffString = diff(expected, received, { expand: this.expand }); return matcherHint('.toBe') + '\n\n' + `Expected value to be (using ===):\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(received) }` + ( diffString ? `\n\nDifference:\n\n${ diffString }` : ''); }; // Passing the the actual and expected objects so that a custom reporter // could access them, for example in order to display a custom visual diff, // or create a different error message return { actual: received, expected, message, name: 'toBe', pass }; }, toBeCloseTo( actual, expected) {let precision = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 2; ensureNumbers(actual, expected, '.toBeCloseTo'); const pass = Math.abs(expected - actual) < Math.pow(10, -precision) / 2; const message = pass ? () => matcherHint('.not.toBeCloseTo', 'received', 'expected, precision') + '\n\n' + `Expected value not to be close to (with ${ printExpected(precision) }-digit precision):\n` + ` ${ printExpected(expected) }\n` + `Received: \n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeCloseTo', 'received', 'expected, precision') + '\n\n' + `Expected value to be close to (with ${ printExpected(precision) }-digit precision):\n` + ` ${ printExpected(expected) }\n` + `Received: \n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeDefined(actual, expected) { ensureNoExpected(expected, '.toBeDefined'); const pass = actual !== void 0; const message = pass ? () => matcherHint('.not.toBeDefined', 'received', '') + '\n\n' + `Expected value not to be defined, instead received\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeDefined', 'received', '') + '\n\n' + `Expected value to be defined, instead received\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeFalsy(actual, expected) { ensureNoExpected(expected, '.toBeFalsy'); const pass = !actual; const message = pass ? () => matcherHint('.not.toBeFalsy', 'received', '') + '\n\n' + `Expected value not to be falsy, instead received\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeFalsy', 'received', '') + '\n\n' + `Expected value to be falsy, instead received\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeGreaterThan(actual, expected) { ensureNumbers(actual, expected, '.toBeGreaterThan'); const pass = actual > expected; const message = pass ? () => matcherHint('.not.toBeGreaterThan') + '\n\n' + `Expected value not to be greater than:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeGreaterThan') + '\n\n' + `Expected value to be greater than:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeGreaterThanOrEqual(actual, expected) { ensureNumbers(actual, expected, '.toBeGreaterThanOrEqual'); const pass = actual >= expected; const message = pass ? () => matcherHint('.not.toBeGreaterThanOrEqual') + '\n\n' + `Expected value not to be greater than or equal:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeGreaterThanOrEqual') + '\n\n' + `Expected value to be greater than or equal:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeInstanceOf(received, constructor) { const constType = getType(constructor); if (constType !== 'function') { throw new Error( matcherHint('[.not].toBeInstanceOf', 'value', 'constructor') + `\n\n` + `Expected constructor to be a function. Instead got:\n` + ` ${ printExpected(constType) }`); } const pass = received instanceof constructor; const message = pass ? () => matcherHint('.not.toBeInstanceOf', 'value', 'constructor') + '\n\n' + `Expected value not to be an instance of:\n` + ` ${ printExpected(constructor.name || constructor) }\n` + `Received:\n` + ` ${ printReceived(received) }\n` : () => matcherHint('.toBeInstanceOf', 'value', 'constructor') + '\n\n' + `Expected value to be an instance of:\n` + ` ${ printExpected(constructor.name || constructor) }\n` + `Received:\n` + ` ${ printReceived(received) }\n` + `Constructor:\n` + ` ${ printReceived(received.constructor && received.constructor.name) }`; return { message, pass }; }, toBeLessThan(actual, expected) { ensureNumbers(actual, expected, '.toBeLessThan'); const pass = actual < expected; const message = pass ? () => matcherHint('.not.toBeLessThan') + '\n\n' + `Expected value not to be less than:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeLessThan') + '\n\n' + `Expected value to be less than:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeLessThanOrEqual(actual, expected) { ensureNumbers(actual, expected, '.toBeLessThanOrEqual'); const pass = actual <= expected; const message = pass ? () => matcherHint('.not.toBeLessThanOrEqual') + '\n\n' + `Expected value not to be less than or equal:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeLessThanOrEqual') + '\n\n' + `Expected value to be less than or equal:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeNaN(actual, expected) { ensureNoExpected(expected, '.toBeNaN'); const pass = Number.isNaN(actual); const message = pass ? () => matcherHint('.not.toBeNaN', 'received', '') + '\n\n' + `Expected value not to be NaN, instead received\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeNaN', 'received', '') + '\n\n' + `Expected value to be NaN, instead received\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeNull(actual, expected) { ensureNoExpected(expected, '.toBeNull'); const pass = actual === null; const message = pass ? () => matcherHint('.not.toBeNull', 'received', '') + '\n\n' + `Expected value not to be null, instead received\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeNull', 'received', '') + '\n\n' + `Expected value to be null, instead received\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeTruthy(actual, expected) { ensureNoExpected(expected, '.toBeTruthy'); const pass = !!actual; const message = pass ? () => matcherHint('.not.toBeTruthy', 'received', '') + '\n\n' + `Expected value not to be truthy, instead received\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeTruthy', 'received', '') + '\n\n' + `Expected value to be truthy, instead received\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toBeUndefined(actual, expected) { ensureNoExpected(expected, '.toBeUndefined'); const pass = actual === void 0; const message = pass ? () => matcherHint('.not.toBeUndefined', 'received', '') + '\n\n' + `Expected value not to be undefined, instead received\n` + ` ${ printReceived(actual) }` : () => matcherHint('.toBeUndefined', 'received', '') + '\n\n' + `Expected value to be undefined, instead received\n` + ` ${ printReceived(actual) }`; return { message, pass }; }, toContain(collection, value) { const collectionType = getType(collection); let converted = null; if (Array.isArray(collection) || typeof collection === 'string') { // strings have `indexOf` so we don't need to convert // arrays have `indexOf` and we don't want to make a copy converted = collection; } else { try { converted = Array.from(collection); } catch (e) { throw new Error( matcherHint('[.not].toContainEqual', 'collection', 'value') + '\n\n' + `Expected ${ RECEIVED_COLOR('collection') } to be an array-like structure.\n` + printWithType('Received', collection, printReceived)); } } // At this point, we're either a string or an Array, // which was converted from an array-like structure. const pass = converted.indexOf(value) != -1; const message = pass ? () => matcherHint('.not.toContain', collectionType, 'value') + '\n\n' + `Expected ${ collectionType }:\n` + ` ${ printReceived(collection) }\n` + `Not to contain value:\n` + ` ${ printExpected(value) }\n` : () => matcherHint('.toContain', collectionType, 'value') + '\n\n' + `Expected ${ collectionType }:\n` + ` ${ printReceived(collection) }\n` + `To contain value:\n` + ` ${ printExpected(value) }`; return { message, pass }; }, toContainEqual(collection, value) { const collectionType = getType(collection); let converted = null; if (Array.isArray(collection)) { converted = collection; } else { try { converted = Array.from(collection); } catch (e) { throw new Error( matcherHint('[.not].toContainEqual', 'collection', 'value') + '\n\n' + `Expected ${ RECEIVED_COLOR('collection') } to be an array-like structure.\n` + printWithType('Received', collection, printReceived)); } } const pass = converted.findIndex(item => equals(item, value, [iterableEquality])) !== -1; const message = pass ? () => matcherHint('.not.toContainEqual', collectionType, 'value') + '\n\n' + `Expected ${ collectionType }:\n` + ` ${ printReceived(collection) }\n` + `Not to contain a value equal to:\n` + ` ${ printExpected(value) }\n` : () => matcherHint('.toContainEqual', collectionType, 'value') + '\n\n' + `Expected ${ collectionType }:\n` + ` ${ printReceived(collection) }\n` + `To contain a value equal to:\n` + ` ${ printExpected(value) }`; return { message, pass }; }, toEqual(received, expected) { const pass = equals(received, expected, [iterableEquality]); const message = pass ? () => matcherHint('.not.toEqual') + '\n\n' + `Expected value to not equal:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(received) }` : () => { const diffString = diff(expected, received, { expand: this.expand }); return matcherHint('.toEqual') + '\n\n' + `Expected value to equal:\n` + ` ${ printExpected(expected) }\n` + `Received:\n` + ` ${ printReceived(received) }` + ( diffString ? `\n\nDifference:\n\n${ diffString }` : ''); }; // Passing the the actual and expected objects so that a custom reporter // could access them, for example in order to display a custom visual diff, // or create a different error message return { actual: received, expected, message, name: 'toEqual', pass }; }, toHaveLength(received, length) { if ( typeof received !== 'string' && ( !received || typeof received.length !== 'number')) { throw new Error( matcherHint('[.not].toHaveLength', 'received', 'length') + '\n\n' + `Expected value to have a 'length' property that is a number. ` + `Received:\n` + ` ${ printReceived(received) }\n` + ( received ? `received.length:\n ${ printReceived(received.length) }` : '')); } const pass = received.length === length; const message = pass ? () => matcherHint('.not.toHaveLength', 'received', 'length') + '\n\n' + `Expected value to not have length:\n` + ` ${ printExpected(length) }\n` + `Received:\n` + ` ${ printReceived(received) }\n` + `received.length:\n` + ` ${ printReceived(received.length) }` : () => matcherHint('.toHaveLength', 'received', 'length') + '\n\n' + `Expected value to have length:\n` + ` ${ printExpected(length) }\n` + `Received:\n` + ` ${ printReceived(received) }\n` + `received.length:\n` + ` ${ printReceived(received.length) }`; return { message, pass }; }, toHaveProperty(object, propPath, value) { const valuePassed = arguments.length === 3; if (!object && typeof object !== 'string' && typeof object !== 'number') { throw new Error( matcherHint('[.not].toHaveProperty', 'object', 'path', { secondArgument: valuePassed ? 'value' : null }) + '\n\n' + `Expected ${ RECEIVED_COLOR('object') } to be an object. Received:\n` + ` ${ getType(object) }: ${ printReceived(object) }`); } if (getType(propPath) !== 'string') { throw new Error( matcherHint('[.not].toHaveProperty', 'object', 'path', { secondArgument: valuePassed ? 'value' : null }) + '\n\n' + `Expected ${ EXPECTED_COLOR('path') } to be a string. Received:\n` + ` ${ getType(propPath) }: ${ printReceived(propPath) }`); } const result = getPath(object, propPath);const lastTraversedObject = result.lastTraversedObject,hasEndProp = result.hasEndProp; let diffString; if (valuePassed && result.hasOwnProperty('value')) { diffString = diff(value, result.value, { expand: this.expand }); } const pass = valuePassed ? equals(result.value, value, [iterableEquality]) : hasEndProp; if (result.hasOwnProperty('value')) { // we don't diff numbers. So instead we'll show the object that contains the resulting value. // And to get that object we need to go up a level. result.traversedPath.pop(); } const traversedPath = result.traversedPath.join('.'); const message = pass ? matcherHint('.not.toHaveProperty', 'object', 'path', { secondArgument: valuePassed ? 'value' : null }) + '\n\n' + `Expected the object:\n` + ` ${ printReceived(object) }\n` + `Not to have a nested property:\n` + ` ${ printExpected(propPath) }\n` + ( valuePassed ? `With a value of:\n ${ printExpected(value) }\n` : '') : matcherHint('.toHaveProperty', 'object', 'path', { secondArgument: valuePassed ? 'value' : null }) + '\n\n' + `Expected the object:\n` + ` ${ printReceived(object) }\n` + `To have a nested property:\n` + ` ${ printExpected(propPath) }\n` + ( valuePassed ? `With a value of:\n ${ printExpected(value) }\n` : '') + ( traversedPath ? `Received:\n ${ RECEIVED_COLOR('object') }.${ traversedPath }: ${ printReceived(lastTraversedObject) }` : '') + ( diffString ? `\nDifference:\n\n${ diffString }` : ''); if (pass === undefined) { throw new Error('pass must be initialized'); } return { message, pass }; }, toMatch(received, expected) { if (typeof received !== 'string') { throw new Error( matcherHint('[.not].toMatch', 'string', 'expected') + '\n\n' + `${ RECEIVED_COLOR('string') } value must be a string.\n` + printWithType('Received', received, printReceived)); } if (!(expected instanceof RegExp) && !(typeof expected === 'string')) { throw new Error( matcherHint('[.not].toMatch', 'string', 'expected') + '\n\n' + `${ EXPECTED_COLOR('expected') } value must be a string or a regular expression.\n` + printWithType('Expected', expected, printExpected)); } const pass = new RegExp( typeof expected === 'string' ? escapeStrForRegex(expected) : expected). test(received); const message = pass ? () => matcherHint('.not.toMatch') + `\n\nExpected value not to match:\n` + ` ${ printExpected(expected) }` + `\nReceived:\n` + ` ${ printReceived(received) }` : () => matcherHint('.toMatch') + `\n\nExpected value to match:\n` + ` ${ printExpected(expected) }` + `\nReceived:\n` + ` ${ printReceived(received) }`; return { message, pass }; }, toMatchObject(receivedObject, expectedObject) { if (typeof receivedObject !== 'object' || receivedObject === null) { throw new Error( matcherHint('[.not].toMatchObject', 'object', 'expected') + '\n\n' + `${ RECEIVED_COLOR('received') } value must be an object.\n` + printWithType('Received', receivedObject, printReceived)); } if (typeof expectedObject !== 'object' || expectedObject === null) { throw new Error( matcherHint('[.not].toMatchObject', 'object', 'expected') + '\n\n' + `${ EXPECTED_COLOR('expected') } value must be an object.\n` + printWithType('Expected', expectedObject, printExpected)); } const compare = (expected, received) => { if (typeof received !== typeof expected) { return false; } if (typeof expected !== 'object' || expected === null) { return expected === received; } if (Array.isArray(expected)) { if (!Array.isArray(received)) { return false; } if (expected.length !== received.length) { return false; } return expected.every((exp, i) => compare(exp, received[i])); } if (expected instanceof Date && received instanceof Date) { return expected.getTime() === received.getTime(); } return Object.keys(expected).every(key => { if (!received.hasOwnProperty(key)) { return false; } const exp = expected[key]; const act = received[key]; if (typeof exp === 'object' && exp !== null && act !== null) { return compare(exp, act); } return act === exp; }); }; // Strip properties form received object that are not present in the expected // object. We need it to print the diff without adding a lot of unrelated noise. const findMatchObject = (expected, received) => { if (Array.isArray(received)) { if (!Array.isArray(expected)) { return received; } if (expected.length !== received.length) { return received; } return expected.map((exp, i) => findMatchObject(exp, received[i])); } else if (received instanceof Date) { return received; } else if (typeof received === 'object' && received !== null && typeof expected === 'object' && expected !== null) { const matchedObject = {}; let match = false; Object.keys(expected).forEach(key => { if (received.hasOwnProperty(key)) { match = true; const exp = expected[key]; const act = received[key]; if (typeof exp === 'object' && exp !== null) { matchedObject[key] = findMatchObject(exp, act); } else { matchedObject[key] = act; } } }); if (match) { return matchedObject; } else { return received; } } else { return received; } }; const pass = compare(expectedObject, receivedObject); const message = pass ? () => matcherHint('.not.toMatchObject') + `\n\nExpected value not to match object:\n` + ` ${ printExpected(expectedObject) }` + `\nReceived:\n` + ` ${ printReceived(receivedObject) }` : () => { const diffString = diff(expectedObject, findMatchObject(expectedObject, receivedObject), { expand: this.expand }); return matcherHint('.toMatchObject') + `\n\nExpected value to match object:\n` + ` ${ printExpected(expectedObject) }` + `\nReceived:\n` + ` ${ printReceived(receivedObject) }` + ( diffString ? `\nDifference:\n${ diffString }` : ''); }; return { message, pass }; } }; module.exports = matchers;