Skip to content

Commit

Permalink
feat(selection-group): add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ndelmar authored and shnaaz committed Sep 17, 2024
1 parent c2b119a commit 05cc446
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 46 deletions.
12 changes: 6 additions & 6 deletions src/components/Menu/Menu.stories.args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default {
table: {
category: 'React Aria - Menu',
type: {
summary: '(key: Key) => void',
summary: "(keys: 'all' | Set<Key>) => void",
},
defaultValue: {
summary: 'undefined',
Expand Down Expand Up @@ -127,9 +127,8 @@ export default {
},
},
},
'ariaLabelledby': {
description:
'The aria-labelledby for the menu wrapper',
ariaLabelledby: {
description: 'The aria-labelledby for the menu wrapper',
control: { type: 'text' },
table: {
type: {
Expand All @@ -139,14 +138,15 @@ export default {
},
},
selectionMode: {
description: 'Selection mode single, multiple or none',
description: 'Default selection mode for the whole menu',
default: undefined,
control: { type: 'select' },
options: ['single', 'multiple', 'none'],
table: {
type: {
summary: "'single' | 'multiple' | 'none'",
},
defaultValue: 'multiple',
},
},
};

106 changes: 70 additions & 36 deletions src/components/Menu/Menu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import { DocumentationPage } from '../../storybook/helper.stories.docs';
import StyleDocs from '../../storybook/docs.stories.style.mdx';
import { Item, Section } from '@react-stately/collections';

import Menu, { MenuProps } from './';
import Menu, { MenuProps, SelectionGroup } from './';
import argTypes from './Menu.stories.args';
import Documentation from './Menu.stories.docs.mdx';
import { action } from '@storybook/addon-actions';
import Flex from '../Flex';
import Avatar from '../Avatar';
import { PresenceType } from '../Avatar/Avatar.types';
import { ListHeader, ListItemBaseSection, Icon } from '..';
import { SelectionGroup } from './Menu.utils';

export default {
title: 'Momentum UI/Menu',
Expand All @@ -26,6 +25,14 @@ export default {
},
};

const menuOnSelectionChange = (...rest) => {
console.log('menuOnSelectionChange', rest);
};

const menuOnAction = (...rest) => {
console.log('menuOnAction', rest);
};

const Example = Template<MenuProps<unknown>>(Menu).bind({});

Example.argTypes = { ...argTypes };
Expand Down Expand Up @@ -73,8 +80,8 @@ Sections.parameters = {
{
itemSize: 32,
isTickOnLeftSide: true,
label: 'Where would you like to live?',
onSelectionChange: action('onSelectionChange'),
onSelectionChange: menuOnSelectionChange,
onAction: menuOnAction,
children: [
<Section
key="0"
Expand All @@ -101,97 +108,123 @@ Sections.parameters = {
<Item key="12">Japan</Item>
</Section>,
<Section
key="2"
title={
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="fill">America</ListItemBaseSection>
</ListHeader>
}
>
<Item key="13">USA</Item>
<Item key="14">Mexico</Item>
<Item key="15">Canada</Item>
</Section>,
key="2"
title={
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="fill">America</ListItemBaseSection>
</ListHeader>
}
>
<Item key="13">USA</Item>
<Item key="14">Mexico</Item>
<Item key="15">Canada</Item>
</Section>,
],
},
],
};

const SelectionGroupExample = MultiTemplate<MenuProps<unknown>>(Menu).bind({});
const SelectionGroups = MultiTemplate<MenuProps<unknown>>(Menu).bind({});

SelectionGroupExample.argTypes = { ...argTypes };
SelectionGroups.argTypes = { ...argTypes };
delete Sections.argTypes.children;
delete Sections.argTypes.isTickOnLeftSide;
delete Sections.argTypes.itemSize;

SelectionGroupExample.args = {
SelectionGroups.args = {
'aria-label': 'Menu with multiple selection modes component',
onSelectionChange: action('onSelectionChange'),
};

SelectionGroupExample.parameters = {
SelectionGroups.parameters = {
variants: [
{
selectionMode: 'none',
selectionMode: 'multiple', // this is the default for all the group
itemSize: 32,
isTickOnLeftSide: true,
onSelectionChange: menuOnSelectionChange,
onAction: menuOnAction,
children: [
<SelectionGroup
key="0"
selectionMode="multiple"
aria-label="First group"
onSelectionChange={(...rest) => {
console.log('multipleselection', rest);
console.log('singleselection1', rest);
}}
onAction={(...rest) => {
console.log('selectionOnAction1', rest);
}}
title={
<ListHeader outline={false}>
<ListItemBaseSection position="start">
<Icon scale={16} name="speaker" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">Speaker</ListItemBaseSection>
<ListItemBaseSection position="fill">
Speaker (you can choose many)
</ListItemBaseSection>
</ListHeader>
}
>
<Item key="00">Use system setting (internal speakers)</Item>
<Item key="01">Internal speaker</Item>
<Item key="02">Bose Headset 100</Item>
<Item key="00">System default speaker</Item>
<Item key="01">Default - External Headphones (Built-in)</Item>
<Item key="02">Desk Pro Web Camera</Item>
<Item key="03">MacBook Pro Speakers</Item>
<Item key="04">Webex Media Audio Device</Item>
</SelectionGroup>,
<SelectionGroup
key="1"
selectionMode="single"
aria-label="Second group"
onSelectionChange={(...rest) => {
console.log('singleselection', rest);
console.log('singleselection2', rest);
}}
onAction={(...rest) => {
console.log('selectionOnAction2', rest);
}}
title={
<>
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="start">
<Icon scale={16} name="microphone" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">Microphone</ListItemBaseSection>
<ListItemBaseSection position="fill">
Microphone (you can choose one)
</ListItemBaseSection>
</ListHeader>
</>
}
>
<Item key="10">Use system setting (internal microphone)</Item>
<Item key="11">Bose Headset 100</Item>
<Item key="10">No Microphone</Item>
<Item key="11">Default - External Microhpone (Built-in)</Item>
<Item key="12">Desk Pro Web Microphone</Item>
<Item key="13">MacBook Pro Microphone</Item>
<Item key="14">Webex Media Audio Device</Item>
</SelectionGroup>,
<SelectionGroup
key="3"
items={[{ key: '20', value: 'Keyboard' }, { key: '21', value: 'Mouse' }]}
key="2"
items={[
{ key: '20', value: 'No optimization' },
{ key: '21', value: 'Noise removal' },
{ key: '22', value: 'Music mode' },
]}
selectionMode="single"
aria-label="Second group"
onSelectionChange={(...rest) => {
console.log('singleselection', rest);
console.log('singleselection3', rest);
}}
onAction={(...rest) => {
console.log('selectionOnAction3', rest);
}}
title={
<>
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="start">
<Icon scale={16} name="accessibility" strokeColor="none" />
<Icon scale={16} name="adjust-microphone" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">
Webex smart audio (You can choose one)
</ListItemBaseSection>
<ListItemBaseSection position="fill">Devices</ListItemBaseSection>
</ListHeader>
</>
}
Expand All @@ -211,6 +244,8 @@ const Common = MultiTemplate<MenuProps<unknown>>(Menu).bind({});

Common.argTypes = { ...argTypes };
delete Common.argTypes.children;
delete Common.argTypes.selectionMode;
delete Common.argTypes.itemShape;

Common.args = {
'aria-label': 'Menu component',
Expand Down Expand Up @@ -250,7 +285,6 @@ Common.parameters = {
</Section>,
],
},

{
selectionMode: 'single',
itemShape: 'isPilled',
Expand Down Expand Up @@ -280,4 +314,4 @@ Common.parameters = {
delete Common.argTypes.onAction;
delete Common.argTypes.disabledKeys;

export { Example, ActionMenu, Sections, SelectionGroupExample, Common };
export { Example, ActionMenu, Sections, SelectionGroups, Common };
4 changes: 2 additions & 2 deletions src/components/Menu/Menu.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CSSProperties, HTMLAttributes, MutableRefObject } from 'react';
import { CSSProperties, HTMLAttributes, Key, MutableRefObject } from 'react';
import { AriaMenuProps } from '@react-types/menu';
import {
CollectionBase,
Expand Down Expand Up @@ -67,6 +67,6 @@ export interface SelectionGroupProps<T>
extends Omit<SectionProps<T>, 'children' | 'items'>,
Omit<CollectionBase<T>, 'disabledKeys'>,
Omit<MultipleSelection, 'disabledKeys' | 'selectionMode'> {
onAction?: () => void;
onAction?: (key: Key) => void;
selectionMode: Exclude<SelectionMode, 'none'>;
}
78 changes: 76 additions & 2 deletions src/components/Menu/Menu.unit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,80 @@ describe('<Menu />', () => {
expect(checkboxItems[1]).toHaveFocus();
});

it('should handle click - for vertical menu with SelectionGroup', async () => {
const user = userEvent.setup();

const { getAllByRole } = render(
<Menu {...defaultProps}>
<SelectionGroup
selectionMode="single"
title="SelectionGroup 1"
key="s1"
aria-label="selection1"
>
<Item key="one">One</Item>
<Item key="two">Two</Item>
</SelectionGroup>
<SelectionGroup
selectionMode="multiple"
title="SelectionGroup 2"
key="s2"
aria-label="selection2"
>
<Item key="three">Three</Item>
<Item key="four">Four</Item>
</SelectionGroup>
</Menu>
);

const radioItems = getAllByRole('menuitemradio');
const checkboxItems = getAllByRole('menuitemcheckbox');

await user.click(radioItems[1]);

expect(radioItems[0]).not.toHaveFocus();
expect(radioItems[0]).not.toBeChecked();
expect(radioItems[1]).toHaveFocus();
expect(radioItems[1]).toBeChecked();
expect(checkboxItems[0]).not.toHaveFocus();
expect(checkboxItems[0]).not.toBeChecked();
expect(checkboxItems[1]).not.toHaveFocus();
expect(checkboxItems[1]).not.toBeChecked();

await user.click(checkboxItems[0]);

expect(radioItems[0]).not.toHaveFocus();
expect(radioItems[0]).not.toBeChecked();
expect(radioItems[1]).not.toHaveFocus();
expect(radioItems[1]).toBeChecked();
expect(checkboxItems[0]).toHaveFocus();
expect(checkboxItems[0]).toBeChecked();
expect(checkboxItems[1]).not.toHaveFocus();
expect(checkboxItems[1]).not.toBeChecked();

await user.click(checkboxItems[1]);

expect(radioItems[0]).not.toHaveFocus();
expect(radioItems[0]).not.toBeChecked();
expect(radioItems[1]).not.toHaveFocus();
expect(radioItems[1]).toBeChecked();
expect(checkboxItems[0]).not.toHaveFocus();
expect(checkboxItems[0]).toBeChecked();
expect(checkboxItems[1]).toHaveFocus();
expect(checkboxItems[1]).toBeChecked();

await user.click(radioItems[0]);

expect(radioItems[0]).toHaveFocus();
expect(radioItems[0]).toBeChecked();
expect(radioItems[1]).not.toHaveFocus();
expect(radioItems[1]).not.toBeChecked();
expect(checkboxItems[0]).not.toHaveFocus();
expect(checkboxItems[0]).toBeChecked();
expect(checkboxItems[1]).not.toHaveFocus();
expect(checkboxItems[1]).toBeChecked();
});

it('should render MenuSelectionGroup if children has SelectionGroup', () => {
const wrapper = mount(
<Menu {...defaultProps}>
Expand Down Expand Up @@ -364,7 +438,7 @@ describe('<Menu />', () => {
title: 'SelectionGroup 1',
'aria-label': 'selection1',
children: expect.any(Object),
selectionGroup: true
selectionGroup: true,
});
expect(wrapper.find(MenuSelectionGroup).at(1).props()).toEqual({
item: expect.any(Object),
Expand All @@ -374,7 +448,7 @@ describe('<Menu />', () => {
title: 'SelectionGroup 2',
'aria-label': 'selection2',
children: expect.any(Object),
selectionGroup: true
selectionGroup: true,
});
});
});
Expand Down

0 comments on commit 05cc446

Please sign in to comment.