mirror of
https://github.com/status-im/react-native-popup-menu.git
synced 2026-08-31 03:51:09 +00:00
227 lines
6.2 KiB
JavaScript
227 lines
6.2 KiB
JavaScript
import React from 'react';
|
|
import { View, Text } from 'react-native';
|
|
import { render } from './helpers';
|
|
|
|
import { MenuTrigger, MenuOptions } from '../src/index';
|
|
|
|
jest.mock('../src/helpers', () => ({
|
|
makeName: () => 'generated-name',
|
|
deprecatedComponent: jest.fn(() => jest.fn()),
|
|
}));
|
|
|
|
jest.dontMock('../src/Menu');
|
|
const exported = require('../src/Menu');
|
|
const { Menu, default: ExportedMenu } = exported;
|
|
|
|
const { objectContaining, createSpy, any } = jasmine;
|
|
|
|
describe('Menu', () => {
|
|
|
|
function renderMenu(element) {
|
|
const ctx = createMockContext();
|
|
const result = render(element, ctx);
|
|
result.ctx = ctx;
|
|
return result;
|
|
}
|
|
|
|
function createMockContext() {
|
|
return {
|
|
menuRegistry : {
|
|
subscribe: createSpy(),
|
|
unsubscribe: createSpy(),
|
|
},
|
|
menuActions: {
|
|
_notify: createSpy(),
|
|
}
|
|
}
|
|
}
|
|
|
|
it('should export api', () => {
|
|
expect(typeof ExportedMenu.debug).toEqual('boolean');
|
|
expect(typeof ExportedMenu.setDefaultRenderer).toEqual('function');
|
|
});
|
|
|
|
it('should render component and preserve children order', () => {
|
|
const { output } = renderMenu(
|
|
<Menu>
|
|
<Text>Some text</Text>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
<Text>Some other text</Text>
|
|
</Menu>
|
|
);
|
|
expect(output.type).toEqual(View);
|
|
expect(output.props.children.length).toEqual(3);
|
|
// React.Children.toArray modifies components keys
|
|
// using the same function to create expected children
|
|
const expectedChildren = React.Children.toArray([
|
|
<Text>Some text</Text>,
|
|
<MenuTrigger />, // trigger will be modified
|
|
<MenuOptions />, // options will be removed
|
|
<Text>Some other text</Text>,
|
|
]);
|
|
expect(output.props.children[0]).toEqual(expectedChildren[0]);
|
|
expect(output.props.children[1]).toEqual(objectContaining({
|
|
type: MenuTrigger,
|
|
props: objectContaining({
|
|
onRef: any(Function)
|
|
})
|
|
}));
|
|
expect(output.props.children[2]).toEqual(expectedChildren[3]);
|
|
});
|
|
|
|
it('should subscribe menu and notify context', () => {
|
|
const { ctx, instance } = renderMenu(
|
|
<Menu>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
instance.componentDidMount();
|
|
expect(ctx.menuRegistry.subscribe).toHaveBeenCalledWith(instance);
|
|
expect(ctx.menuActions._notify).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not subscribe menu because of missing options', () => {
|
|
const { instance, renderer, ctx } = renderMenu(
|
|
<Menu>
|
|
<MenuTrigger />
|
|
<Text>Some text</Text>
|
|
</Menu>
|
|
);
|
|
instance.componentDidMount();
|
|
expect(ctx.menuRegistry.subscribe).not.toHaveBeenCalled();
|
|
const output = renderer.getRenderOutput();
|
|
expect(output.type).toEqual(View);
|
|
const expectedChildren = React.Children.toArray([
|
|
<MenuTrigger />,
|
|
<Text>Some text</Text>,
|
|
]);
|
|
expect(output.props.children[0]).toEqual(
|
|
objectContaining({
|
|
type: MenuTrigger
|
|
})
|
|
);
|
|
expect(output.props.children[1]).toEqual(expectedChildren[1]);
|
|
});
|
|
|
|
it('should not subscribe menu because of missing trigger', () => {
|
|
const { instance, renderer, ctx } = renderMenu(
|
|
<Menu>
|
|
<Text>Some text</Text>
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
instance.componentDidMount();
|
|
expect(ctx.menuRegistry.subscribe).not.toHaveBeenCalled();
|
|
const output = renderer.getRenderOutput();
|
|
expect(output.type).toEqual(View);
|
|
expect(output.props.children).toEqual(React.Children.toArray(
|
|
<Text>Some text</Text>
|
|
));
|
|
});
|
|
|
|
it('should not fail without any children', () => {
|
|
const { instance, renderer } = renderMenu(
|
|
<Menu/>
|
|
);
|
|
instance.componentDidMount();
|
|
const output = renderer.getRenderOutput();
|
|
expect(output.type).toEqual(View);
|
|
expect(output.props.children).toEqual([]);
|
|
instance.componentWillUnmount();
|
|
});
|
|
|
|
it('should autogenerate name if not provided', () => {
|
|
const { instance } = renderMenu(
|
|
<Menu/>
|
|
);
|
|
expect(instance.getName()).toEqual('generated-name');
|
|
});
|
|
|
|
it('should use name from props if provided', () => {
|
|
const { instance } = renderMenu(
|
|
<Menu name='prop-name'/>
|
|
);
|
|
expect(instance.getName()).toEqual('prop-name');
|
|
});
|
|
|
|
it('should unsubscribe menu', () => {
|
|
const { instance, ctx } = renderMenu(
|
|
<Menu>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
instance.componentWillUnmount();
|
|
expect(ctx.menuRegistry.unsubscribe).toHaveBeenCalledWith(instance);
|
|
});
|
|
|
|
it('should notify context if updated', () => {
|
|
const { instance, ctx } = renderMenu(
|
|
<Menu>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
instance.componentDidUpdate({});
|
|
expect(ctx.menuActions._notify).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should get menu options', () => {
|
|
const onSelect = () => 0;
|
|
const { instance } = renderMenu(
|
|
<Menu onSelect={ onSelect }>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
const options = instance._getOptions();
|
|
expect(options.type).toEqual(MenuOptions);
|
|
});
|
|
|
|
it('declarative opened takes precedence over imperative', () => {
|
|
const { instance } = renderMenu(
|
|
<Menu opened={false}/>
|
|
);
|
|
instance._setOpened(true);
|
|
expect(instance._isOpen()).toEqual(false);
|
|
expect(instance._getOpened()).toEqual(true);
|
|
});
|
|
|
|
it('imperative opened is used if no declarative', () => {
|
|
const { instance } = renderMenu(
|
|
<Menu/>
|
|
);
|
|
instance._setOpened(true);
|
|
expect(instance._isOpen()).toEqual(true);
|
|
});
|
|
|
|
it('should be considered closed after unmount', () => {
|
|
const { instance, ctx } = renderMenu(
|
|
<Menu opened={true}>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
expect(instance._isOpen()).toEqual(true);
|
|
instance.componentWillUnmount();
|
|
expect(instance._isOpen()).toEqual(false);
|
|
expect(ctx.menuActions._notify).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should know its trigger reference', () => {
|
|
const triggerRef = 9;
|
|
const { instance, output } = renderMenu(
|
|
<Menu>
|
|
<MenuTrigger />
|
|
<MenuOptions />
|
|
</Menu>
|
|
);
|
|
output.props.children[0].props.onRef(triggerRef);
|
|
expect(instance._getTrigger()).toEqual(triggerRef);
|
|
});
|
|
|
|
|
|
});
|