diff --git a/docs/api/ShallowWrapper/instance.md b/docs/api/ShallowWrapper/instance.md index 487a34eac..a67af46e0 100644 --- a/docs/api/ShallowWrapper/instance.md +++ b/docs/api/ShallowWrapper/instance.md @@ -30,7 +30,7 @@ class Stateful extends React.Component { ``` #### React 16.x ```jsx -test('shallow wrapper instance should not be null', () => { +test('shallow wrapper instance should be null', () => { const wrapper = shallow(); const instance = wrapper.instance(); diff --git a/package.json b/package.json index 01c8446d4..5d7c19e48 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,6 @@ "author": "Leland Richardson ", "license": "MIT", "devDependencies": { - "acorn": "^6.0.4", - "acorn-jsx": "^5.0.1", "babel-cli": "^6.26.0", "babel-core": "^6.26.3", "babel-eslint": "^7.2.3", @@ -71,20 +69,19 @@ "babel-register": "^6.26.0", "chai": "^4.2.0", "coveralls": "^2.13.3", - "eslint": "^5.9.0", + "eslint": "^5.12.0", "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-markdown": "^1.0.0-rc.0", - "eslint-plugin-react": "^7.11.1", - "espree": "^4.1.0", + "eslint-plugin-markdown": "^1.0.0", + "eslint-plugin-react": "^7.12.2", "gitbook-cli": "^1.0.1", "gitbook-plugin-anchors": "^0.7.1", "gitbook-plugin-codeblock-disable-glossary": "0.0.1", "gitbook-plugin-collapsible-menu": "^1.0.3", "gitbook-plugin-edit-link": "^2.0.2", "gitbook-plugin-github": "^2.0.0", - "glob-gitignore": "^1.0.9", + "glob-gitignore": "^1.0.11", "in-publish": "^2.0.0", "istanbul": "^1.0.0-alpha.2", "istanbul-api": "^1.3.7", @@ -98,7 +95,7 @@ "lerna": "^2.11.0", "mocha": "^3.5.3", "prop-types": "^15.6.2", - "rimraf": "^2.6.2", + "rimraf": "^2.6.3", "safe-publish-latest": "^1.1.2", "webpack": "^1.15.0" }, diff --git a/packages/enzyme-adapter-react-13/package.json b/packages/enzyme-adapter-react-13/package.json index 94e2938b2..d7dbe0a77 100644 --- a/packages/enzyme-adapter-react-13/package.json +++ b/packages/enzyme-adapter-react-13/package.json @@ -52,7 +52,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-14/package.json b/packages/enzyme-adapter-react-14/package.json index 31eb03fcd..7a2c0fe9b 100644 --- a/packages/enzyme-adapter-react-14/package.json +++ b/packages/enzyme-adapter-react-14/package.json @@ -55,7 +55,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-15.4/package.json b/packages/enzyme-adapter-react-15.4/package.json index f60312e90..fb7397618 100644 --- a/packages/enzyme-adapter-react-15.4/package.json +++ b/packages/enzyme-adapter-react-15.4/package.json @@ -56,7 +56,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-15/package.json b/packages/enzyme-adapter-react-15/package.json index 893dc22d8..71cb14f9c 100644 --- a/packages/enzyme-adapter-react-15/package.json +++ b/packages/enzyme-adapter-react-15/package.json @@ -55,7 +55,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-16.1/package.json b/packages/enzyme-adapter-react-16.1/package.json index 0df23ba56..6012166fa 100644 --- a/packages/enzyme-adapter-react-16.1/package.json +++ b/packages/enzyme-adapter-react-16.1/package.json @@ -55,7 +55,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-16.1/src/ReactSixteenOneAdapter.js b/packages/enzyme-adapter-react-16.1/src/ReactSixteenOneAdapter.js index d59974ca3..b4ea3a9d5 100644 --- a/packages/enzyme-adapter-react-16.1/src/ReactSixteenOneAdapter.js +++ b/packages/enzyme-adapter-react-16.1/src/ReactSixteenOneAdapter.js @@ -29,6 +29,7 @@ import { ensureKeyOrUndefined, simulateError, wrap, + getMaskedContext, } from 'enzyme-adapter-utils'; import { findCurrentFiberUsingSlowPath } from 'react-reconciler/reflection'; @@ -315,7 +316,7 @@ class ReactSixteenOneAdapter extends EnzymeAdapter { let isDOM = false; let cachedNode = null; return { - render(el, context) { + render(el, unmaskedContext) { cachedNode = el; /* eslint consistent-return: 0 */ if (typeof el.type === 'string') { @@ -328,6 +329,7 @@ class ReactSixteenOneAdapter extends EnzymeAdapter { Component.prototype.isReactComponent || Array.isArray(Component.__reactAutoBindPairs) // fallback for createClass components ); + const context = getMaskedContext(Component.contextTypes, unmaskedContext); if (!isStateful && typeof Component === 'function') { const wrappedEl = Object.assign( diff --git a/packages/enzyme-adapter-react-16.2/package.json b/packages/enzyme-adapter-react-16.2/package.json index ab9d703c0..ec8309184 100644 --- a/packages/enzyme-adapter-react-16.2/package.json +++ b/packages/enzyme-adapter-react-16.2/package.json @@ -56,7 +56,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-16.2/src/ReactSixteenTwoAdapter.js b/packages/enzyme-adapter-react-16.2/src/ReactSixteenTwoAdapter.js index 4b64a859f..618e36aa4 100644 --- a/packages/enzyme-adapter-react-16.2/src/ReactSixteenTwoAdapter.js +++ b/packages/enzyme-adapter-react-16.2/src/ReactSixteenTwoAdapter.js @@ -30,6 +30,7 @@ import { ensureKeyOrUndefined, simulateError, wrap, + getMaskedContext, } from 'enzyme-adapter-utils'; import { findCurrentFiberUsingSlowPath } from 'react-reconciler/reflection'; @@ -317,7 +318,7 @@ class ReactSixteenTwoAdapter extends EnzymeAdapter { let isDOM = false; let cachedNode = null; return { - render(el, context) { + render(el, unmaskedContext) { cachedNode = el; /* eslint consistent-return: 0 */ if (typeof el.type === 'string') { @@ -330,6 +331,7 @@ class ReactSixteenTwoAdapter extends EnzymeAdapter { Component.prototype.isReactComponent || Array.isArray(Component.__reactAutoBindPairs) // fallback for createClass components ); + const context = getMaskedContext(Component.contextTypes, unmaskedContext); if (!isStateful && typeof Component === 'function') { const wrappedEl = Object.assign( diff --git a/packages/enzyme-adapter-react-16.3/package.json b/packages/enzyme-adapter-react-16.3/package.json index 01a8e8180..bcb90c1bb 100644 --- a/packages/enzyme-adapter-react-16.3/package.json +++ b/packages/enzyme-adapter-react-16.3/package.json @@ -57,7 +57,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-16/package.json b/packages/enzyme-adapter-react-16/package.json index 6de706e43..b455275a5 100644 --- a/packages/enzyme-adapter-react-16/package.json +++ b/packages/enzyme-adapter-react-16/package.json @@ -56,7 +56,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js b/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js index 3fe38d6c6..071f707a4 100644 --- a/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js +++ b/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js @@ -41,6 +41,7 @@ import { ensureKeyOrUndefined, simulateError, wrap, + getMaskedContext, } from 'enzyme-adapter-utils'; import findCurrentFiberUsingSlowPath from './findCurrentFiberUsingSlowPath'; import detectFiberTags from './detectFiberTags'; @@ -358,7 +359,7 @@ class ReactSixteenAdapter extends EnzymeAdapter { let isDOM = false; let cachedNode = null; return { - render(el, context) { + render(el, unmaskedContext) { cachedNode = el; /* eslint consistent-return: 0 */ if (typeof el.type === 'string') { @@ -372,6 +373,7 @@ class ReactSixteenAdapter extends EnzymeAdapter { || Array.isArray(Component.__reactAutoBindPairs) // fallback for createClass components ); + const context = getMaskedContext(Component.contextTypes, unmaskedContext); if (!isStateful && typeof Component === 'function') { const wrappedEl = Object.assign( (...args) => Component(...args), // eslint-disable-line new-cap diff --git a/packages/enzyme-adapter-react-helper/package.json b/packages/enzyme-adapter-react-helper/package.json index 052a10e3a..8fd93b863 100644 --- a/packages/enzyme-adapter-react-helper/package.json +++ b/packages/enzyme-adapter-react-helper/package.json @@ -46,7 +46,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "react": "0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0 || ^16.3.0-0 || ^16.4.0-0", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-utils/package.json b/packages/enzyme-adapter-utils/package.json index 06006c870..e4b86bd2a 100644 --- a/packages/enzyme-adapter-utils/package.json +++ b/packages/enzyme-adapter-utils/package.json @@ -36,6 +36,7 @@ "dependencies": { "function.prototype.name": "^1.1.0", "object.assign": "^4.1.0", + "object.fromentries": "^2.0.0", "prop-types": "^15.6.2", "semver": "^5.6.0" }, @@ -50,7 +51,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "rimraf": "^2.6.2", "safe-publish-latest": "^1.1.2" diff --git a/packages/enzyme-adapter-utils/src/Utils.js b/packages/enzyme-adapter-utils/src/Utils.js index d4c37d3e8..35ba6d139 100644 --- a/packages/enzyme-adapter-utils/src/Utils.js +++ b/packages/enzyme-adapter-utils/src/Utils.js @@ -1,4 +1,5 @@ import functionName from 'function.prototype.name'; +import fromEntries from 'object.fromentries'; import createMountWrapper from './createMountWrapper'; import createRenderWrapper from './createRenderWrapper'; import wrap from './wrapWithSimpleWrapper'; @@ -282,4 +283,10 @@ export function simulateError( export function fakeDynamicImport(moduleToImport) { return Promise.resolve({ default: moduleToImport }); + +export function getMaskedContext(contextTypes, unmaskedContext) { + if (!contextTypes || !unmaskedContext) { + return {}; + } + return fromEntries(Object.keys(contextTypes).map(key => [key, unmaskedContext[key]])); } diff --git a/packages/enzyme-example-mocha/package.json b/packages/enzyme-example-mocha/package.json index b3e6e19d4..7abe00e43 100644 --- a/packages/enzyme-example-mocha/package.json +++ b/packages/enzyme-example-mocha/package.json @@ -25,7 +25,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "espree": "^4.1.0", "in-publish": "^2.0.0", "jsdom": "^11.5.1", diff --git a/packages/enzyme-test-suite/package.json b/packages/enzyme-test-suite/package.json index 32842fb2f..ceae11af7 100644 --- a/packages/enzyme-test-suite/package.json +++ b/packages/enzyme-test-suite/package.json @@ -52,7 +52,7 @@ "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", "eslint-plugin-mocha": "^5.2.0", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "react-is": "^16.7.0" } } diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx index 69b333a75..3b9359570 100644 --- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx +++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx @@ -4536,6 +4536,30 @@ describe('shallow', () => { expect(wrapper.context().name).to.equal(context.name); expect(wrapper.context('name')).to.equal(context.name); }); + + it('filters context to childContextTypes', () => { + class Bar extends React.Component { + render() { + return
; + } + } + Bar.contextTypes = { + name: PropTypes.string, + }; + class Foo extends React.Component { + render() { + return ( +
+ +
+ ); + } + } + + const context = { name: 'foo', hello: 'world' }; + const wrapper = shallow(, { context }); + expect(wrapper.find(Bar).dive().context()).to.eql({ name: 'foo' }); + }); }); describeIf(is('> 0.13'), 'stateless function components', () => { diff --git a/packages/enzyme-test-suite/test/adapter-utils-spec.jsx b/packages/enzyme-test-suite/test/adapter-utils-spec.jsx index 162f49f72..a308bd9e6 100644 --- a/packages/enzyme-test-suite/test/adapter-utils-spec.jsx +++ b/packages/enzyme-test-suite/test/adapter-utils-spec.jsx @@ -3,6 +3,7 @@ import { expect } from 'chai'; import { displayNameOfNode, ensureKeyOrUndefined, + getMaskedContext, } from 'enzyme-adapter-utils'; import './_helpers/setupAdapters'; @@ -82,4 +83,36 @@ describe('enzyme-adapter-utils', () => { }); }); }); + + describe('getMaskedContext', () => { + const contextTypes = { + a() {}, + c() {}, + }; + const unmaskedContext = { + a: 1, + b: 2, + c: 3, + }; + const falsies = [undefined, null, false, '', NaN, 0]; + + it('returns an empty object with falsy `contextTypes`', () => { + falsies.forEach((falsy) => { + expect(getMaskedContext(falsy, unmaskedContext)).to.eql({}); + }); + }); + + it('returns an empty object with falsy `unmaskedContext`', () => { + falsies.forEach((falsy) => { + expect(getMaskedContext(contextTypes, falsy)).to.eql({}); + }); + }); + + it('filters `unmaskedContext` down to `contextTypes`', () => { + expect(getMaskedContext(contextTypes, unmaskedContext)).to.eql({ + a: unmaskedContext.a, + c: unmaskedContext.c, + }); + }); + }); }); diff --git a/packages/enzyme-test-suite/test/selector-spec.jsx b/packages/enzyme-test-suite/test/selector-spec.jsx index d9d76bbdb..13d03e3f1 100644 --- a/packages/enzyme-test-suite/test/selector-spec.jsx +++ b/packages/enzyme-test-suite/test/selector-spec.jsx @@ -6,7 +6,7 @@ import { } from 'enzyme'; import './_helpers/setupAdapters'; -import { describeWithDOM } from './_helpers'; +import { describeWithDOM, describeIf } from './_helpers'; const tests = [ { @@ -283,6 +283,72 @@ describe('selectors', () => { expect(wrapper.find('span:last-child').text()).to.equal('last'); }); + describeIf(name === 'mount', ':focus pseudo selector', () => { + it('works in mount with directly focused DOM node', () => { + const wrapper = renderMethod(( + + )); + const inputNode = wrapper.find('input'); + + expect(inputNode.is(':focus')).to.equal(false); + + const inputDOMNode = wrapper.getDOMNode(); + inputDOMNode.focus(); + + expect(inputNode.is(':focus')).to.equal(true); + }); + + it('works on component in mount', () => { + class ClassComponent extends React.Component { + render() { + return ( + + ); + } + } + + const wrapper = renderMethod(( + + )); + + expect(wrapper.find('ClassComponent:focus')).to.have.lengthOf(0); + + const inputDOMNode = wrapper.getDOMNode(); + inputDOMNode.focus(); + + expect(wrapper.find('ClassComponent:focus')).to.have.lengthOf(1); + }); + + it('works on nested component in mount', () => { + class InnerComponent extends React.Component { + render() { + return ( + + ); + } + } + class WrapComponent extends React.Component { + render() { + return ; + } + } + const wrapper = renderMethod(( + + )); + + expect(wrapper.find('InnerComponent:focus')).to.have.lengthOf(0); + expect(wrapper.find('WrapComponent:focus')).to.have.lengthOf(0); + expect(wrapper.find('input:focus')).to.have.lengthOf(0); + + const inputDOMNode = wrapper.getDOMNode(); + inputDOMNode.focus(); + + expect(wrapper.find('InnerComponent:focus')).to.have.lengthOf(1); + expect(wrapper.find('WrapComponent:focus')).to.have.lengthOf(1); + expect(wrapper.find('input:focus')).to.have.lengthOf(1); + }); + }); + it('throws for complex selectors in simple selector methods', () => { const wrapper = renderMethod(
); ['is', 'filter', 'not', 'every'].forEach((method) => { diff --git a/packages/enzyme/package.json b/packages/enzyme/package.json index 75e44631d..90aadce12 100644 --- a/packages/enzyme/package.json +++ b/packages/enzyme/package.json @@ -62,7 +62,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", - "eslint-plugin-react": "^7.11.1", + "eslint-plugin-react": "^7.12.3", "in-publish": "^2.0.0", "jsdom": "^6.5.1", "rimraf": "^2.6.2", diff --git a/packages/enzyme/src/selectors.js b/packages/enzyme/src/selectors.js index 57f4a3aff..4b3f42dfe 100644 --- a/packages/enzyme/src/selectors.js +++ b/packages/enzyme/src/selectors.js @@ -160,6 +160,14 @@ function matchPseudoSelector(node, token, root) { const { rendered } = findParentNode(root, node); return rendered[rendered.length - 1] === node; } + if (name === 'focus') { + if (typeof document === 'undefined') { + throw new Error('Enzyme::Selector does not support the ":focus" pseudo-element without a global `document`.'); + } + const adapter = getAdapter(); + /* eslint-env browser */ + return document.activeElement && adapter.nodeToHostNode(node) === document.activeElement; + } throw new TypeError(`Enzyme::Selector does not support the "${token.name}" pseudo-element or pseudo-class selectors.`); }