/**
* Copyright (c) Paymium.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root of this projects source tree.
*/
import { render } from '@crossed/test';
import { DropDownMenu } from '../index';
import { Popover, useFloatingContext } from '../../overlay';
import { MenuList } from '../MenuList';
import { Divider } from '../../layout/Divider';
import { useMedia } from '../../useMedia';
import { Text } from '../../typography';
jest.mock('../../overlay', () => ({
Popover: Object.assign(
jest.fn(({ children }) => children),
{
Trigger: jest.fn(({ children }) => children),
Content: jest.fn(({ children }) => children),
}
),
useFloatingContext: jest.fn(),
}));
jest.mock('../MenuList', () => ({
MenuList: Object.assign(
jest.fn(({ children }) => children),
{
Item: jest.fn(({ children }) => children),
Label: jest.fn(({ children }) => children),
Title: jest.fn(({ children }) => children),
}
),
}));
jest.mock('../../layout/Divider', () => ({
Divider: jest.fn(() => null),
}));
jest.mock('../../useMedia', () => ({
useMedia: jest.fn(),
}));
const PopoverMocked = jest.mocked(Popover);
const MenuListMocked = jest.mocked(MenuList);
const useFloatingContextMocked = jest.mocked(useFloatingContext);
const useMediaMocked = jest.mocked(useMedia);
const DividerMocked = jest.mocked(Divider);
const mockUseMedia = (md: boolean) => {
useMediaMocked.mockReturnValue({
md,
sm: false,
lg: false,
xl: false,
} as any);
};
const mockFloatingContext = (onClose = jest.fn()) => {
useFloatingContextMocked.mockReturnValue({
onClose,
open: true,
onOpen: jest.fn(),
} as any);
};
describe('DropDownMenu', () => {
beforeEach(() => {
mockUseMedia(true);
mockFloatingContext();
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders with default props', () => {
render(
Open Menu
Item 1
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty('placement', 'bottom-end');
expect(call).toHaveProperty('triggerStrategy', 'onPress');
expect(call).toHaveProperty('children');
});
test('accepts custom placement', () => {
render(
Open Menu
Item 1
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty('placement', 'top-start');
});
test('accepts custom triggerStrategy', () => {
render(
Open Menu
Item 1
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty('triggerStrategy', 'onPointerEnter');
});
test('forwards additional props to Popover', () => {
render(
Open Menu
Item 1
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty('offsetValue', 15);
});
test('renders all static components', () => {
expect(DropDownMenu.Trigger).toBeDefined();
expect(DropDownMenu.Content).toBeDefined();
expect(DropDownMenu.Item).toBeDefined();
expect(DropDownMenu.Label).toBeDefined();
expect(DropDownMenu.Title).toBeDefined();
expect(DropDownMenu.Divider).toBeDefined();
});
test('Content renders MenuList with bordered=true on desktop', () => {
mockUseMedia(true);
MenuListMocked.mockClear();
render(
Open Menu
Item 1
);
const menuListCall = MenuListMocked.mock.calls[0][0];
expect(menuListCall).toHaveProperty('bordered', true);
});
test('Content renders MenuList with bordered=false on mobile', () => {
mockUseMedia(false);
MenuListMocked.mockClear();
render(
Open Menu
Item 1
);
const menuListCall = MenuListMocked.mock.calls[0][0];
expect(menuListCall).toHaveProperty('bordered', false);
});
test('Item closes popover on press', () => {
const onClose = jest.fn();
mockFloatingContext(onClose);
const MenuListItemMocked = jest.mocked(MenuList.Item);
render(
Open Menu
{}}>
Item 1
);
const itemCall = MenuListItemMocked.mock.calls[0][0];
expect(itemCall).toHaveProperty('onPress');
if ('onPress' in itemCall && typeof itemCall.onPress === 'function') {
itemCall.onPress({} as any);
}
expect(onClose).toHaveBeenCalledTimes(1);
});
test('Item composes custom onPress with onClose', () => {
const onClose = jest.fn();
const customOnPress = jest.fn();
mockFloatingContext(onClose);
const MenuListItemMocked = jest.mocked(MenuList.Item);
render(
Open Menu
Item 1
);
const itemCall = MenuListItemMocked.mock.calls[0][0];
if ('onPress' in itemCall && typeof itemCall.onPress === 'function') {
itemCall.onPress({} as any);
}
expect(customOnPress).toHaveBeenCalledTimes(1);
expect(onClose).toHaveBeenCalledTimes(1);
});
test('Label renders MenuList.Label', () => {
const MenuListLabelMocked = jest.mocked(MenuList.Label);
render(
Open Menu
Item 1
);
expect(MenuListLabelMocked).toHaveBeenCalled();
});
test('Title renders MenuList.Title', () => {
const MenuListTitleMocked = jest.mocked(MenuList.Title);
render(
Open Menu
Menu Title
);
expect(MenuListTitleMocked).toHaveBeenCalled();
});
test('Divider renders Divider component', () => {
render(
Open Menu
Item 1
Item 2
);
expect(DividerMocked).toHaveBeenCalled();
});
test('Divider forwards props', () => {
DividerMocked.mockClear();
render(
Open Menu
);
const dividerCall = DividerMocked.mock.calls[0][0];
expect(dividerCall).toHaveProperty('direction', 'vertical');
});
});