UNPKG

wix-style-react

Version:
323 lines (263 loc) • 10.1 kB
import React from 'react'; import PropTypes from 'prop-types'; import { mount } from 'enzyme'; import Button from '../../Button'; import { createDriverFactory } from 'wix-ui-test-utils/driver-factory'; import { withFocusable, focusableStates } from './FocusableHOC'; const focusableDriver = ({ element, eventTrigger }) => ({ focus: () => eventTrigger.focus(element), blur: () => eventTrigger.blur(element), hasFocusState: () => !!element.getAttribute('data-focus'), hasFocusVisibleState: () => !!element.getAttribute('data-focus-visible'), }); describe('FocusableHOC', () => { const render = Comp => mount(Comp, { attachTo: document.createElement('div') }); // Pure component without state class PureChildComponent extends React.PureComponent { constructor(props) { super(props); this.id = props.id; this.boundMethod = this.boundMethod.bind(this); } static propTypes = { id: PropTypes.string, }; static staticVariable = 'staticVariable'; static staticMethod() { return 'staticMethod'; } unboundMethod() { return 'unboundMethod'; } boundMethod() { return this.id; } render() { return ( <div onFocus={this.props.focusableOnFocus} // eslint-disable-line react/prop-types onBlur={this.props.focusableOnBlur} // eslint-disable-line react/prop-types {...focusableStates(this.props)} > Hello </div> ); } } const pureChildDriverFactory = ({ element, eventTrigger }) => { return { ...focusableDriver({ element, getFocusableElement: () => element, eventTrigger, }), }; }; const WithFocusableComp = withFocusable(PureChildComponent); describe('Pure component HOC', () => { it('should render the wrapped component', () => { const wrapper = render(<WithFocusableComp />); expect(wrapper.children().instance()).toBeInstanceOf(PureChildComponent); }); describe('hoisting', () => { it('should hoist static methods', () => { expect(WithFocusableComp.staticMethod()).toEqual('staticMethod'); }); it('should hoist static variables', () => { expect(WithFocusableComp.staticVariable).toEqual('staticVariable'); }); it('should hoist prototype methods from child to HOC and bind them', () => { const wrapper = render(<WithFocusableComp id="some_id" />); expect(wrapper.instance().unboundMethod()).toEqual('unboundMethod'); expect(wrapper.instance().boundMethod()).toEqual('some_id'); }); }); }); describe('Focusable', () => { const driverFactory = createDriverFactory(pureChildDriverFactory); const createDriver = Component => { const driver = driverFactory(Component); const fireMouseDown = () => window.dispatchEvent(new window.Event('mousedown')); const fireMouseUp = () => window.dispatchEvent(new window.Event('mouseup')); const fireKeyDown = () => window.dispatchEvent(new window.Event('keydown')); const fireKeyUp = () => window.dispatchEvent(new window.Event('keyup')); const tabOut = () => { fireKeyDown(); driver.blur(); fireKeyUp(); }; const tabIn = () => { fireKeyDown(); driver.focus(); fireKeyUp(); }; const click = () => { fireMouseDown(); driver.focus(); fireMouseUp(); }; return { ...driver, fireMouseDown, fireKeyDown, fireKeyUp, tabOut, tabIn, click, }; }; const expectKeyboardFocused = (driver, msg) => { const prefix = msg ? `${msg} - ` : ''; expect(driver.hasFocusState()).toBe(true, `${prefix}hasFocusState`); expect(driver.hasFocusVisibleState()).toBe( true, `${prefix}hasFocusVisibleState`, ); }; const expectNotFocused = (driver, msg) => { const prefix = msg ? `${msg} - ` : ''; expect(driver.hasFocusState()).toBe(false, `${prefix}hasFocusState`); expect(driver.hasFocusVisibleState()).toBe( false, `${prefix}hasFocusVisibleState`, ); }; const expectMouseFocused = (driver, msg) => { const prefix = msg ? `${msg} - ` : ''; expect(driver.hasFocusState()).toBe(true, `${prefix}hasFocusState`); expect(driver.hasFocusVisibleState()).toBe( false, `${prefix}hasFocusVisibleState`, ); }; let WithFocusableComp2; let focusableModule; beforeEach(() => { // Reseting modules, in order to reset the FocusableHOC.InputMethod.method state. jest.resetModules(); focusableModule = require('./FocusableHOC'); WithFocusableComp2 = focusableModule.withFocusable(PureChildComponent); // TODO: find a way to reset the eventHandlers which are added to the window. }); it('should not have focus nor focus-visible [given] initial render', () => { const driver = createDriver(<WithFocusableComp2 />); expectNotFocused(driver); }); it('should have focus and focus-visible [when] focused programatically', () => { const driver = createDriver(<WithFocusableComp2 />); driver.focus(); // Default input is keyboard expectKeyboardFocused(driver, 'after focus'); }); it('should have focus and focus-visible [when] tabbed in', () => { const driver = createDriver(<WithFocusableComp2 />); driver.tabIn(); expectKeyboardFocused(driver, 'after focus'); }); it('should have focus and focus-visible [when] tabbed in withot keyDown', () => { // This test case checks a scenario when the focus is on the browser's // url input, and we press tab. The keyDown is not fired. const driver = createDriver(<WithFocusableComp2 />); driver.focus(); driver.fireKeyUp(); expectKeyboardFocused(driver, 'after focus'); }); it('should not have focus nor focus-visible [when] blured programatically [given] keyboard focused', () => { const driver = createDriver(<WithFocusableComp2 />); driver.tabIn(); expectKeyboardFocused(driver, 'after focus'); driver.blur(); expectNotFocused(driver, 'after blur'); }); it('should have focus but not focus-visible [when] clicked', () => { const driver = createDriver(<WithFocusableComp2 />); driver.click(); expectMouseFocused(driver, 'after click'); }); it('should have focus but not focus-visible [when] focused programatically [given] current input method is mouse', () => { // This test must be here , after a test which finishes with the input method = mouse. // this test is only to test that we are reseting the FocusableHOC global state proparely, // usin the jest.resetModules() call. const driver = createDriver(<WithFocusableComp2 />); driver.focus(); expectKeyboardFocused(driver, 'after click'); }); /** * This test checks that the InpurMethod.method state is updated to `keyboard` after * is was set to `mouse`. */ it('should have focus and focus-visible [when] focused [given] mouseDown and blur', () => { const driver = createDriver(<WithFocusableComp2 />); driver.click(); expectMouseFocused(driver, 'after click'); driver.blur(); expectNotFocused(driver, 'after blur'); driver.tabIn(); expectKeyboardFocused(driver, 'after focus'); }); it('should not be focused [when] tabbed out [given] focused by mouse', () => { const driver = createDriver(<WithFocusableComp />); driver.click(); expectMouseFocused(driver, 'after click'); driver.tabOut(); expectNotFocused(driver, 'after tab'); }); it('should have focus and focus-visible, when: any keyboard key pressed [given] focused by mouse', () => { const driver = createDriver(<WithFocusableComp />); driver.click(); expectMouseFocused(driver, 'after click'); driver.fireKeyDown(); expectKeyboardFocused(driver, 'after pressing space'); }); }); describe('regressions', () => { class ButtonWithDisabledState extends React.Component { state = { disabled: false }; handleButtonClick = () => { this.setState({ disabled: true }); }; render() { return ( <div> <Button dataHook="disabled-button" disabled={this.state.disabled} onClick={this.handleButtonClick} > click me </Button> <input placeholder="click the button and type here" onChange={() => this.setState({ disabled: false })} /> </div> ); } } it('ISSUE-1721: Fix focusable button in disabled state', () => { const component = mount(<ButtonWithDisabledState />); const button = component.find('button'); const input = component.find('input'); /* by default should not have focus and should not be disabled */ expect(button.getDOMNode().disabled).toBeFalsy(); expect(button.getDOMNode().attributes['data-focus']).toBeFalsy(); /* become focused */ button.simulate('focus'); expect(button.getDOMNode().attributes['data-focus']).toBeTruthy(); /* click on button after that, button should become disabled */ button.simulate('click'); expect(button.getDOMNode().disabled).toBeTruthy(); /* bug was here, after button become disabled, focus should disappear */ expect(button.getDOMNode().attributes['data-focus']).toBeFalsy(); /* input change, after that should be disabled === false */ input.simulate('change', { target: { value: '123' } }); expect(button.getDOMNode().disabled).toBeFalsy(); /* bug was here, after input change, button should become unfocused */ expect(button.getDOMNode().attributes['data-focus']).toBeFalsy(); }); }); });