Skip to content

Commit

Permalink
[New]: supports lazy and Suspense in mount and shallow
Browse files Browse the repository at this point in the history
  • Loading branch information
chenesan committed Jan 10, 2019
1 parent e5fcbcb commit e656f7a
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 9 deletions.
2 changes: 2 additions & 0 deletions packages/enzyme-adapter-react-16/.babelrc
Expand Up @@ -2,5 +2,7 @@
"presets": ["airbnb"],
"plugins": [
["transform-replace-object-assign", { "moduleSpecifier": "object.assign" }],
"syntax-dynamic-import",
"dynamic-import-node"
],
}
7 changes: 7 additions & 0 deletions packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
Expand Up @@ -20,8 +20,10 @@ import {
ContextProvider,
StrictMode,
ForwardRef,
Lazy,
Profiler,
Portal,
Suspense,
} from 'react-is';
import { EnzymeAdapter } from 'enzyme';
import { typeOfNode } from 'enzyme/build/Utils';
Expand Down Expand Up @@ -187,6 +189,9 @@ function toTree(vnode) {
rendered: childrenToTree(node.child),
};
}
case FiberTags.Suspense:
case FiberTags.Lazy:
return childrenToTree(node.child);
default:
throw new Error(`Enzyme Internal Error: unknown node with tag ${node.tag}`);
}
Expand Down Expand Up @@ -504,6 +509,7 @@ class ReactSixteenAdapter extends EnzymeAdapter {
case StrictMode || NaN: return 'StrictMode';
case Profiler || NaN: return 'Profiler';
case Portal || NaN: return 'Portal';
case Suspense || NaN: return 'Suspense';
default:
}
}
Expand All @@ -520,6 +526,7 @@ class ReactSixteenAdapter extends EnzymeAdapter {
const name = type.render.displayName || functionName(type.render);
return name ? `ForwardRef(${name})` : 'ForwardRef';
}
case Lazy || NaN: return 'Lazy';
default: return displayNameOfNode(node);
}
}
Expand Down
@@ -0,0 +1,5 @@
import React from 'react';

const DynamicComponent = () => <div>Dynamic Component</div>;

module.exports = DynamicComponent;
Expand Up @@ -14,10 +14,38 @@ function getFiber(element) {
return inst._reactInternalFiber.child;
}

function getLazyFiber(LazyComponent) {
const container = global.document.createElement('div');
let inst = null;
// eslint-disable-next-line react/prefer-stateless-function
class Tester extends React.Component {
render() {
inst = this;
return (
<LazyComponent />
);
}
}
// eslint-disable-next-line react/prefer-stateless-function
class SuspenseWrapper extends React.Component {
render() {
return (
<React.Suspense fallback={false}>
<Tester />
</React.Suspense>
);
}
}
ReactDOM.render(React.createElement(SuspenseWrapper), container);
return inst._reactInternalFiber.child;
}

module.exports = function detectFiberTags() {
const supportsMode = typeof React.StrictMode !== 'undefined';
const supportsContext = typeof React.createContext !== 'undefined';
const supportsForwardRef = typeof React.forwardRef !== 'undefined';
const supportsSuspense = typeof React.Suspense !== 'undefined';
const supportsLazy = typeof React.lazy !== 'undefined';

function Fn() {
return null;
Expand All @@ -30,6 +58,7 @@ module.exports = function detectFiberTags() {
}
let Ctx = null;
let FwdRef = null;
let LazyComponent = null;
if (supportsContext) {
Ctx = React.createContext();
}
Expand All @@ -38,6 +67,9 @@ module.exports = function detectFiberTags() {
// eslint-disable-next-line no-unused-vars
FwdRef = React.forwardRef((props, ref) => null);
}
if (supportsLazy) {
LazyComponent = React.lazy(() => import('./_helpers/dynamicImportedComponent'));
}

return {
HostRoot: getFiber('test').return.return.tag, // Go two levels above to find the root
Expand All @@ -59,5 +91,11 @@ module.exports = function detectFiberTags() {
ForwardRef: supportsForwardRef
? getFiber(React.createElement(FwdRef)).tag
: -1,
Suspense: supportsSuspense
? getFiber(React.createElement(React.Suspense, { fallback: false })).tag
: -1,
Lazy: supportsLazy
? getLazyFiber(LazyComponent).tag
: -1,
};
};
10 changes: 10 additions & 0 deletions packages/enzyme-test-suite/test/Adapter-spec.jsx
Expand Up @@ -21,6 +21,7 @@ import {
AsyncMode,
ConcurrentMode,
Profiler,
Suspense,
} from './_helpers/react-compat';
import { is } from './_helpers/version';
import { itIf, describeWithDOM, describeIf } from './_helpers';
Expand Down Expand Up @@ -1009,6 +1010,15 @@ describe('Adapter', () => {
itIf(is('>= 16.6'), 'supports ConcurrentMode', () => {
expect(getDisplayName(<ConcurrentMode />)).to.equal('ConcurrentMode');
});

itIf(is('>= 16.6'), 'supports Suspense', () => {
expect(getDisplayName(<Suspense />)).to.equal('Suspense');
});

itIf(is('>= 16.6'), 'supports lazy', () => {
const LazyComponent = lazy(() => import('./_helpers/dynamicImportedComponent'));
expect(getDisplayName(<LazyComponent />)).to.equal('Lazy');
});
});

describeIf(is('>= 16.2'), 'determines if node isFragment', () => {
Expand Down
40 changes: 40 additions & 0 deletions packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Expand Up @@ -26,9 +26,11 @@ import {
createContext,
createPortal,
createRef,
lazy,
Fragment,
forwardRef,
PureComponent,
Suspense,
} from './_helpers/react-compat';
import {
describeWithDOM,
Expand Down Expand Up @@ -560,6 +562,44 @@ describeWithDOM('mount', () => {
});
});

describeIf(is('>= 16.6'), 'Suspense & lazy', () => {
it('finds Suspense and its children when no lazy component', () => {
class Component extends React.Component {
render() {
return (
<div>test</div>
);
}
}
const SuspenseComponent = () => (
<Suspense fallback={false}>
<Component />
</Suspense>
);

const wrapper = mount(<SuspenseComponent />);

expect(wrapper.find('SuspenseComponent')).to.have.lengthOf(1);
expect(wrapper.find(Component)).to.have.lengthOf(1);
});

it('finds fallback when given lazy component', () => {
const LazyComponent = lazy(() => import('./_helpers/dynamicImportedComponent.jsx'));
const Fallback = () => <div />;
const SuspenseComponent = () => (
<Suspense fallback={<Fallback />}>
<LazyComponent />
</Suspense>
);

const wrapper = mount(<SuspenseComponent />);

expect(wrapper.find('SuspenseComponent')).to.have.lengthOf(1);
expect(wrapper.find(LazyComponent)).to.have.lengthOf(0);
expect(wrapper.find('Fallback')).to.have.lengthOf(1);
});
});

describe('.contains(node)', () => {
it('allows matches on the root node', () => {
const a = <div className="foo" />;
Expand Down
41 changes: 41 additions & 0 deletions packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Expand Up @@ -26,9 +26,11 @@ import {
createContext,
createPortal,
createRef,
lazy,
Fragment,
forwardRef,
PureComponent,
Suspense,
} from './_helpers/react-compat';
import {
describeIf,
Expand Down Expand Up @@ -1273,6 +1275,45 @@ describe('shallow', () => {
expect(wrapper.find(Component.displayName)).to.have.lengthOf(2);
});
});

describeIf(is('>= 16.6'), 'Suspense & lazy', () => {
it('finds Suspense and its children when no lazy component', () => {
class Component extends React.Component {
render() {
return (
<div>test</div>
);
}
}
const SuspenseComponent = () => (
<Suspense fallback={false}>
<Component />
</Suspense>
);

const wrapper = shallow(<SuspenseComponent />);

expect(wrapper.find('Suspense')).to.have.lengthOf(1);
expect(wrapper.find(Component)).to.have.lengthOf(1);
});

it('finds Lazy when given lazy component', () => {
const LazyComponent = lazy(() => import('./_helpers/dynamicImportedComponent.jsx'));
const Fallback = () => <div />;
const SuspenseComponent = () => (
<Suspense fallback={<Fallback />}>
<LazyComponent />
</Suspense>
);

const wrapper = shallow(<SuspenseComponent />);

expect(wrapper.find('Suspense')).to.have.lengthOf(1);
expect(wrapper.find(LazyComponent)).to.have.lengthOf(1);
// won't render fallback in shallow renderer
expect(wrapper.find(Fallback)).to.have.lengthOf(0);
});
});
});

describe('.findWhere(predicate)', () => {
Expand Down
@@ -1,11 +1,5 @@
import React from 'react'
import React from 'react';

class DynamicComponent extends React.Component {
render() {
return (
<div>Dynamic Component</div>
);
}
}
const DynamicComponent = () => <div>Dynamic Component</div>;

module.exports = DynamicComponent;
module.exports = DynamicComponent;

0 comments on commit e656f7a

Please sign in to comment.