snapshot.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _typeof = require("@babel/runtime/helpers/typeof");
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.createSnapshotFromFactories = createSnapshotFromFactories;
  8. exports.validateBundle = validateBundle;
  9. exports.validateTypeOf = void 0;
  10. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  11. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  12. var _assert = _interopRequireDefault(require("assert"));
  13. var allIsFunctions = _interopRequireWildcard(require("./is.js"));
  14. var _create = require("../core/create.js");
  15. var _string = require("./string.js");
  16. function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
  17. function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  18. function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
  19. function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } /**
  20. * This file contains helper methods to create expected snapshot structures
  21. * of both instance and ES6 exports.
  22. *
  23. * The files are located here and not under /test or /tools so it's transpiled
  24. * into ES5 code under /lib and can be used straight by node.js
  25. */
  26. var validateTypeOf = allIsFunctions.typeOf;
  27. exports.validateTypeOf = validateTypeOf;
  28. function validateBundle(expectedBundleStructure, bundle) {
  29. var originalWarn = console.warn;
  30. console.warn = function () {
  31. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  32. args[_key] = arguments[_key];
  33. }
  34. if (args.join(' ').indexOf('is moved to') !== -1 && args.join(' ').indexOf('Please use the new location instead') !== -1) {
  35. // Ignore warnings like:
  36. // Warning: math.type.isNumber is moved to math.isNumber in v6.0.0. Please use the new location instead.
  37. return;
  38. }
  39. originalWarn.apply(console, args);
  40. };
  41. try {
  42. var issues = [];
  43. // see whether all expected functions and objects are there
  44. traverse(expectedBundleStructure, function (expectedType, path) {
  45. var actualValue = get(bundle, path);
  46. var actualType = validateTypeOf(actualValue);
  47. var message = actualType === 'undefined' ? 'Missing entry in bundle. ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType) : 'Unexpected entry type in bundle. ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType);
  48. if (actualType !== expectedType) {
  49. issues.push({
  50. actualType: actualType,
  51. expectedType: expectedType,
  52. message: message
  53. });
  54. console.warn(message);
  55. }
  56. });
  57. // see whether there are any functions or objects that shouldn't be there
  58. traverse(bundle, function (actualValue, path) {
  59. var actualType = validateTypeOf(actualValue);
  60. var expectedType = get(expectedBundleStructure, path) || 'undefined';
  61. // FIXME: ugly to have these special cases
  62. if (path.join('.').indexOf('docs.') !== -1) {
  63. // ignore the contents of docs
  64. return;
  65. }
  66. if (path.join('.').indexOf('all.') !== -1) {
  67. // ignore the contents of all dependencies
  68. return;
  69. }
  70. var message = expectedType === 'undefined' ? 'Unknown entry in bundle. ' + 'Is there a new function added which is missing in this snapshot test? ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType) : 'Unexpected entry type in bundle. ' + "Path: ".concat(JSON.stringify(path), ", expected type: ").concat(expectedType, ", actual type: ").concat(actualType);
  71. if (actualType !== expectedType) {
  72. issues.push({
  73. actualType: actualType,
  74. expectedType: expectedType,
  75. message: message
  76. });
  77. console.warn(message);
  78. }
  79. });
  80. // assert on the first issue (if any)
  81. if (issues.length > 0) {
  82. var _issues$ = issues[0],
  83. actualType = _issues$.actualType,
  84. expectedType = _issues$.expectedType,
  85. message = _issues$.message;
  86. console.warn("".concat(issues.length, " bundle issues found"));
  87. _assert["default"].strictEqual(actualType, expectedType, message);
  88. }
  89. } finally {
  90. console.warn = originalWarn;
  91. }
  92. }
  93. /**
  94. * Based on an object with factory functions, create the expected
  95. * structures for ES6 export and a mathjs instance.
  96. * @param {Object} factories
  97. * @return {{expectedInstanceStructure: Object, expectedES6Structure: Object}}
  98. */
  99. function createSnapshotFromFactories(factories) {
  100. var math = (0, _create.create)(factories);
  101. var allFactoryFunctions = {};
  102. var allFunctionsConstantsClasses = {};
  103. var allFunctionsConstants = {};
  104. var allTransformFunctions = {};
  105. var allDependencyCollections = {};
  106. var allClasses = {};
  107. var allNodeClasses = {};
  108. Object.keys(factories).forEach(function (factoryName) {
  109. var factory = factories[factoryName];
  110. var name = factory.fn;
  111. var isTransformFunction = factory.meta && factory.meta.isTransformFunction;
  112. var isClass = !isLowerCase(name[0]) && validateTypeOf(math[name]) === 'function';
  113. var dependenciesName = factory.fn + (isTransformFunction ? 'Transform' : '') + 'Dependencies';
  114. allFactoryFunctions[factoryName] = 'function';
  115. allFunctionsConstantsClasses[name] = validateTypeOf(math[name]);
  116. allDependencyCollections[dependenciesName] = 'Object';
  117. if (isTransformFunction) {
  118. allTransformFunctions[name] = 'function';
  119. }
  120. if (isClass) {
  121. if ((0, _string.endsWith)(name, 'Node')) {
  122. allNodeClasses[name] = 'function';
  123. } else {
  124. allClasses[name] = 'function';
  125. }
  126. } else {
  127. allFunctionsConstants[name] = validateTypeOf(math[name]);
  128. }
  129. });
  130. var embeddedDocs = {};
  131. Object.keys(factories).forEach(function (factoryName) {
  132. var factory = factories[factoryName];
  133. var name = factory.fn;
  134. if (isLowerCase(factory.fn[0])) {
  135. // ignore class names starting with upper case
  136. embeddedDocs[name] = 'Object';
  137. }
  138. });
  139. embeddedDocs = exclude(embeddedDocs, ['equalScalar', 'apply', 'addScalar', 'multiplyScalar', 'print', 'divideScalar', 'parse', 'compile', 'parser', 'chain', 'reviver', 'replacer']);
  140. var allTypeChecks = {};
  141. Object.keys(allIsFunctions).forEach(function (name) {
  142. if (name.indexOf('is') === 0) {
  143. allTypeChecks[name] = 'function';
  144. }
  145. });
  146. var allErrorClasses = {
  147. ArgumentsError: 'function',
  148. DimensionError: 'function',
  149. IndexError: 'function'
  150. };
  151. var expectedInstanceStructure = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, allFunctionsConstantsClasses), {}, {
  152. on: 'function',
  153. off: 'function',
  154. once: 'function',
  155. emit: 'function',
  156. "import": 'function',
  157. config: 'function',
  158. create: 'function',
  159. factory: 'function'
  160. }, allTypeChecks), allErrorClasses), {}, {
  161. expression: {
  162. transform: _objectSpread({}, allTransformFunctions),
  163. mathWithTransform: _objectSpread(_objectSpread({}, exclude(allFunctionsConstants, ['chain'])), {}, {
  164. config: 'function'
  165. })
  166. }
  167. });
  168. var expectedES6Structure = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, exclude(allFunctionsConstantsClasses, ['E', 'false', 'Infinity', 'NaN', 'null', 'PI', 'true'])), {}, {
  169. create: 'function',
  170. config: 'function',
  171. factory: 'function',
  172. _true: 'boolean',
  173. _false: 'boolean',
  174. _null: 'null',
  175. _Infinity: 'number',
  176. _NaN: 'number'
  177. }, allTypeChecks), allErrorClasses), allDependencyCollections), allFactoryFunctions), {}, {
  178. docs: embeddedDocs
  179. });
  180. return {
  181. expectedInstanceStructure: expectedInstanceStructure,
  182. expectedES6Structure: expectedES6Structure
  183. };
  184. }
  185. function traverse(obj) {
  186. var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (value, path) {};
  187. var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  188. // FIXME: ugly to have these special cases
  189. if (path.length > 0 && path[0].indexOf('Dependencies') !== -1) {
  190. // special case for objects holding a collection of dependencies
  191. callback(obj, path);
  192. } else if (validateTypeOf(obj) === 'Array') {
  193. obj.map(function (item, index) {
  194. return traverse(item, callback, path.concat(index));
  195. });
  196. } else if (validateTypeOf(obj) === 'Object') {
  197. Object.keys(obj).forEach(function (key) {
  198. // FIXME: ugly to have these special cases
  199. // ignore special case of deprecated docs
  200. if (key === 'docs' && path.join('.') === 'expression') {
  201. return;
  202. }
  203. traverse(obj[key], callback, path.concat(key));
  204. });
  205. } else {
  206. callback(obj, path);
  207. }
  208. }
  209. function get(object, path) {
  210. var child = object;
  211. for (var i = 0; i < path.length; i++) {
  212. var key = path[i];
  213. child = child ? child[key] : undefined;
  214. }
  215. return child;
  216. }
  217. /**
  218. * Create a copy of the provided `object` and delete
  219. * all properties listed in `excludedProperties`
  220. * @param {Object} object
  221. * @param {string[]} excludedProperties
  222. * @return {Object}
  223. */
  224. function exclude(object, excludedProperties) {
  225. var strippedObject = (0, _extends2["default"])({}, object);
  226. excludedProperties.forEach(function (excludedProperty) {
  227. delete strippedObject[excludedProperty];
  228. });
  229. return strippedObject;
  230. }
  231. function isLowerCase(text) {
  232. return typeof text === 'string' && text.toLowerCase() === text;
  233. }