From 09be72409d864e0d65ebc2aa09adb288fe1fa645 Mon Sep 17 00:00:00 2001 From: Pete Gleeson Date: Fri, 4 May 2018 15:24:38 +1000 Subject: [PATCH] adds comment about where ReactTestInstance has come from --- .../package.json | 9 ++- .../src/ReactMountWrapper.js | 55 +++++++++++++- .../src/ReactTestInstance.js | 72 ++++++------------- 3 files changed, 84 insertions(+), 52 deletions(-) diff --git a/packages/enzyme-adapter-react-renderer/package.json b/packages/enzyme-adapter-react-renderer/package.json index ec5425e10..d299e93b6 100644 --- a/packages/enzyme-adapter-react-renderer/package.json +++ b/packages/enzyme-adapter-react-renderer/package.json @@ -36,10 +36,17 @@ "dependencies": { "cheerio": "^1.0.0-rc.2", "enzyme-adapter-utils": "^1.3.0", + "has": "^1.0.1", "invariant": "^2.2.4", + "is-subset": "^0.1.1", + "lodash": "^4.17.4", + "object.entries": "^1.0.4", + "object.values": "^1.0.4", + "object-is": "^1.0.1", "react-is": "^16.3.2", "react-reconciler": "^0.7.0", - "react-test-renderer": "^16.3.2" + "react-test-renderer": "^16.3.2", + "rst-selector-parser": "^2.2.3" }, "peerDependencies": { "enzyme": "^3.0.0", diff --git a/packages/enzyme-adapter-react-renderer/src/ReactMountWrapper.js b/packages/enzyme-adapter-react-renderer/src/ReactMountWrapper.js index c0f4ea5d7..f5a6848ff 100644 --- a/packages/enzyme-adapter-react-renderer/src/ReactMountWrapper.js +++ b/packages/enzyme-adapter-react-renderer/src/ReactMountWrapper.js @@ -5,6 +5,8 @@ import ReactDOMServer from 'react-dom/server'; import ReactTestRendererAdapter from './ReactTestRendererAdapter'; import ReactTestInstance from './ReactTestInstance'; +import { reduceTreesBySelector } from './selectors'; + const noop = () => {}; const flatMap = (collection, fn) => @@ -70,14 +72,46 @@ class ReactMountWrapper { return _context; } + /** + * Finds every node in the render tree of the current wrapper that matches the provided selector. + * + * @param {String|Function} selector + * @returns {ReactWrapper} + */ find(selector) { return new ReactMountWrapper( - flatMap(this.instances, instance => instance.findAllByType(selector)), + reduceTreesBySelector(selector, this.instances), this.rootWrapper, this.rootNode, ); } + /** + * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate + * function. + * + * @param {Function} predicate + * @returns {ReactWrapper} + */ + findWhere(predicate) { + return new ReactMountWrapper( + flatMap(this.instances, instance => + instance.findAll(testInstance => + predicate(new ReactMountWrapper([testInstance], this.rootWrapper, this.rootNode)))), + this.rootWrapper, + this.rootNode, + ); + } + + /** + * Returns a wrapper around the first node of the current wrapper. + * + * @returns {ReactWrapper} + */ + first() { + return this.at(0); + } + /** * Returns the HTML of the node. * @@ -119,6 +153,15 @@ class ReactMountWrapper { return first && first.parent.instance !== this.rootWrapper; } + /** + * Returns a wrapper around the last node of the current wrapper. + * + * @returns {ReactWrapper} + */ + last() { + return this.at(this.length - 1); + } + /** * Returns the name of the root node of this wrapper. * @@ -133,6 +176,16 @@ class ReactMountWrapper { }); } + /** + * Returns the value of prop with the given name of the root node. + * + * @param {String} propName + * @returns {*} + */ + prop(propName) { + return this.props()[propName]; + } + /** * Returns the props hash for the root node of the wrapper. * diff --git a/packages/enzyme-adapter-react-renderer/src/ReactTestInstance.js b/packages/enzyme-adapter-react-renderer/src/ReactTestInstance.js index 959b45fa1..7e0782828 100644 --- a/packages/enzyme-adapter-react-renderer/src/ReactTestInstance.js +++ b/packages/enzyme-adapter-react-renderer/src/ReactTestInstance.js @@ -1,4 +1,7 @@ -import {findCurrentFiberUsingSlowPath} from 'react-reconciler/reflection'; +// COPIED FROM https://github.com/facebook/react/blob/master/packages/react-test-renderer/src/ReactTestRenderer.js +// Ideally ReactTestInstance would be exported from the react-test-renderer package + +import { findCurrentFiberUsingSlowPath } from 'react-reconciler/reflection'; import invariant from 'invariant'; export const IndeterminateComponent = 0; // Before we know whether it is functional or class @@ -17,12 +20,7 @@ export const ContextConsumer = 12; export const ContextProvider = 13; export const ForwardRef = 14; -const validWrapperTypes = new Set([ - FunctionalComponent, - ClassComponent, - HostComponent, - ForwardRef, -]); +const validWrapperTypes = new Set([FunctionalComponent, ClassComponent, HostComponent, ForwardRef]); function getPublicInstance(inst) { switch (inst.tag) { @@ -51,27 +49,18 @@ function wrapFiber(fiber) { return wrapper; } -function expectOne( - all, - message, -) { +function expectOne(all, message) { if (all.length === 1) { return all[0]; } const prefix = - all.length === 0 - ? 'No instances found ' - : `Expected 1 but found ${all.length} instances `; + all.length === 0 ? 'No instances found ' : `Expected 1 but found ${all.length} instances `; throw new Error(prefix + message); } -function findAll( - root, - predicate, - options, -) { +function findAll(root, predicate, options) { const deep = options ? options.deep : true; const results = []; @@ -126,9 +115,8 @@ class ReactTestInstance { get instance() { if (this._fiber.tag === HostComponent) { return getPublicInstance(this._fiber.stateNode); - } else { - return this._fiber.stateNode; } + return this._fiber.stateNode; } get type() { @@ -141,9 +129,7 @@ class ReactTestInstance { get parent() { const parent = this._fiber.return; - return parent === null || parent.tag === HostRoot - ? null - : wrapFiber(parent); + return parent === null || parent.tag === HostRoot ? null : wrapFiber(parent); } get children() { @@ -165,7 +151,7 @@ class ReactTestInstance { children.push(wrapFiber(node)); break; case HostText: - children.push('' + node.memoizedProps); + children.push(`${node.memoizedProps}`); break; case Fragment: case ContextProvider: @@ -176,8 +162,7 @@ class ReactTestInstance { default: invariant( false, - 'Unsupported component type %s in test renderer. ' + - 'This is probably a bug in React.', + 'Unsupported component type %s in test renderer. ' + 'This is probably a bug in React.', node.tag, ); } @@ -190,10 +175,10 @@ class ReactTestInstance { if (node.return === startingNode) { break outer; } - node = (node.return); + node = node.return; } - (node.sibling).return = node.return; - node = (node.sibling); + node.sibling.return = node.return; + node = node.sibling; } return children; } @@ -201,48 +186,35 @@ class ReactTestInstance { // Custom search functions find(predicate) { return expectOne( - this.findAll(predicate, {deep: false}), + this.findAll(predicate, { deep: false }), `matching custom predicate: ${predicate.toString()}`, ); } findByType(type) { return expectOne( - this.findAllByType(type, {deep: false}), + this.findAllByType(type, { deep: false }), `with node type: "${type.displayName || type.name}"`, ); } findByProps(props) { return expectOne( - this.findAllByProps(props, {deep: false}), + this.findAllByProps(props, { deep: false }), `with props: ${JSON.stringify(props)}`, ); } - findAll( - predicate, - options = null, - ) { + findAll(predicate, options = null) { return findAll(this, predicate, options); } - findAllByType( - type, - options = null, - ) { + findAllByType(type, options = null) { return findAll(this, node => node.type === type, options); } - findAllByProps( - props, - options = null, - ) { - return findAll( - this, - node => node.props && propsMatch(node.props, props), - options, - ); + findAllByProps(props, options = null) { + return findAll(this, node => node.props && propsMatch(node.props, props), options); } }