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

Add additional type checks to adapters #1701

Merged
merged 6 commits into from
Jul 22, 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
9 changes: 9 additions & 0 deletions packages/enzyme-adapter-react-13/src/ReactThirteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ReactContext from 'react/lib/ReactContext';
import values from 'object.values';
import { EnzymeAdapter } from 'enzyme';
import {
displayNameOfNode,
propFromEvent,
withSetStateAllowed,
assertDomAvailable,
Expand Down Expand Up @@ -249,6 +250,10 @@ class ReactThirteenAdapter extends EnzymeAdapter {
return React.createElement(node.type, propsWithKeysAndRef(node));
}

displayNameOfNode(node) {
return displayNameOfNode(node);
}

elementToNode(element) {
return elementToTree(element);
}
Expand All @@ -261,6 +266,10 @@ class ReactThirteenAdapter extends EnzymeAdapter {
return React.isValidElement(element);
}

isValidElementType(object) {
return typeof object === 'string' || typeof object === 'function';
}

createElement(...args) {
return React.createElement(...args);
}
Expand Down
11 changes: 10 additions & 1 deletion packages/enzyme-adapter-react-14/src/ReactFourteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import ReactDOMServer from 'react-dom/server';
// eslint-disable-next-line import/no-unresolved, import/extensions
import TestUtils from 'react-addons-test-utils';
import values from 'object.values';
import { isElement } from 'react-is';
import { isElement, isValidElementType } from 'react-is';
import { EnzymeAdapter } from 'enzyme';
import {
displayNameOfNode,
elementToTree,
mapNativeEventNames,
propFromEvent,
Expand Down Expand Up @@ -229,10 +230,18 @@ class ReactFourteenAdapter extends EnzymeAdapter {
return ReactDOM.findDOMNode(node.instance);
}

displayNameOfNode(node) {
return displayNameOfNode(node);
}

isValidElement(element) {
return isElement(element);
}

isValidElementType(object) {
return isValidElementType(object);
}

createElement(...args) {
return React.createElement(...args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import ReactDOMServer from 'react-dom/server';
// eslint-disable-next-line import/no-unresolved, import/extensions
import TestUtils from 'react-addons-test-utils';
import values from 'object.values';
import { isElement } from 'react-is';
import { isElement, isValidElementType } from 'react-is';
import { EnzymeAdapter } from 'enzyme';
import {
displayNameOfNode,
elementToTree,
mapNativeEventNames,
propFromEvent,
Expand Down Expand Up @@ -262,10 +263,18 @@ class ReactFifteenFourAdapter extends EnzymeAdapter {
return ReactDOM.findDOMNode(node.instance);
}

displayNameOfNode(node) {
return displayNameOfNode(node);
}

isValidElement(element) {
return isElement(element);
}

isValidElementType(object) {
return isValidElementType(object);
}

createElement(...args) {
return React.createElement(...args);
}
Expand Down
11 changes: 10 additions & 1 deletion packages/enzyme-adapter-react-15/src/ReactFifteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import TestUtils from 'react-dom/test-utils';
// eslint-disable-next-line import/no-unresolved, import/extensions
import ShallowRenderer from 'react-test-renderer/shallow';
import values from 'object.values';
import { isElement } from 'react-is';
import { isElement, isValidElementType } from 'react-is';
import { EnzymeAdapter } from 'enzyme';
import {
displayNameOfNode,
elementToTree,
mapNativeEventNames,
propFromEvent,
Expand Down Expand Up @@ -262,10 +263,18 @@ class ReactFifteenAdapter extends EnzymeAdapter {
return ReactDOM.findDOMNode(node.instance);
}

displayNameOfNode(node) {
return displayNameOfNode(node);
}

isValidElement(element) {
return isElement(element);
}

isValidElementType(object) {
return isValidElementType(object);
}

createElement(...args) {
return React.createElement(...args);
}
Expand Down
1 change: 1 addition & 0 deletions packages/enzyme-adapter-react-16/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"license": "MIT",
"dependencies": {
"enzyme-adapter-utils": "^1.3.0",
"function.prototype.name": "^1.0.3",
"object.assign": "^4.1.0",
"object.values": "^1.0.4",
"prop-types": "^15.6.0",
Expand Down
58 changes: 51 additions & 7 deletions packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint no-use-before-define: 0 */
import functionName from 'function.prototype.name';
import React from 'react';
import ReactDOM from 'react-dom';
// eslint-disable-next-line import/no-unresolved
Expand All @@ -7,9 +8,21 @@ import ReactDOMServer from 'react-dom/server';
import ShallowRenderer from 'react-test-renderer/shallow';
// eslint-disable-next-line import/no-unresolved
import TestUtils from 'react-dom/test-utils';
import { isElement } from 'react-is';
import {
isElement,
isValidElementType,
AsyncMode,
Fragment,
ContextConsumer,
ContextProvider,
StrictMode,
ForwardRef,
Profiler,
Portal,
} from 'react-is';
import { EnzymeAdapter } from 'enzyme';
import {
displayNameOfNode,
elementToTree,
nodeTypeFromType,
mapNativeEventNames,
Expand All @@ -25,14 +38,14 @@ import { findCurrentFiberUsingSlowPath } from 'react-reconciler/reflection';

const HostRoot = 3;
const ClassComponent = 2;
const Fragment = 10;
const FragmentType = 10;
const FunctionalComponent = 1;
const HostPortal = 4;
const HostComponent = 5;
const HostText = 6;
const Mode = 11;
const ContextConsumer = 12;
const ContextProvider = 13;
const ContextConsumerType = 12;
const ContextProviderType = 13;

function nodeAndSiblingsArray(nodeWithSibling) {
const array = [];
Expand Down Expand Up @@ -113,10 +126,10 @@ function toTree(vnode) {
}
case HostText: // 6
return node.memoizedProps;
case Fragment: // 10
case FragmentType: // 10
case Mode: // 11
case ContextProvider: // 13
case ContextConsumer: // 12
case ContextProviderType: // 13
case ContextConsumerType: // 12
return childrenToTree(node.child);
default:
throw new Error(`Enzyme Internal Error: unknown node with tag ${node.tag}`);
Expand Down Expand Up @@ -337,10 +350,41 @@ class ReactSixteenAdapter extends EnzymeAdapter {
return nodeToHostNode(node);
}

displayNameOfNode(node) {
if (!node) return null;
const { type, $$typeof } = node;

switch (type || $$typeof) {
case AsyncMode: return 'AsyncMode';
case Fragment: return 'Fragment';
case StrictMode: return 'StrictMode';
case Profiler: return 'Profiler';
case Portal: return 'Portal';

default: {
const $$typeofType = type && type.$$typeof;

switch ($$typeofType) {
case ContextConsumer: return 'ContextConsumer';
case ContextProvider: return 'ContextProvider';
case ForwardRef: {
const name = type.render.displayName || functionName(type.render);
return name ? `ForwardRef(${name})` : 'ForwardRef';
}
default: return displayNameOfNode(node);
}
}
}
}

isValidElement(element) {
return isElement(element);
}

isValidElementType(object) {
return isValidElementType(object);
}

createElement(...args) {
return React.createElement(...args);
}
Expand Down
1 change: 1 addition & 0 deletions packages/enzyme-adapter-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"author": "Leland Richardson <[email protected]>",
"license": "MIT",
"dependencies": {
"function.prototype.name": "^1.0.3",
"object.assign": "^4.1.0",
"prop-types": "^15.6.0"
},
Expand Down
11 changes: 11 additions & 0 deletions packages/enzyme-adapter-utils/src/Utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import functionName from 'function.prototype.name';
import createMountWrapper from './createMountWrapper';
import createRenderWrapper from './createRenderWrapper';

Expand Down Expand Up @@ -86,6 +87,16 @@ export function assertDomAvailable(feature) {
}
}

export function displayNameOfNode(node) {
if (!node) return null;

const { type } = node;

if (!type) return null;

return type.displayName || (typeof type === 'function' ? functionName(type) : type.name || type);
}

export function nodeTypeFromType(type) {
if (typeof type === 'string') {
return 'host';
Expand Down
1 change: 1 addition & 0 deletions packages/enzyme-test-suite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"enzyme": "^3.3.0",
"enzyme-adapter-utils": "^1.3.0",
"jsdom": "^6.5.1",
"mocha-wrap": "^2.1.2",
"object.assign": "^4.1.0",
"prop-types": "^15.6.0",
"semver": "^5.5.0",
Expand Down
107 changes: 106 additions & 1 deletion packages/enzyme-test-suite/test/Adapter-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ import { configure, shallow } from 'enzyme';

import './_helpers/setupAdapters';
import Adapter from './_helpers/adapter';
import { renderToString } from './_helpers/react-compat';
import {
renderToString,
createContext,
createPortal,
forwardRef,
Fragment,
StrictMode,
AsyncMode,
Profiler,
} from './_helpers/react-compat';
import { is } from './_helpers/version';
import { itIf, describeWithDOM } from './_helpers';

Expand Down Expand Up @@ -801,4 +810,100 @@ describe('Adapter', () => {
},
}));
});

describe('determines valid element types', () => {
itIf(is('> 0.13'), 'supports stateless function components', () => {
const SFC = () => null;

expect(adapter.isValidElementType(SFC)).to.equal(true);
});

it('supports custom components', () => {
class Component extends React.Component {
render() { return null; }
}

expect(adapter.isValidElementType(Component)).to.equal(true);
});

it('supports HTML elements', () => {
expect(adapter.isValidElementType('div')).to.equal(true);
});

itIf(is('>= 16'), 'supports Portals', () => {
expect(adapter.isValidElementType(createPortal(<div />, { nodeType: 1 }))).to.equal(false);
});

itIf(is('>= 16.3'), 'supports Context', () => {
const Context = createContext({ });
expect(adapter.isValidElementType(Context.Consumer)).to.equal(true);
expect(adapter.isValidElementType(Context.Provider)).to.equal(true);
});

itIf(is('>= 16.3'), 'supports forward refs', () => {
expect(adapter.isValidElementType(forwardRef(() => null))).to.equal(true);
});
});

describe('provides node displayNames', () => {
const getDisplayName = el => adapter.displayNameOfNode(adapter.elementToNode(el));

itIf(is('> 0.13'), 'supports stateless function components', () => {
const SFC = () => null;

expect(getDisplayName(<SFC />)).to.equal('SFC');
});

it('supports custom components', () => {
class Component extends React.Component {
render() { return null; }
}
class Something extends React.Component {
render() { return null; }
}
Something.displayName = 'MyComponent';

expect(getDisplayName(<Component />)).to.equal('Component');
expect(getDisplayName(<Something />)).to.equal('MyComponent');
});

it('supports HTML elements', () => {
expect(getDisplayName(<div />)).to.equal('div');
});

itIf(is('>= 16.2'), 'supports Fragments', () => {
expect(getDisplayName(<Fragment />)).to.equal('Fragment');
});

itIf(is('>= 16'), 'supports Portals', () => {
expect(getDisplayName(createPortal(<div />, { nodeType: 1 }))).to.equal('Portal');
});

itIf(is('>= 16.3'), 'supports Context', () => {
const Context = createContext({});
expect(getDisplayName(<Context.Consumer />)).to.equal('ContextConsumer');
expect(getDisplayName(<Context.Provider />)).to.equal('ContextProvider');
});

itIf(is('>= 16.3'), 'supports forward refs', () => {
const ForwaredRef = forwardRef(() => null);
// eslint-disable-next-line prefer-arrow-callback
const NamedForwardedRef = forwardRef(function Named() { return null; });

expect(getDisplayName(<ForwaredRef />)).to.equal('ForwardRef');
expect(getDisplayName(<NamedForwardedRef />)).to.equal('ForwardRef(Named)');
});

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

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

itIf(is('>= 16.4'), 'supports Profiler', () => {
expect(getDisplayName(<Profiler />)).to.equal('Profiler');
});
});
});
Loading