How to set the width of a React component during test?

前端 未结 3 2028
隐瞒了意图╮
隐瞒了意图╮ 2021-02-19 05:23

I\'m trying to test a slider component. \"\"

This slider compone

相关标签:
3条回答
  • 2021-02-19 05:32

    I've been fighting the same problem myself today - I'm building a component that will scale its text size based on the size of the element. Because renderIntoDocument places your component inside a detached DOM node, it isn't possible to calculate offsetWidth, clientWidth, etc.

    Are you testing in a browser or node.js? (EDIT: I see you tagged the question PhantomJS so I'm guessing browser!) If you're in a browser you may be able to render the component into the DOM for real:

    React.render(<Slider />, document.body);
    

    If you're worried about test isolation, you can create an IFrame to render the component into, and clean that up afterwards:

    beforeEach(function() {
        this.iframe = document.createElement('iframe');
        document.body.appendChild(this.iframe);
    });
    
    React.render(<Slider />, this.iframe.contentDocument.body);
    
    afterEach(function() {
        document.body.removeChild(this.iframe);
    });
    

    Then call this.iframe.contentDocument.body.querySelectorAll('.track') to get the HTML Element and run your assertions against it (This is a plain HTML element, not a React component, so use the standard APIs to query it).

    0 讨论(0)
  • 2021-02-19 05:44

    Here is an example. React 0.14 warns about rendering document into body. Like what Matt said, we will need to append 'div' in the iframe to prevent such errors.

    describe('html tooltip utility class', function() {
    
    let iframe;
    let div;
    
    beforeEach(() => {
        iframe = document.createElement('iframe');
        document.body.appendChild(iframe);
        div = document.createElement('div');
    });
    
    
    it('returns true if text overflows', () => {
        // jshint ignore:start
        let style = {
            width: 5
        };
        let data = 'hello this is a long text.';
        iframe.contentDocument.body.appendChild(div);
        ReactDOM.render(<div style={style}>{data}</div>, div);
    
        // jshint ignore:end
        let textNode = div.querySelectorAll('div')[0];
    
        expect(HTMLTooltip.showTooltip(textNode)).to.be.true;
    });
    
    afterEach(() => {
        document.body.removeChild(iframe);
    });
    });
    
    0 讨论(0)
  • 2021-02-19 05:56

    Have you tried to set the dimension for the actual dom node first before testing it? I use Enzyme and what I normally do is create a dummy element node, attached it to the body, then mount the Component to that element. If I need to setup width and height of the element inside the component, i will just update its real DOM node width and height through vanilla javascript. I'm posting my code example below, hope it will help.

    Component code that needs to be tested

    getMaskComponentContent() {
        const { clientWidth, clientHeight } = this.button;
        const size = clientWidth + clientHeight;
        const lineGap = 15;
        let lines = [];
    
        for (let i = lineGap; i < size; i += lineGap) {
            lines.push(<line key={i} className='lrn-line1' x1='0' y1={i} x2={i} y2='0'/>);
        }
    
        return (
            <svg className='lrn-mask' xmlns='http://www.w3.org/2000/svg'>
                <rect x='0' y='0' width='100%' height='100%' fill='transparent'/>
                {lines}
            </svg>
        );
    }
    

    Unit-test with enzyme

    let wrapper, mountElement;
    
    function setup(props = {}, mountOptions) {
        const providerWrapper = enzyme.mount(<MaskableElement {...props}/>, mountOptions);
    
        wrapper = providerWrapper.find('MaskableElement');
    }
    
    beforeEach(function () {
        // Create dummy element
        mountElement = document.createElement('DIV');
        document.body.appendChild(mountElement);
    });
    
    afterEach(function () {
        mountElement.remove();
    });
    
    it('the masking svg should contain multiple line elements based on the width and height of the main button', function () {
        // First we setup the component without maskId
        setup({
            maskIds: []
        }, {
            attachTo: mountElement
        });
    
        const button = wrapper.find('button');
        const node = button.node;
    
        // then we set size to the component
        node.style.width = '300px';
        node.style.height = '30px';
    
        // stimulate click event to apply the mask
        button.simulate('click');
    
        const svg = button.find('svg');
    
        // 330 is the total clientWidth + clientHeight, 15 is the gap b/w lines
        const expectedNumberOfLines = (330 / 15) - 1; 
    
        expect(svg.find('line').length).toEqual(expectedNumberOfLines);
    });
    
    0 讨论(0)
提交回复
热议问题