wix-style-react
Version:
wix-style-react
388 lines (302 loc) • 11.8 kB
JavaScript
import React from 'react';
import { mount } from 'enzyme';
import { createUniDriverFactory } from 'wix-ui-test-utils/uni-driver-factory';
import { enzymeUniTestkitFactoryCreator } from 'wix-ui-test-utils/enzyme';
import DropdownBase from './DropdownBase';
import { dropdownBasePrivateDriverFactory } from './DropdownBase.driver.private';
describe('DropdownBase', () => {
const createDriver = createUniDriverFactory(dropdownBasePrivateDriverFactory);
const dropdownBaseEnzymeDriver = enzymeUniTestkitFactoryCreator(
dropdownBasePrivateDriverFactory,
);
const defaultProps = {
options: [
{ id: 0, value: 'First option' },
{ id: 1, value: 'Second option' },
{ id: 2, value: 'Third option' },
{ id: 3, value: 'Fourth option' },
],
};
const createUncontrolledDriver = (renderProp, initialProps) => {
let args;
const driver = createDriver(
<DropdownBase {...defaultProps} {...initialProps}>
{_args => {
args = _args;
return renderProp ? renderProp(_args) : <div>Hello again</div>;
}}
</DropdownBase>,
);
return {
args,
driver,
};
};
const createControlledDriver = (renderProp, initialProps) => {
let args;
const dataHook = 'dropdown-base-0';
const wrapper = mount(
<DropdownBase
{...defaultProps}
dataHook={dataHook}
open={false}
{...initialProps}
>
{_args => {
args = _args;
return renderProp ? renderProp(_args) : <div>Hello again</div>;
}}
</DropdownBase>,
);
const driver = dropdownBaseEnzymeDriver({
wrapper,
dataHook,
});
return {
args,
driver,
wrapper,
};
};
it('should render', async () => {
const driver = createDriver(<DropdownBase {...defaultProps} />);
expect(await driver.exists()).toBeTruthy();
});
it('should accept a node as a children', async () => {
const driver = createDriver(
<DropdownBase {...defaultProps}>
<div>Hello</div>
</DropdownBase>,
);
const targetElement = await driver.getTargetElement();
expect(targetElement.innerHTML).toContain('Hello');
});
it('should accept a function as a children and pass it the required arguments', async () => {
const driver = createDriver(
<DropdownBase {...defaultProps}>
{({ open, close, toggle, delegateKeyDown, selectedOption }) => {
expect(typeof open).toBe('function');
expect(typeof close).toBe('function');
expect(typeof toggle).toBe('function');
expect(typeof delegateKeyDown).toBe('function');
expect(selectedOption).toEqual(undefined);
return <div>Hello again</div>;
}}
</DropdownBase>,
);
const targetElement = await driver.getTargetElement();
expect(targetElement.innerHTML).toContain('Hello again');
});
it('should call onSelect when an option was selected', async () => {
const onSelectFn = jest.fn();
const driver = createDriver(
<DropdownBase {...defaultProps} open onSelect={onSelectFn}>
<div>Hello</div>
</DropdownBase>,
);
await driver.selectOption(0);
expect(onSelectFn).toHaveBeenCalledWith({ id: 0, value: 'First option' });
});
it('should call onClickOutside', async () => {
const onClickOutsideFn = jest.fn();
const driver = createDriver(
<DropdownBase {...defaultProps} onClickOutside={onClickOutsideFn}>
<div>Hello</div>
</DropdownBase>,
);
await driver.clickOutside();
expect(onClickOutsideFn).toHaveBeenCalledTimes(1);
});
it('should call onMouseEnter', async () => {
const onMouseEnterFn = jest.fn();
const driver = createDriver(
<DropdownBase {...defaultProps} onMouseEnter={onMouseEnterFn}>
<div>Hello</div>
</DropdownBase>,
);
await driver.mouseEnter();
expect(onMouseEnterFn).toHaveBeenCalledTimes(1);
});
it('should call onMouseLeave', async () => {
const onMouseLeaveFn = jest.fn();
const driver = createDriver(
<DropdownBase {...defaultProps} onMouseLeave={onMouseLeaveFn}>
<div>Hello</div>
</DropdownBase>,
);
await driver.mouseLeave();
expect(onMouseLeaveFn).toHaveBeenCalledTimes(1);
});
describe('uncontrolled open behaviour', () => {
it('should allow controlling the behaviour using a render prop', async () => {
const { args, driver } = createUncontrolledDriver();
args.open();
expect(await driver.isDropdownShown()).toBeTruthy();
args.close();
expect(await driver.isDropdownShown()).toBeFalsy();
args.toggle();
expect(await driver.isDropdownShown()).toBeTruthy();
args.toggle();
expect(await driver.isDropdownShown()).toBeFalsy();
});
it('should close on click outside', async () => {
const { args, driver } = createUncontrolledDriver();
args.open();
expect(await driver.isDropdownShown()).toBeTruthy();
await driver.clickOutside();
expect(await driver.isDropdownShown()).toBeFalsy();
});
it('should close when selecting an option', async () => {
const { args, driver } = createUncontrolledDriver();
args.open();
expect(await driver.isDropdownShown()).toBeTruthy();
await driver.selectOption(0);
expect(await driver.isDropdownShown()).toBeFalsy();
});
describe('keyDown handling', () => {
it('should delegate the event to the DropdownLayout', async () => {
const { args, driver } = createUncontrolledDriver();
// We'll press the ArrowDown key to highlight the next option, and then select it with the
// Enter key.
args.open();
await driver.keyDown('ArrowDown');
expect(await driver.isOptionHovered(0)).toBeTruthy();
await driver.keyDown('Enter');
args.open();
expect(await driver.isOptionSelected(0)).toBeTruthy();
});
it.each([['Enter', 'Spacebar', 'ArrowDown']])(
'should open the DropdownLayout when the %s key is pressed',
async expectedKey => {
const { driver } = createUncontrolledDriver();
expect(await driver.isDropdownShown()).toBeFalsy();
await driver.keyDown(expectedKey);
expect(await driver.isDropdownShown()).toBeTruthy();
},
);
});
describe('mouseLeave handling', () => {
it('should not close the popover when leaving the target element', async () => {
// This test handles a special case when the `close` function triggers directly on the
// `mouseleave` event of the target element. Normally, The `mouseleave` event will trigger
// when the user moves the cursor from the target element to the DropdownLayout, thus the
// DropdownLayout will be closed.
// This is not the desired behaviour. As a result, the DropdownBase handle this specific
// case.
// We'll use a custom render function
const { driver } = createUncontrolledDriver(({ open, close }) => {
return (
<div onMouseEnter={open} onMouseLeave={close}>
Hover me!
</div>
);
});
await driver.mouseEnterTarget();
expect(await driver.isDropdownShown()).toBeTruthy();
// Dropdown should still be shown when a mouseLeave happens on the target
await driver.mouseLeaveTarget();
expect(await driver.isDropdownShown()).toBeTruthy();
// Dropdown should be hidden when a mouseLeave happens on the DropdownLayout
await driver.mouseLeave();
expect(await driver.isDropdownShown()).toBeFalsy();
});
});
});
describe('controlled open behaviour', () => {
it('should allow controlling the behaviour using the `open` prop', async () => {
const { driver, wrapper } = createControlledDriver();
wrapper.setProps({ open: true });
expect(await driver.isDropdownShown()).toBeTruthy();
wrapper.setProps({ open: false });
expect(await driver.isDropdownShown()).toBeFalsy();
});
it('should not allow controlling the behaviour using a render prop', async () => {
const { args, driver } = createControlledDriver();
args.open();
expect(await driver.isDropdownShown()).toBeFalsy();
args.close();
expect(await driver.isDropdownShown()).toBeFalsy();
args.toggle();
expect(await driver.isDropdownShown()).toBeFalsy();
});
it('should not close on click outside', async () => {
const { driver, wrapper } = createControlledDriver();
wrapper.setProps({ open: true });
expect(await driver.isDropdownShown()).toBeTruthy();
await driver.clickOutside();
expect(await driver.isDropdownShown()).toBeTruthy();
});
it('should not close when selecting an option', async () => {
const { driver, wrapper } = createControlledDriver();
wrapper.setProps({ open: true });
expect(await driver.isDropdownShown()).toBeTruthy();
await driver.selectOption(0);
expect(await driver.isDropdownShown()).toBeTruthy();
});
describe('keyDown handling', () => {
it('should not delegate the event to the DropdownLayout by default', async () => {
const { driver, wrapper } = createControlledDriver();
wrapper.setProps({ open: true });
await driver.keyDown('ArrowDown');
expect(await driver.isOptionHovered(0)).toBeFalsy();
await driver.keyDown('Enter');
expect(await driver.isDropdownShown()).toBeTruthy();
});
});
});
describe('uncontrolled selection behaviour', () => {
it('should accept an initialSelectedId and use it', async () => {
const driver = createDriver(
<DropdownBase {...defaultProps} open initialSelectedId={2}>
<div>Hello</div>
</DropdownBase>,
);
expect(await driver.isOptionSelected(2)).toBeTruthy();
});
it('should store the selection after user interaction', async () => {
const driver = createDriver(
<DropdownBase {...defaultProps} open>
<div>Hello</div>
</DropdownBase>,
);
await driver.selectOption(0);
expect(await driver.isOptionSelected(0)).toBeTruthy();
await driver.selectOption(2);
expect(await driver.isOptionSelected(2)).toBeTruthy();
});
});
describe('controlled selection behaviour', () => {
it('should accept an initialSelectedId and use it', async () => {
const { driver } = createControlledDriver(null, {
open: true,
onSelect: jest.fn(),
selectedId: 0,
initialSelectedId: 2,
});
expect(await driver.isOptionSelected(2)).toBeTruthy();
});
it('should update according to the selectedId', async () => {
const { driver, wrapper } = createControlledDriver(null, {
open: true,
onSelect: jest.fn(),
selectedId: 1,
});
expect(await driver.isOptionSelected(1)).toBeTruthy();
wrapper.setProps({ selectedId: 2 });
expect(await driver.isOptionSelected(2)).toBeTruthy();
});
it('should not store the selection after user interaction', async () => {
const { driver } = createControlledDriver(null, {
open: true,
onSelect: jest.fn(),
selectedId: 1,
});
await driver.selectOption(0);
expect(await driver.isOptionSelected(0)).toBeFalsy();
expect(await driver.isOptionSelected(1)).toBeTruthy();
await driver.selectOption(2);
expect(await driver.isOptionSelected(2)).toBeFalsy();
expect(await driver.isOptionSelected(1)).toBeTruthy();
});
});
});