Skip to content

Commit 2ae2d93

Browse files
committed
Add support for new types to debug()
1 parent 65a6499 commit 2ae2d93

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { shallow, render, ShallowWrapper, mount } from 'enzyme';
66
import { ITERATOR_SYMBOL, withSetStateAllowed, sym } from 'enzyme/build/Utils';
77

88
import './_helpers/setupAdapters';
9-
import { createClass, createContext, forwardRef } from './_helpers/react-compat';
9+
import { createClass, createContext, forwardRef, createPortal } from './_helpers/react-compat';
1010
import { describeIf, itIf, itWithData, generateEmptyRenderData } from './_helpers';
1111
import { REACT013, REACT014, REACT15, REACT150_4, REACT16, REACT163, is } from './_helpers/version';
1212

@@ -2957,6 +2957,36 @@ describe('shallow', () => {
29572957
it('should pass through to the debugNodes function', () => {
29582958
expect(shallow(<div />).debug()).to.equal('<div />');
29592959
});
2960+
2961+
itIf(REACT163, 'should handle internal types gracefully', () => {
2962+
const { Provider, Consumer } = createContext(null);
2963+
// eslint-disable-next-line prefer-arrow-callback
2964+
const Forwarded = forwardRef(function MyComponent(props) {
2965+
return (
2966+
<Provider value={5}>
2967+
<Forwarded />
2968+
<div {...props}>
2969+
<React.Fragment>
2970+
<Consumer>{() => <div />}</Consumer>
2971+
{createPortal(<span />, { nodeType: 1 })}
2972+
</React.Fragment>
2973+
</div>
2974+
</Provider>
2975+
);
2976+
});
2977+
2978+
expect(shallow(<Forwarded />).debug()).to.equal(`<ContextProvider value={5}>
2979+
<ForwardRef(MyComponent) />
2980+
<div>
2981+
<Fragment>
2982+
<ContextConsumer>
2983+
[function child]
2984+
</ContextConsumer>
2985+
<Portal />
2986+
</Fragment>
2987+
</div>
2988+
</ContextProvider>`);
2989+
});
29602990
});
29612991

29622992
describe('.html()', () => {

packages/enzyme/src/Debug.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,41 @@ import {
1212
propsOfNode,
1313
childrenOfNode,
1414
} from './RSTTraversal';
15+
import {
16+
typeOf,
17+
AsyncMode,
18+
ContextProvider,
19+
ContextConsumer,
20+
Element,
21+
ForwardRef,
22+
Fragment,
23+
Portal,
24+
StrictMode,
25+
} from './Utils';
1526

1627
const booleanValue = Function.bind.call(Function.call, Boolean.prototype.valueOf);
1728

29+
1830
export function typeName(node) {
19-
return typeof node.type === 'function'
20-
? (node.type.displayName || functionName(node.type) || 'Component')
21-
: node.type;
31+
const { type } = node;
32+
switch (typeOf(node)) {
33+
case AsyncMode: return 'AsyncMode';
34+
case ContextProvider: return 'ContextProvider';
35+
case ContextConsumer: return 'ContextConsumer';
36+
case Portal: return 'Portal';
37+
case StrictMode: return 'StrictMode';
38+
case ForwardRef: {
39+
const name = type.render.displayName || functionName(type.render);
40+
return name ? `ForwardRef(${name})` : 'ForwardRef';
41+
}
42+
case Fragment:
43+
return 'Fragment';
44+
case Element:
45+
default:
46+
return typeof node.type === 'function'
47+
? (type.displayName || functionName(type) || 'Component')
48+
: type || 'unknown';
49+
}
2250
}
2351

2452
export function spaces(n) {
@@ -66,6 +94,7 @@ function indentChildren(childrenStrs, indentLength) {
6694

6795
export function debugNode(node, indentLength = 2, options = {}) {
6896
if (typeof node === 'string' || typeof node === 'number') return escape(node);
97+
if (typeof node === 'function') return '[function child]';
6998
if (!node) return '';
7099

71100
const childrenStrs = compact(childrenOfNode(node).map(n => debugNode(n, indentLength, options)));

packages/enzyme/src/Utils.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,47 @@ import configuration from './configuration';
77
import validateAdapter from './validateAdapter';
88
import { childrenOfNode } from './RSTTraversal';
99

10+
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
11+
1012
export const ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
1113

14+
// TODO use react-is when a version is released with no peer dependency on React
15+
export const AsyncMode = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf;
16+
export const ContextProvider = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
17+
export const ContextConsumer = hasSymbol ? Symbol.for('react.context') : 0xeace;
18+
export const Element = hasSymbol ? Symbol.for('react.element') : 0xeac7;
19+
export const ForwardRef = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
20+
export const Fragment = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
21+
export const Portal = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
22+
export const StrictMode = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
23+
24+
export function typeOf(node) {
25+
if (node !== null) {
26+
const { type, $$typeof } = node;
27+
28+
switch (type || $$typeof) {
29+
case AsyncMode:
30+
case Fragment:
31+
case StrictMode:
32+
return type;
33+
default: {
34+
const $$typeofType = type && type.$$typeof;
35+
36+
switch ($$typeofType) {
37+
case ContextConsumer:
38+
case ForwardRef:
39+
case Portal:
40+
case ContextProvider:
41+
return $$typeofType;
42+
default:
43+
return type || $$typeof;
44+
}
45+
}
46+
}
47+
}
48+
return undefined;
49+
}
50+
1251
export function getAdapter(options = {}) {
1352
if (options.adapter) {
1453
validateAdapter(options.adapter);

0 commit comments

Comments
 (0)