/** * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ const util = require('util'); const chalk = require('chalk'); const React = require('react'); const ReactTestRenderer = require('react-test-renderer'); const prettyFormat = require('../build'); const ReactTestComponent = require('../build/plugins/ReactTestComponent'); const worldGeoJson = require('./world.geo.json'); const NANOSECONDS = 1000000000; let TIMES_TO_RUN = 100000; function testCase(name, fn) { let result, error, time, total; try { result = fn(); } catch (err) { error = err; } if (!error) { const start = process.hrtime(); for (let i = 0; i < TIMES_TO_RUN; i++) { fn(); } const diff = process.hrtime(start); total = diff[0] * 1e9 + diff[1]; time = Math.round(total / TIMES_TO_RUN); } return { error, name, result, time, total, }; } function test(name, value, ignoreResult, prettyFormatOpts) { const formatted = testCase('prettyFormat() ', () => prettyFormat(value, prettyFormatOpts), ); const inspected = testCase('util.inspect() ', () => util.inspect(value, { depth: null, showHidden: true, }), ); const stringified = testCase('JSON.stringify()', () => JSON.stringify(value, null, ' '), ); const results = [formatted, inspected, stringified].sort( (a, b) => a.time - b.time, ); const winner = results[0]; results.forEach((item, index) => { item.isWinner = index === 0; item.isLoser = index === results.length - 1; }); function log(current) { let message = current.name; if (current.time) { message += ' - ' + String(current.time).padStart(6) + 'ns'; } if (current.total) { message += ' - ' + current.total / NANOSECONDS + 's total (' + TIMES_TO_RUN + ' runs)'; } if (current.error) { message += ' - Error: ' + current.error.message; } if (!ignoreResult && current.result) { message += ' - ' + JSON.stringify(current.result); } message = ' ' + message + ' '; if (current.error) { message = chalk.dim(message); } const diff = current.time - winner.time; if (diff > winner.time * 0.85) { message = chalk.bgRed.black(message); } else if (diff > winner.time * 0.65) { message = chalk.bgYellow.black(message); } else if (!current.error) { message = chalk.bgGreen.black(message); } else { message = chalk.dim(message); } console.log(' ' + message); } console.log(name + ': '); results.forEach(log); console.log(); } function returnArguments() { return arguments; } test('empty arguments', returnArguments()); test('arguments', returnArguments(1, 2, 3)); test('an empty array', []); test('an array with items', [1, 2, 3]); test('a typed array', new Uint32Array(3)); test('an array buffer', new ArrayBuffer(3)); test('a nested array', [[1, 2, 3]]); test('true', true); test('false', false); test('an error', new Error()); test('a typed error with a message', new TypeError('message')); /* eslint-disable no-new-func */ test('a function constructor', new Function()); /* eslint-enable no-new-func */ test('an anonymous function', () => {}); function named() {} test('a named function', named); test('Infinity', Infinity); test('-Infinity', -Infinity); test('an empty map', new Map()); const mapWithValues = new Map(); const mapWithNonStringKeys = new Map(); mapWithValues.set('prop1', 'value1'); mapWithValues.set('prop2', 'value2'); mapWithNonStringKeys.set({prop: 'value'}, {prop: 'value'}); test('a map with values', mapWithValues); test('a map with non-string keys', mapWithNonStringKeys); test('NaN', NaN); test('null', null); test('a number', 123); test('a date', new Date(10e11)); test('an empty object', {}); test('an object with properties', {prop1: 'value1', prop2: 'value2'}); const objectWithPropsAndSymbols = {prop: 'value1'}; objectWithPropsAndSymbols[Symbol('symbol1')] = 'value2'; objectWithPropsAndSymbols[Symbol('symbol2')] = 'value3'; test('an object with properties and symbols', objectWithPropsAndSymbols); test('an object with sorted properties', {a: 2, b: 1}); test('regular expressions from constructors', new RegExp('regexp')); test('regular expressions from literals', /regexp/gi); test('an empty set', new Set()); const setWithValues = new Set(); setWithValues.add('value1'); setWithValues.add('value2'); test('a set with values', setWithValues); test('a string', 'string'); test('a symbol', Symbol('symbol')); test('undefined', undefined); test('a WeakMap', new WeakMap()); test('a WeakSet', new WeakSet()); test('deeply nested objects', {prop: {prop: {prop: 'value'}}}); const circularReferences = {}; circularReferences.prop = circularReferences; test('circular references', circularReferences); const parallelReferencesInner = {}; const parallelReferences = { prop1: parallelReferencesInner, prop2: parallelReferencesInner, }; test('parallel references', parallelReferences); test('able to customize indent', {prop: 'value'}); const bigObj = {}; for (let i = 0; i < 50; i++) { bigObj[i] = i; } test('big object', bigObj); const element = React.createElement( 'div', {onClick: () => {}, prop: {a: 1, b: 2}}, React.createElement('div', {prop: {a: 1, b: 2}}), React.createElement('div'), React.createElement( 'div', {prop: {a: 1, b: 2}}, React.createElement('div', null, React.createElement('div')), ), ); test('react', ReactTestRenderer.create(element).toJSON(), false, { plugins: [ReactTestComponent], }); TIMES_TO_RUN = 100; test('massive', worldGeoJson, true);