All files / boundless/packages/boundless-utils-test-helpers index.js

96.3% Statements 26/27
75% Branches 9/12
100% Functions 5/5
96% Lines 24/25
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95                                                      19x 95x           95x 10x     85x         19x 19x   19x 185x 19x 166x       166x       19x   19x         19x   19x         19x   19x         19x   19x         19x   19x         358x 19x  
import React from 'react';
import {findDOMNode} from 'react-dom';
import get from 'lodash.get';
 
/**
 * A testing module to verify that arbitrary React-supported attributes are passed
 * through the destination element node. The conformance checker uses the following
 * valid JSX attributes as examples:
 *
 * - className
 * - id
 * - style
 * - data-foo
 * - aria-label
 *
 * Each must be able to be mixed and matched without overwriting each other,
 * with the exception of `id`, where `props.id`
 *
 * @param {function}  render        a pre-build render function to take in vdom and render to a designated place
 * @param {function}  Constructor   a valid ReactClass
 * @param {object}    baseProps     any fundamental props that are needed for the component to be rendered successfully
 * @param {string}   [key] an instance key to check for compliance instead of the base element; this is
 *                                  used for React components that render to <body> or a node other than its logical parent
 */
export function conformanceChecker(render, Constructor, baseProps, key) {
    let node;
 
    const renderWithPropsAndGetNode = (props) => {
        const element = render(
            <Constructor
                {...baseProps}
                {...props} />
        );
 
        if (key) {
            return findDOMNode(get(element, key));
        }
 
        return findDOMNode(element);
    };
 
    /* verify defaultProps are set for all propTypes; if we can be assured they're equivalent,
       we can generate "internal keys" off defaultProps instead and entirely drop propTypes in production */
    const ownProps = Object.keys(Constructor.propTypes || {});
    const defaults = Constructor.defaultProps || {};
 
    ownProps.forEach((propName) => {
        if (propName === '*') {
            return;
        } else Iif (!(propName in defaults)) {
            console.error(`${propName} is missing in ${Constructor.name}.defaultProps.`);
        }
 
        expect(propName in defaults).toBe(true);
    });
 
    /* verify props.className */
    node = renderWithPropsAndGetNode({className: 'foo'});
 
    expect(node.classList.contains('foo')).toBe(true,
        `${Constructor.name} does not support adding of classes via props.className`
    );
 
    /* verify props.id */
    node = renderWithPropsAndGetNode({id: 'foo'});
 
    expect(node.id === 'foo').toBe(true,
        `${Constructor.name} does not support adding of an HTML id via props.id`
    );
 
    /* verify props.style */
    node = renderWithPropsAndGetNode({style: {color: 'red'}});
 
    expect(node.style.color === 'red').toBe(true,
        `${Constructor.name} does not support adding inline styles via props.style`
    );
 
    /* verify props['data-foo'] */
    node = renderWithPropsAndGetNode({'data-foo': 'bar'});
 
    expect(node.getAttribute('data-foo') === 'bar').toBe(true,
        `${Constructor.name} does not support adding data attributes via props`
    );
 
    /* verify props['aria-label'] */
    node = renderWithPropsAndGetNode({'aria-label': 'foo'});
 
    expect(node.getAttribute('aria-label') === 'foo').toBe(true,
        `${Constructor.name} does not support adding aria attributes via props`
    );
}
 
export const $ = (selector, context = document) => context.querySelector(selector);
export const $$ = (selector, context = document) => context.querySelectorAll(selector);