Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React adapter 16: portals and roots may render fragments #1710

Merged
merged 2 commits into from
Jul 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ function toTree(vnode) {
const node = findCurrentFiberUsingSlowPath(vnode);
switch (node.tag) {
case HostRoot: // 3
return toTree(node.child);
case HostPortal: // 4
return toTree(node.child);
return childrenToTree(node.child);
case HostPortal: { // 4
return childrenToTree(node.child);
}
case ClassComponent:
return {
nodeType: 'class',
Expand Down Expand Up @@ -251,11 +252,13 @@ class ReactSixteenAdapter extends EnzymeAdapter {
} else {
isDOM = false;
const { type: Component } = el;

const isStateful = Component.prototype && (
Component.prototype.isReactComponent
|| Array.isArray(Component.__reactAutoBindPairs) // fallback for createClass components
);
if (!isStateful) {

if (!isStateful && typeof Component === 'function') {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just so we get a clearer error is a user tries to mount a Fragment or Portal, they will see the ShallowTestRenderer informative error instead of the much less clear "Component is not a function"

const wrappedEl = Object.assign(
(...args) => Component(...args), // eslint-disable-line new-cap
Component,
Expand Down
46 changes: 44 additions & 2 deletions packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import {
} from 'enzyme/build/Utils';

import './_helpers/setupAdapters';
import { createClass, createContext, createPortal } from './_helpers/react-compat';
import {
createClass,
createContext,
createPortal,
Fragment,
} from './_helpers/react-compat';
import {
describeWithDOM,
describeIf,
Expand Down Expand Up @@ -776,6 +781,43 @@ describeWithDOM('mount', () => {
expect(wrapper.find('button')).to.have.lengthOf(1);
});

itIf(is('>= 16.2'), 'should support fragments', () => {
const wrapper = mount((
<Fragment>
<p>hello</p>
<span>boo</span>
</Fragment>
));

expect(wrapper).to.have.lengthOf(2);
});

itIf(is('>= 16'), 'should find elements through portals', () => {
const containerDiv = global.document.createElement('div');
class FooPortal extends React.Component {
render() {
return createPortal(
this.props.children,
containerDiv,
);
}
}


const wrapper = mount((
<FooPortal>
<h1>Successful Portal!</h1>
<span />
</FooPortal>
));

expect(wrapper.find('h1')).to.have.lengthOf(1);

expect(wrapper.find('span')).to.have.lengthOf(1);

expect(containerDiv.querySelectorAll('h1')).to.have.lengthOf(1);
});

it('should support object property selectors', () => {
const wrapper = mount((
<div>
Expand Down Expand Up @@ -4193,7 +4235,7 @@ describeWithDOM('mount', () => {
});
});

describeIf(ITERATOR_SYMBOL, '@@iterator', () => {
describeIf(!!ITERATOR_SYMBOL, '@@iterator', () => {
it('should be iterable', () => {
class Foo extends React.Component {
render() {
Expand Down
2 changes: 1 addition & 1 deletion packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5173,7 +5173,7 @@ describe('shallow', () => {
});
});

describeIf(ITERATOR_SYMBOL, '@@iterator', () => {
describeIf(!!ITERATOR_SYMBOL, '@@iterator', () => {
it('should be iterable', () => {
class Foo extends React.Component {
render() {
Expand Down
16 changes: 16 additions & 0 deletions packages/enzyme-test-suite/test/_helpers/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import React from 'react';
* determines whether or not the test will be run
*/
export function describeIf(test, a, b) {
if (typeof test !== 'boolean') {
throw new TypeError(`a boolean is required, you passed a ${typeof test}`);
}

if (test) {
describe(a, b);
} else {
Expand All @@ -19,13 +23,25 @@ export function describeIf(test, a, b) {
* determines whether or not the test will be run
*/
export function itIf(test, a, b) {
if (typeof test !== 'boolean') {
throw new TypeError(`a boolean is required, you passed a ${typeof test}`);
}

if (test) {
it(a, b);
} else {
it.skip(a, b);
}
}

itIf.only = (test, a, b) => {
if (test) {
it.only(a, b);
} else {
it.skip(a, b);
}
};

/**
* Simple wrapper around mocha it which allows an array of possible values to test against.
* Each test will be wrapped in a try/catch block to handle any errors.
Expand Down