Files
react/packages/shared/__tests__/describeComponentFrame-test.js
Sebastian Markbåge b0cb137bcb Don't dedupe using the stack (#18693)
We currently use the stack to dedupe warnings in a couple of places.
This is a very heavy weight way of computing that a warning doesn't need
to be fired.

This uses parent component name as a heuristic for deduping. It's not
perfect but as soon as you fix one you'll uncover the next. It might be a
little annoying but having many logs is also annoying.

We now have no special cases for stacks. The only thing that uses stacks in
dev is the console.error and dev tools. This means that we could
externalize this completely to an console.error patching module and drop
it from being built-in to react.

The only prod/dev behavior is the one we pass to error boundaries or the
error we throw if you don't have an error boundary.
2020-04-22 19:02:11 -07:00

114 lines
3.4 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
let React;
let ReactDOM;
describe('Component stack trace displaying', () => {
beforeEach(() => {
React = require('react');
ReactDOM = require('react-dom');
});
// @gate !enableComponentStackLocations || !__DEV__
it('should provide filenames in stack traces', () => {
class Component extends React.Component {
render() {
return [<span>a</span>, <span>b</span>];
}
}
spyOnDev(console, 'error');
const container = document.createElement('div');
const fileNames = {
'': '',
'/': '',
'\\': '',
Foo: 'Foo',
'Bar/Foo': 'Foo',
'Bar\\Foo': 'Foo',
'Baz/Bar/Foo': 'Foo',
'Baz\\Bar\\Foo': 'Foo',
'Foo.js': 'Foo.js',
'Foo.jsx': 'Foo.jsx',
'/Foo.js': 'Foo.js',
'/Foo.jsx': 'Foo.jsx',
'\\Foo.js': 'Foo.js',
'\\Foo.jsx': 'Foo.jsx',
'Bar/Foo.js': 'Foo.js',
'Bar/Foo.jsx': 'Foo.jsx',
'Bar\\Foo.js': 'Foo.js',
'Bar\\Foo.jsx': 'Foo.jsx',
'/Bar/Foo.js': 'Foo.js',
'/Bar/Foo.jsx': 'Foo.jsx',
'\\Bar\\Foo.js': 'Foo.js',
'\\Bar\\Foo.jsx': 'Foo.jsx',
'Bar/Baz/Foo.js': 'Foo.js',
'Bar/Baz/Foo.jsx': 'Foo.jsx',
'Bar\\Baz\\Foo.js': 'Foo.js',
'Bar\\Baz\\Foo.jsx': 'Foo.jsx',
'/Bar/Baz/Foo.js': 'Foo.js',
'/Bar/Baz/Foo.jsx': 'Foo.jsx',
'\\Bar\\Baz\\Foo.js': 'Foo.js',
'\\Bar\\Baz\\Foo.jsx': 'Foo.jsx',
'C:\\funny long (path)/Foo.js': 'Foo.js',
'C:\\funny long (path)/Foo.jsx': 'Foo.jsx',
'index.js': 'index.js',
'index.jsx': 'index.jsx',
'/index.js': 'index.js',
'/index.jsx': 'index.jsx',
'\\index.js': 'index.js',
'\\index.jsx': 'index.jsx',
'Bar/index.js': 'Bar/index.js',
'Bar/index.jsx': 'Bar/index.jsx',
'Bar\\index.js': 'Bar/index.js',
'Bar\\index.jsx': 'Bar/index.jsx',
'/Bar/index.js': 'Bar/index.js',
'/Bar/index.jsx': 'Bar/index.jsx',
'\\Bar\\index.js': 'Bar/index.js',
'\\Bar\\index.jsx': 'Bar/index.jsx',
'Bar/Baz/index.js': 'Baz/index.js',
'Bar/Baz/index.jsx': 'Baz/index.jsx',
'Bar\\Baz\\index.js': 'Baz/index.js',
'Bar\\Baz\\index.jsx': 'Baz/index.jsx',
'/Bar/Baz/index.js': 'Baz/index.js',
'/Bar/Baz/index.jsx': 'Baz/index.jsx',
'\\Bar\\Baz\\index.js': 'Baz/index.js',
'\\Bar\\Baz\\index.jsx': 'Baz/index.jsx',
'C:\\funny long (path)/index.js': 'funny long (path)/index.js',
'C:\\funny long (path)/index.jsx': 'funny long (path)/index.jsx',
};
Object.keys(fileNames).forEach((fileName, i) => {
Component.displayName = 'Component ' + i;
ReactDOM.render(
<Component __source={{fileName, lineNumber: i}} />,
container,
);
});
if (__DEV__) {
let i = 0;
expect(console.error.calls.count()).toBe(Object.keys(fileNames).length);
for (const fileName in fileNames) {
if (!fileNames.hasOwnProperty(fileName)) {
continue;
}
const args = console.error.calls.argsFor(i);
const stack = args[args.length - 1];
const expected = fileNames[fileName];
expect(stack).toContain(`at ${expected}:`);
i++;
}
}
});
});