diff --git a/packages/enzyme-adapter-react-16/.babelrc b/packages/enzyme-adapter-react-16/.babelrc
index d6bfb99df..c5568b914 100644
--- a/packages/enzyme-adapter-react-16/.babelrc
+++ b/packages/enzyme-adapter-react-16/.babelrc
@@ -2,5 +2,7 @@
"presets": ["airbnb"],
"plugins": [
["transform-replace-object-assign", { "moduleSpecifier": "object.assign" }],
+ "syntax-dynamic-import",
+ "dynamic-import-node"
],
}
diff --git a/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js b/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
index 3840f47f6..3fe38d6c6 100644
--- a/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
+++ b/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
@@ -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';
@@ -187,6 +189,19 @@ function toTree(vnode) {
rendered: childrenToTree(node.child),
};
}
+ case FiberTags.Suspense: {
+ return {
+ nodeType: 'suspense',
+ type: Suspense,
+ props: { ...node.memoizedProps },
+ key: ensureKeyOrUndefined(node.key),
+ ref: node.ref,
+ instance: null,
+ rendered: childrenToTree(node.child),
+ };
+ }
+ case FiberTags.Lazy:
+ return childrenToTree(node.child);
default:
throw new Error(`Enzyme Internal Error: unknown node with tag ${node.tag}`);
}
@@ -504,6 +519,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:
}
}
@@ -520,6 +536,7 @@ class ReactSixteenAdapter extends EnzymeAdapter {
const name = type.render.displayName || functionName(type.render);
return name ? `ForwardRef(${name})` : 'ForwardRef';
}
+ case Lazy || NaN: return 'LazyComponent';
default: return displayNameOfNode(node);
}
}
diff --git a/packages/enzyme-adapter-react-16/src/_helpers/dynamicImportedComponent.jsx b/packages/enzyme-adapter-react-16/src/_helpers/dynamicImportedComponent.jsx
new file mode 100644
index 000000000..2a938ffd1
--- /dev/null
+++ b/packages/enzyme-adapter-react-16/src/_helpers/dynamicImportedComponent.jsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+const DynamicComponent = () =>
Dynamic Component
;
+
+module.exports = DynamicComponent;
diff --git a/packages/enzyme-adapter-react-16/src/detectFiberTags.js b/packages/enzyme-adapter-react-16/src/detectFiberTags.jsx
similarity index 63%
rename from packages/enzyme-adapter-react-16/src/detectFiberTags.js
rename to packages/enzyme-adapter-react-16/src/detectFiberTags.jsx
index 57c037a91..b2b65228f 100644
--- a/packages/enzyme-adapter-react-16/src/detectFiberTags.js
+++ b/packages/enzyme-adapter-react-16/src/detectFiberTags.jsx
@@ -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 (
+
+ );
+ }
+ }
+ // eslint-disable-next-line react/prefer-stateless-function
+ class SuspenseWrapper extends React.Component {
+ render() {
+ return (
+
+
+
+ );
+ }
+ }
+ 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;
@@ -30,6 +58,7 @@ module.exports = function detectFiberTags() {
}
let Ctx = null;
let FwdRef = null;
+ let LazyComponent = null;
if (supportsContext) {
Ctx = React.createContext();
}
@@ -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
@@ -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,
};
};
diff --git a/packages/enzyme-test-suite/test/Adapter-spec.jsx b/packages/enzyme-test-suite/test/Adapter-spec.jsx
index 3ab12ee2b..12946cb22 100644
--- a/packages/enzyme-test-suite/test/Adapter-spec.jsx
+++ b/packages/enzyme-test-suite/test/Adapter-spec.jsx
@@ -21,6 +21,7 @@ import {
AsyncMode,
ConcurrentMode,
Profiler,
+ Suspense,
} from './_helpers/react-compat';
import { is } from './_helpers/version';
import { itIf, describeWithDOM, describeIf } from './_helpers';
@@ -1009,6 +1010,15 @@ describe('Adapter', () => {
itIf(is('>= 16.6'), 'supports ConcurrentMode', () => {
expect(getDisplayName()).to.equal('ConcurrentMode');
});
+
+ itIf(is('>= 16.6'), 'supports Suspense', () => {
+ expect(getDisplayName()).to.equal('Suspense');
+ });
+
+ itIf(is('>= 16.6'), 'supports lazy', () => {
+ const LazyComponent = lazy(() => import('./_helpers/dynamicImportedComponent'));
+ expect(getDisplayName()).to.equal('LazyComponent');
+ });
});
describeIf(is('>= 16.2'), 'determines if node isFragment', () => {
diff --git a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
index 2afb6bd44..6e9a57cef 100644
--- a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
+++ b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
@@ -26,9 +26,11 @@ import {
createContext,
createPortal,
createRef,
+ lazy,
Fragment,
forwardRef,
PureComponent,
+ Suspense,
} from './_helpers/react-compat';
import {
describeWithDOM,
@@ -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 (
+ test
+ );
+ }
+ }
+ const SuspenseComponent = () => (
+
+
+
+ );
+
+ const wrapper = mount();
+
+ expect(wrapper.find('SuspenseComponent')).to.have.lengthOf(1);
+ expect(wrapper.find(Component)).to.have.lengthOf(1);
+ });
+
+ it('finds fallback when given lazy component in initial mount', () => {
+ const LazyComponent = lazy(() => import('./_helpers/dynamicImportedComponent.jsx'));
+ const Fallback = () => ;
+ const SuspenseComponent = () => (
+ }>
+
+
+ );
+
+ const wrapper = mount();
+
+ 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 = ;
diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
index 1f5ed13d5..e28684573 100644
--- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
+++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
@@ -26,9 +26,11 @@ import {
createContext,
createPortal,
createRef,
+ lazy,
Fragment,
forwardRef,
PureComponent,
+ Suspense,
} from './_helpers/react-compat';
import {
describeIf,
@@ -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 (
+ test
+ );
+ }
+ }
+ const SuspenseComponent = () => (
+
+
+
+ );
+
+ const wrapper = shallow();
+
+ 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 = () => ;
+ const SuspenseComponent = () => (
+ }>
+
+
+ );
+
+ const wrapper = shallow();
+
+ 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)', () => {
diff --git a/packages/enzyme-test-suite/test/_helpers/dynamicImportedComponent.jsx b/packages/enzyme-test-suite/test/_helpers/dynamicImportedComponent.jsx
index 3afa41bb0..2a938ffd1 100644
--- a/packages/enzyme-test-suite/test/_helpers/dynamicImportedComponent.jsx
+++ b/packages/enzyme-test-suite/test/_helpers/dynamicImportedComponent.jsx
@@ -1,11 +1,5 @@
-import React from 'react'
+import React from 'react';
-class DynamicComponent extends React.Component {
- render() {
- return (
- Dynamic Component
- );
- }
-}
+const DynamicComponent = () => Dynamic Component
;
-module.exports = DynamicComponent;
\ No newline at end of file
+module.exports = DynamicComponent;