function compareObjects(a: Object, b: Object, options: ?DiffOptions) { let diffMessage; let hasThrown = false; try { diffMessage = diffStrings( prettyFormat(a, FORMAT_OPTIONS), prettyFormat(b, FORMAT_OPTIONS), options, ); } catch (e) { hasThrown = true; } // If the comparison yields no results, compare again but this time // without calling `toJSON`. It's also possible that toJSON might throw. if (!diffMessage || diffMessage === NO_DIFF_MESSAGE) { diffMessage = diffStrings( prettyFormat(a, FALLBACK_FORMAT_OPTIONS), prettyFormat(b, FALLBACK_FORMAT_OPTIONS), options, ); if (diffMessage !== NO_DIFF_MESSAGE && !hasThrown) { diffMessage = SIMILAR_MESSAGE + '\n\n' + diffMessage; } } return diffMessage; }
// Generate a string that will highlight the difference between two values // with green and red. (similar to how github does code diffing) function diff(a: any, b: any): ?string { if (a === b) { return NO_DIFF_MESSAGE; } if (getType(a) !== getType(b)) { return chalk.reset.gray( 'Comparing different types of values.\n' + `Actual: '${chalk.cyan(getType(b))}'` + ', ' + `Expected: '${chalk.cyan(getType(a))}'`, ); } switch (getType(a)) { case 'string': return diffStrings(String(a), String(b)); case 'number': case 'boolean': return chalk.gray('Actual: ') + chalk.red(b) + '\n' + chalk.gray('Expected: ') + chalk.green(a); default: return diffStrings( prettyFormat(a, {plugins: [jsxLikeExtension]}), prettyFormat(b, {plugins: [jsxLikeExtension]}), ); } }
/** * Formats the text with prettier and then eslint based on the given options * @param {String} options.filePath - the path of the file being formatted * can be used in leu of `eslintConfig` (eslint will be used to find the * relevant config for the file). Will also be used to load the `text` if * `text` is not provided. * @param {String} options.text - the text (JavaScript code) to format * @param {String} options.eslintPath - the path to the eslint module to use. * Will default to require.resolve('eslint') * @param {String} options.prettierPath - the path to the prettier module. * Will default to require.resovlve('prettierPath') * @param {String} options.eslintConfig - the config to use for formatting * with ESLint. * @param {Object} options.prettierOptions - the options to pass for * formatting with `prettier`. If not provided, prettier-eslint will attempt * to create the options based on the eslintConfig * @param {Object} options.fallbackPrettierOptions - the options to pass for * formatting with `prettier` if the given option is not inferrable from the * eslintConfig. * @param {String} options.logLevel - the level for the logs * (error, warn, info, debug, trace) * @param {Boolean} options.prettierLast - Run Prettier Last * @return {String} - the formatted string */ function format(options) { const {logLevel = getDefaultLogLevel()} = options logger.setLevel(logLevel) logger.trace('called format with options:', prettyFormat(options)) const { filePath, text = getTextFromFilePath(filePath), eslintPath = getModulePath(filePath, 'eslint'), prettierPath = getModulePath(filePath, 'prettier'), prettierOptions, prettierLast, fallbackPrettierOptions, } = options const eslintConfig = defaultEslintConfig( getConfig(filePath, eslintPath), options.eslintConfig, ) const formattingOptions = getOptionsForFormatting( eslintConfig, prettierOptions, fallbackPrettierOptions, ) logger.debug( 'inferred options:', prettyFormat({ filePath, text, eslintPath, prettierPath, eslintConfig: formattingOptions.eslint, prettierOptions: formattingOptions.prettier, logLevel, prettierLast, }), ) const isCss = /\.(css|less|scss)$/.test(filePath) if (isCss) { formattingOptions.prettier.parser = 'postcss' } const prettify = createPrettify(formattingOptions.prettier, prettierPath) const eslintFix = createEslintFix(formattingOptions.eslint, eslintPath) if (isCss) { return prettify(text, filePath) } if (prettierLast) { return prettify(eslintFix(text, filePath)) } return eslintFix(prettify(text), filePath) }
const stringify = object => { try { return prettyFormat(object, { min: true }); } catch (e) { return prettyFormat(object, { callToJSON: false, min: true }); } };
it('toTree() handles complicated tree of fragments', () => { const renderer = ReactTestRenderer.create( <React.Fragment> <React.Fragment> <div>One</div> <div>Two</div> <React.Fragment> <div>Three</div> </React.Fragment> </React.Fragment> <div>Four</div> </React.Fragment>, ); const tree = renderer.toTree(); cleanNodeOrArray(tree); expect(prettyFormat(tree)).toEqual( prettyFormat([ { type: 'div', nodeType: 'host', props: {}, instance: null, rendered: ['One'], }, { type: 'div', nodeType: 'host', props: {}, instance: null, rendered: ['Two'], }, { type: 'div', nodeType: 'host', props: {}, instance: null, rendered: ['Three'], }, { type: 'div', nodeType: 'host', props: {}, instance: null, rendered: ['Four'], }, ]), ); });
const serialize = data => { return addExtraLineBreaks(prettyFormat(data, { escapeRegex: true, plugins: getSerializers(), printFunctionName: false })); };
function getConfig(filePath, eslintPath) { const eslintOptions = {} if (filePath) { eslintOptions.cwd = path.dirname(filePath) } logger.trace( oneLine` creating ESLint CLI Engine to get the config for "${filePath || process.cwd()}" `, ) const configFinder = getESLintCLIEngine(eslintPath, eslintOptions) try { logger.debug(`getting eslint config for file at "${filePath}"`) const config = configFinder.getConfigForFile(filePath) logger.trace( `eslint config for "${filePath}" received`, prettyFormat(config), ) return config } catch (error) { // is this noisy? Try setting options.disableLog to false logger.debug('Unable to find config') return {rules: {}} } }
return function eslintFix(text, filePath) { const eslint = getESLintCLIEngine(eslintPath, eslintConfig) try { logger.trace(`calling eslint.executeOnText with the text`) const report = eslint.executeOnText(text, filePath, true) logger.trace( `executeOnText returned the following report:`, prettyFormat(report), ) // default the output to text because if there's nothing // to fix, eslint doesn't provide `output` const [{output = text}] = report.results logger.trace('eslint --fix: output === input', output === text) // NOTE: We're ignoring linting errors/warnings here and // defaulting to the given text if there are any // because all we're trying to do is fix what we can. // We don't care about what we can't logger.trace( stripIndent` eslint --fix output: ${indentString(output, 2)} `, ) return output } catch (error) { logger.error('eslint fix failed due to an eslint error') throw error } }
const _formatError = (errors: ?Exception | [?Exception, Exception]): string => { let error; let asyncError; if (Array.isArray(errors)) { error = errors[0]; asyncError = errors[1]; } else { error = errors; asyncError = new Error(); } if (error) { if (error.stack) { return error.stack; } if (error.message) { return error.message; } } asyncError.message = `thrown: ${prettyFormat(error, {maxDepth: 3})}`; return asyncError.stack; };
test('min option', () => { const fn = jest.fn(val => val); fn({key: 'value'}); const expected = '[MockFunction] {"calls": [[{"key": "value"}]], "results": [{"type": "return", "value": {"key": "value"}}]}'; expect(prettyFormat(fn, {min: true, plugins: [plugin]})).toBe(expected); });
function attributeHook(name, value, context, opts, isComponent) { let type = typeof value; // always skip null & undefined values, skip false DOM attributes, skip functions if told to if (value==null || (type==='function' && !opts.functions)) return ''; if (opts.skipFalseAttributes && !isComponent && (value===false || ((name==='class' || name==='style') && value===''))) return ''; let indentChar = typeof opts.pretty==='string' ? opts.pretty : '\t'; if (type!=='string') { if (type==='function' && !opts.functionNames) { value = 'Function'; } else { preactPlugin.context = context; preactPlugin.opts = opts; value = prettyFormat(value, prettyFormatOpts); if (~value.indexOf('\n')) { value = `${indent('\n'+value, indentChar)}\n`; } } return indent(`\n${name}={${value}}`, indentChar); } return `\n${indentChar}${name}="${encodeEntities(value)}"`; }
return data.map(item => { if (typeof item === 'string') { return item; } else { return prettyFormat(item); } });
constructor(value: ?Object) { if (this._isPrimitive(value)) { throw new TypeError( [ 'Primitives cannot leak memory.', 'You passed a ' + typeof value + ': <' + prettyFormat(value) + '>', ].join(' '), ); } let weak; try { // eslint-disable-next-line import/no-extraneous-dependencies weak = require('weak'); } catch (err) { if (!err || err.code !== 'MODULE_NOT_FOUND') { throw err; } throw new Error( 'The leaking detection mechanism requires the "weak" package to be installed and work. ' + 'Please install it as a dependency on your main project', ); } weak(value, () => (this._isReferenceBeingHeld = false)); this._isReferenceBeingHeld = true; // Ensure value is not leaked by the closure created by the "weak" callback. value = null; }
return data.map(item => { if (typeof item === 'string') { return item; } else { return prettyFormat(item, { plugins: [ReactNodeFormatter] }); } });
function prettyFormat(thing) { return prettyFormatPkg(thing, { plugins: [ prettyFormatPkg.plugins.ReactElement, prettyFormatPkg.plugins.ReactTestComponent, ], }); }
test('maxDepth option', () => { const fn1 = jest.fn(); fn1.mockName('atDepth1'); fn1('primitive', {key: 'value'}); const fn2 = jest.fn(); fn2.mockName('atDepth2'); fn2('primitive', {key: 'value'}); const fn3 = jest.fn(); fn3.mockName('atDepth3'); fn3('primitive', {key: 'value'}); const val = { fn1, greaterThan1: { fn2, greaterThan2: { fn3, }, }, }; const expected = [ 'Object {', // ++depth === 1 ' "fn1": [MockFunction atDepth1] {', ' "calls": Array [', // ++depth === 2 ' Array [', // ++depth === 3 ' "primitive",', ' [Object],', // ++depth === 4 ' ],', ' ],', ' "results": Array [', // ++depth === 2 ' Object {', // ++depth === 3 ' "type": "return",', ' "value": undefined,', ' },', ' ],', ' },', ' "greaterThan1": Object {', // ++depth === 2 ' "fn2": [MockFunction atDepth2] {', ' "calls": Array [', // ++depth === 3 ' [Array],', // ++depth === 4 ' ],', ' "results": Array [', // ++depth === 3 ' [Object],', // ++depth === 4 ' ],', ' },', ' "greaterThan2": Object {', // ++depth === 3 ' "fn3": [MockFunction atDepth3] {', ' "calls": [Array],', // ++depth === 4 ' "results": [Array],', // ++depth === 4 ' },', ' },', ' },', '}', ].join('\n'); expect(prettyFormat(val, {maxDepth: 3, plugins: [plugin]})).toBe(expected); });
async function _serializeErrorAsync(error, message) { if (message == null) { message = error.message; } if (!error.stack || !error.stack.length) { return prettyFormat(error); } let stack = await _symbolicateErrorAsync(error); let formattedStack = _formatStack(stack); return { message, stack: formattedStack }; }
export const serialize = (data: any): string => { return addExtraLineBreaks( normalizeNewlines( prettyFormat(data, { escapeRegex: true, plugins: getSerializers(), printFunctionName: false, }), ), ); };
const done = (reason?: Error | string): void => { // $FlowFixMe: It doesn't approve of .stack const isError = reason && reason.message && reason.stack; return reason ? reject( isError ? reason : new Error(`Failed: ${prettyFormat(reason, {maxDepth: 3})}`), ) : resolve(); };
test('does not calls global test title with %p placeholder when no data is supplied at given position', () => { const globalTestMocks = getGlobalTestMocks(); const eachObject = each.withGlobal(globalTestMocks)([ ['string1', 'pretty1', 'string2'], ['string1', 'pretty1', 'string2'], ]); const testFunction = get(eachObject, keyPath); testFunction('expected string: %s %p %s %p', noop); const globalMock = get(globalTestMocks, keyPath); expect(globalMock).toHaveBeenCalledTimes(2); expect(globalMock).toHaveBeenCalledWith( `expected string: string1 ${pretty('pretty1')} string2 %p`, expectFunction, ); expect(globalMock).toHaveBeenCalledWith( `expected string: string1 ${pretty('pretty1')} string2 %p`, expectFunction, ); });
it('supports forwardRef', () => { const InnerRefed = React.forwardRef((props, ref) => ( <div> <span ref={ref} /> </div> )); class App extends React.Component { render() { return <InnerRefed ref={r => (this.ref = r)} />; } } const renderer = ReactTestRenderer.create(<App />); const tree = renderer.toTree(); cleanNodeOrArray(tree); expect(prettyFormat(tree)).toEqual( prettyFormat({ instance: null, nodeType: 'component', props: {}, rendered: { instance: null, nodeType: 'host', props: {}, rendered: [ { instance: null, nodeType: 'host', props: {}, rendered: [], type: 'span', }, ], type: 'div', }, type: App, }), ); });
it('toTree() handles nested Fragments', () => { const Foo = () => ( <React.Fragment> <React.Fragment>foo</React.Fragment> </React.Fragment> ); const renderer = ReactTestRenderer.create(<Foo />); const tree = renderer.toTree(); cleanNodeOrArray(tree); expect(prettyFormat(tree)).toEqual( prettyFormat({ nodeType: 'component', type: Foo, instance: null, props: {}, rendered: 'foo', }), ); });
export default function isError(potentialError: any) { // duck-type Error, see #2549 const isError = typeof potentialError === 'object' && typeof potentialError.message === 'string' && typeof potentialError.name === 'string'; const message = isError ? null : `Failed: ${prettyFormat(potentialError, {maxDepth: 3})}`; return {isError, message}; }
it('toTree() handles simple components that return arrays', () => { const Foo = ({children}) => children; const renderer = ReactTestRenderer.create( <Foo> <div>One</div> <div>Two</div> </Foo>, ); const tree = renderer.toTree(); cleanNodeOrArray(tree); expect(prettyFormat(tree)).toEqual( prettyFormat({ type: Foo, nodeType: 'component', props: {}, instance: null, rendered: [ { instance: null, nodeType: 'host', props: {}, rendered: ['One'], type: 'div', }, { instance: null, nodeType: 'host', props: {}, rendered: ['Two'], type: 'div', }, ], }), ); });
export const stringify = (object: any, maxDepth?: number = 10): string => { const MAX_LENGTH = 10000; let result; try { result = prettyFormat(object, { maxDepth, min: true, plugins: PLUGINS, }); } catch (e) { result = prettyFormat(object, { callToJSON: false, maxDepth, min: true, plugins: PLUGINS, }); } return result.length >= MAX_LENGTH && maxDepth > 1 ? stringify(object, Math.floor(maxDepth / 2)) : result; };
test('calls global test title with %p placeholder injected at the correct positions', () => { const globalTestMocks = getGlobalTestMocks(); const eachObject = each.withGlobal(globalTestMocks)([ ['string1', 'pretty1', 'string2', 'pretty2'], ['string1', 'pretty1', 'string2', 'pretty2'], ]); const testFunction = get(eachObject, keyPath); testFunction('expected string: %s %p %s %p', noop); const globalMock = get(globalTestMocks, keyPath); expect(globalMock).toHaveBeenCalledTimes(2); expect(globalMock).toHaveBeenCalledWith( `expected string: string1 ${pretty('pretty1')} string2 ${pretty( 'pretty2', )}`, expectFunction, ); expect(globalMock).toHaveBeenCalledWith( `expected string: string1 ${pretty('pretty1')} string2 ${pretty( 'pretty2', )}`, expectFunction, ); });
it('supports modes', () => { function Child(props) { return props.value; } function App(props) { return ( <React.StrictMode> <Child value={props.value} /> </React.StrictMode> ); } const renderer = ReactTestRenderer.create(<App value="a" />); const child = renderer.root.findByType(Child); expect(child.children).toEqual(['a']); expect(prettyFormat(renderer.toTree())).toEqual( prettyFormat({ instance: null, nodeType: 'component', props: { value: 'a', }, rendered: { instance: null, nodeType: 'component', props: { value: 'a', }, rendered: 'a', type: Child, }, type: App, }), ); });
it('supports context providers and consumers', () => { const {Consumer, Provider} = React.createContext('a'); function Child(props) { return props.value; } function App() { return ( <Provider value="b"> <Consumer>{value => <Child value={value} />}</Consumer> </Provider> ); } const renderer = ReactTestRenderer.create(<App />); const child = renderer.root.findByType(Child); expect(child.children).toEqual(['b']); expect(prettyFormat(renderer.toTree())).toEqual( prettyFormat({ instance: null, nodeType: 'component', props: {}, rendered: { instance: null, nodeType: 'component', props: { value: 'b', }, rendered: 'b', type: Child, }, type: App, }), ); });
it('toTree() renders simple components returning host components', () => { const Qoo = () => <span className="Qoo">Hello World!</span>; const renderer = ReactTestRenderer.create(<Qoo />); const tree = renderer.toTree(); cleanNodeOrArray(tree); expect(prettyFormat(tree)).toEqual( prettyFormat({ nodeType: 'component', type: Qoo, props: {}, instance: null, rendered: { nodeType: 'host', type: 'span', props: {className: 'Qoo'}, instance: null, rendered: ['Hello World!'], }, }), ); });
test('indent option', () => { const fn = jest.fn(); fn({key: 'value'}); const expected = [ '[MockFunction] {', '"calls": Array [', 'Array [', 'Object {', '"key": "value",', '},', '],', '],', '}', ].join('\n'); expect(prettyFormat(fn, {indent: 0, plugins: [plugin]})).toBe(expected); });