RubyLouvre/anu

View on GitHub
lib/ReactTestUtils.js

Summary

Maintainability
C
1 day
Test Coverage
(function umd(root, factory) {
    if (typeof exports === "object" && typeof module === "object") {
        module.exports = factory(require("react"));
    } else if (typeof define === "function" && define.amd) {
        define(["react"], factory);
    } else if (typeof exports === "object") {
        exports["ReactTestUtils"] = factory(require("react"));
    } else {
        root["ReactTestUtils"] = factory(root["React"]);
    }
})(this, function (React) {


    function getFiber(inst) {
        return inst._reactInternalFiber || inst.updater;
    }
    //收集符合条件的元素节点
    function findChildren(fiber, callback, ret) {

        for (var i in fiber.children) {
            var a = fiber.children[i];
            findAllInRenderedTreeImpl(a, callback, ret);
        }
    }
    function findAllInRenderedTreeImpl(target, callback, ret) {
        if (!target) {
            return;
        } else if (target.nodeType) {
            if (callback(target)) {
                ret.push(target);
            }
        } else if (target.render) {//实例
            var fiber = getFiber(target);
            findChildren(fiber, callback, ret);
        } else if (target.tag + 0 === target.tag) {
            var instance = target.stateNode;
            if (callback(instance)) {
                ret.push(instance);
            }
            if (instance.render) {//实例
                findChildren(getFiber(instance), callback, ret);
            } else if (target.tag == 5) {
                findChildren(target, callback, ret);
            }
        }
    }


    var ReactTestUtils = {
        renderIntoDocument: function (element) {
            var div = document.createElement("div");
            return ReactDOM.render(element, div);
        },

        isElement: function (element) {
            return React.isValidElement(element);
        },

        isElementOfType: function (inst, convenienceConstructor) {
            return React.isValidElement(inst) && inst.type === convenienceConstructor;
        },

        isDOMComponent: function (inst) {
            return !!(inst && inst.nodeType === 1 && inst.tagName);
        },

        isDOMComponentElement: function (inst) {
            //是否为元素节点
            return !!(inst && React.isValidElement(inst) && !!inst.tagName);
        },

        isCompositeComponent: function (inst) {
            //是否为组件实例
            if (ReactTestUtils.isDOMComponent(inst)) {
                return false;
            }
            return inst != null && typeof inst.render === "function" && typeof inst.setState === "function";
        },

        isCompositeComponentWithType: function (inst, type) {
            if (!ReactTestUtils.isCompositeComponent(inst)) {
                return false;
            }

            return inst.constructor === type;
        },

        isCompositeComponentElement: function (inst) {
            if (!React.isValidElement(inst)) {
                return false;
            }

            var prototype = inst.constructor.prototype;
            return typeof prototype.render === "function" && typeof prototype.setState === "function";
        },

        isCompositeComponentElementWithType: function (inst, type) {

            if (!ReactTestUtils.isCompositeComponent(inst)) {
                return false;
            }
            const fiber = inst._reactInternalFiber || {};
            return fiber.type = type;
        },

        findAllInRenderedTree: function (inst, fn) {
            var ret = [];
            if (!inst) {
                return ret;
            }
            findAllInRenderedTreeImpl(inst, fn, ret);
            return ret;
        },

        /**
         * 相当于getElementsByClassName
         */
        scryRenderedDOMComponentsWithClass: function (root, classNames) {

            return ReactTestUtils.findAllInRenderedTree(root, function (inst) {
                if (ReactTestUtils.isDOMComponent(inst)) {
                    var className = inst.className;
                    if (typeof className !== "string") {
                        // SVG, probably.
                        className = inst.getAttribute("class") || "";
                    }
                    var classList = className.split(/\s+/);
                    if (!Array.isArray(classNames)) {
                        classNames = classNames.split(/\s+/);
                    }
                    return classNames.every(function (name) {
                        return classList.indexOf(name) !== -1;
                    });
                }
                return false;
            });
        },

        /**
         *相当于getElementByClassName(注意最多返回一个),不等于1个就抛错
         */
        findRenderedDOMComponentWithClass: function (root, className) {
            var all = ReactTestUtils.scryRenderedDOMComponentsWithClass(root, className);
            if (all.length !== 1) {
                throw new Error("Did not find exactly one match (found: " + all.length + ") " + "for class:" + className);
            }
            return all[0];
        },

        /**
         * 相当于getElementsByTag
         */
        scryRenderedDOMComponentsWithTag: function (root, tagName) {
            return ReactTestUtils.findAllInRenderedTree(root, function (inst) {
                return ReactTestUtils.isDOMComponent(inst) && inst.tagName.toUpperCase() === tagName.toUpperCase();
            });
        },

        /**
         * 相当于getElementByTag(注意最多返回一个),不等于1个就抛错
         */
        findRenderedDOMComponentWithTag: function (root, tagName) {
            var all = ReactTestUtils.scryRenderedDOMComponentsWithTag(root, tagName);
            if (all.length !== 1) {
                throw new Error("Did not find exactly one match (found: " + all.length + ") " + "for tag:" + tagName);
            }
            return all[0];
        },

        /**
         * 找出所有符合指定子组件的实例
         */
        scryRenderedComponentsWithType: function (root, componentType) {
            return ReactTestUtils.findAllInRenderedTree(root, function (inst) {
                return ReactTestUtils.isCompositeComponentWithType(inst, componentType);
            });
        },

        /**
         * 与scryRenderedComponentsWithType用法相同,但只返回一个节点,如有零个或多个匹配的节点就报错
         */
        findRenderedComponentWithType: function (root, componentType) {
            var all = ReactTestUtils.scryRenderedComponentsWithType(root, componentType);
            if (all.length !== 1) {
                throw new Error("Did not find exactly one match (found: " + all.length + ") " + "for componentType:" + componentType);
            }
            return all[0];
        },

        mockComponent: function (module, mockTagName) {
            mockTagName = mockTagName || module.mockTagName || "div";

            module.prototype.render.mockImplementation(function () {
                return React.createElement(mockTagName, null, this.props.children);
            });

            return this;
        },

        simulateNativeEventOnNode: function (topLevelType, node, fakeNativeEvent) {
            fakeNativeEvent.target = node;
            fakeNativeEvent.simulated = true;
            if(topLevelType.indexOf("top") === 0){
                topLevelType = topLevelType.slice(3).toLowerCase()
            }

            React.eventSystem.dispatchEvent(fakeNativeEvent, topLevelType);
        },

        simulateNativeEventOnDOMComponent: function (topLevelType, comp, fakeNativeEvent) {
            ReactTestUtils.simulateNativeEventOnNode(topLevelType, React.findDOMNode(comp), fakeNativeEvent);
        },

        nativeTouchData: function (x, y) {
            return {
                touches: [{ pageX: x, pageY: y }]
            };
        },

        Simulate: {},
        SimulateNative: {}
    };
    // ReactTestUtils.Simulate.click(element, options)
    "click,change,keyDown,keyUp,KeyPress,mouseDown,mouseUp,mouseMove,input,focus,blur".replace(/\w+/g, function (name) {
        ReactTestUtils.Simulate[name] = function (node, opts) {
            if (!node || node.nodeType !== 1) {
                throw "第一个参数必须为元素节点";
            }
            var fakeNativeEvent = opts || {};
           
            var fakeTarget = fakeNativeEvent.target;
            if(fakeTarget && !fakeTarget.appendChild){
                for(var i in fakeTarget){
                    node[i] = fakeTarget[i];
                }
            }
            
            fakeNativeEvent.target = node;
           

            fakeNativeEvent.simulated = true;
            var eventName = name.toLowerCase();
            fakeNativeEvent.type = eventName;
            var fn = node["on" + eventName];

            React.eventSystem.dispatchEvent(fakeNativeEvent, eventName);
            if (fn) {
                try {
                    fn.call(node, fakeNativeEvent);
                } catch (e) { }
            }

        };
    });
    ReactTestUtils.SimulateNative = ReactTestUtils.Simulate;
    return ReactTestUtils;
});