|
@@ -3,87 +3,127 @@
|
|
|
import CommonActionMenu from '#desktop/components/CommonActionMenu/CommonActionMenu.vue'
|
|
|
import renderComponent from '#tests/support/components/renderComponent.ts'
|
|
|
import type { ObjectLike } from '#shared/types/utils.ts'
|
|
|
+import type { MenuItem } from '#desktop/components/CommonPopover/types.ts'
|
|
|
+import type { Props } from '../CommonActionMenu.vue'
|
|
|
|
|
|
const fn = vi.fn()
|
|
|
-describe('CommonActionMenu', () => {
|
|
|
- let view: ReturnType<typeof renderComponent>
|
|
|
|
|
|
- const actions = [
|
|
|
+describe('CommonActionMenu', () => {
|
|
|
+ const actions: MenuItem[] = [
|
|
|
{
|
|
|
key: 'delete-foo',
|
|
|
label: 'Delete Foo',
|
|
|
icon: 'trash3',
|
|
|
- onClick: ({ id }: { id: string }) => {
|
|
|
- fn(id)
|
|
|
+ show: () => true,
|
|
|
+ onClick: (entity?: ObjectLike) => {
|
|
|
+ fn(entity?.id)
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
key: 'change-foo',
|
|
|
label: 'Change Foo',
|
|
|
icon: 'person-gear',
|
|
|
- onClick: ({ id }: { id: string }) => {
|
|
|
- fn(id)
|
|
|
+ show: () => true,
|
|
|
+ onClick: (entity?: ObjectLike) => {
|
|
|
+ fn(entity?.id)
|
|
|
},
|
|
|
},
|
|
|
]
|
|
|
|
|
|
- beforeEach(() => {
|
|
|
- view = renderComponent(CommonActionMenu, {
|
|
|
+ const renderActionMenu = async (
|
|
|
+ actions: MenuItem[],
|
|
|
+ props?: Partial<Props>,
|
|
|
+ ) => {
|
|
|
+ return renderComponent(CommonActionMenu, {
|
|
|
props: {
|
|
|
+ ...props,
|
|
|
entity: {
|
|
|
id: 'foo-test-action',
|
|
|
},
|
|
|
actions,
|
|
|
},
|
|
|
})
|
|
|
- })
|
|
|
+ }
|
|
|
|
|
|
- it('shows action menu button by default', () => {
|
|
|
- expect(view.getByIconName('three-dots-vertical')).toBeInTheDocument()
|
|
|
- })
|
|
|
+ describe('Multiple Actions', () => {
|
|
|
+ it('shows action menu button by default', async () => {
|
|
|
+ const view = await renderActionMenu(actions)
|
|
|
+ expect(view.getByIconName('three-dots-vertical')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('show not content when no item exists', async () => {
|
|
|
+ const view = await renderActionMenu([
|
|
|
+ {
|
|
|
+ ...actions[0],
|
|
|
+ show: () => false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ ...actions[1],
|
|
|
+ show: () => false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'example',
|
|
|
+ label: 'Example',
|
|
|
+ show: () => false,
|
|
|
+ },
|
|
|
+ ])
|
|
|
+
|
|
|
+ expect(
|
|
|
+ view.queryByIconName('three-dots-vertical'),
|
|
|
+ ).not.toBeInTheDocument()
|
|
|
+ })
|
|
|
|
|
|
- it('calls onClick handler when action is clicked', async () => {
|
|
|
- await view.events.click(view.getByIconName('three-dots-vertical'))
|
|
|
+ it('calls onClick handler when action is clicked', async () => {
|
|
|
+ const view = await renderActionMenu(actions)
|
|
|
|
|
|
- expect(view.getByIconName('trash3')).toBeInTheDocument()
|
|
|
- expect(view.getByIconName('person-gear')).toBeInTheDocument()
|
|
|
+ await view.events.click(view.getByIconName('three-dots-vertical'))
|
|
|
|
|
|
- await view.events.click(view.getByText('Change Foo'))
|
|
|
+ expect(view.getByIconName('trash3')).toBeInTheDocument()
|
|
|
+ expect(view.getByIconName('person-gear')).toBeInTheDocument()
|
|
|
|
|
|
- expect(fn).toHaveBeenCalledWith('foo-test-action')
|
|
|
- })
|
|
|
+ await view.events.click(view.getByText('Change Foo'))
|
|
|
|
|
|
- it('finds corresponding a11y controls', async () => {
|
|
|
- await view.events.click(view.getByIconName('three-dots-vertical'))
|
|
|
- const id = view
|
|
|
- .getByLabelText('Action menu button')
|
|
|
- .getAttribute('aria-controls')
|
|
|
+ expect(fn).toHaveBeenCalledWith('foo-test-action')
|
|
|
+ })
|
|
|
|
|
|
- const popover = document.getElementById(id as string)
|
|
|
+ it('finds corresponding a11y controls', async () => {
|
|
|
+ const view = await renderActionMenu(actions)
|
|
|
|
|
|
- expect(popover?.getAttribute('id')).toEqual(id)
|
|
|
- })
|
|
|
+ await view.events.click(view.getByIconName('three-dots-vertical'))
|
|
|
+ const id = view
|
|
|
+ .getByLabelText('Action menu button')
|
|
|
+ .getAttribute('aria-controls')
|
|
|
|
|
|
- it('sets a custom aria label on single action button', async () => {
|
|
|
- await view.rerender({
|
|
|
- customMenuButtonLabel: 'Custom Action Menu Label',
|
|
|
+ const popover = document.getElementById(id as string)
|
|
|
+
|
|
|
+ expect(popover?.getAttribute('id')).toEqual(id)
|
|
|
})
|
|
|
|
|
|
- expect(view.getByLabelText('Custom Action Menu Label')).toBeInTheDocument()
|
|
|
- })
|
|
|
+ it('sets a custom aria label on single action button', async () => {
|
|
|
+ const view = await renderActionMenu(actions, {
|
|
|
+ customMenuButtonLabel: 'Custom Action Menu Label',
|
|
|
+ })
|
|
|
|
|
|
- describe('single action mode', () => {
|
|
|
- beforeEach(async () => {
|
|
|
await view.rerender({
|
|
|
- actions: [actions[0]],
|
|
|
+ customMenuButtonLabel: 'Custom Action Menu Label',
|
|
|
})
|
|
|
+
|
|
|
+ expect(
|
|
|
+ view.getByLabelText('Custom Action Menu Label'),
|
|
|
+ ).toBeInTheDocument()
|
|
|
})
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('single action mode', () => {
|
|
|
+ it('adds aria label on single action button', async () => {
|
|
|
+ const view = await renderActionMenu([actions[0]])
|
|
|
|
|
|
- it('adds aria label on single action button', () => {
|
|
|
expect(view.getByLabelText('Delete Foo')).toBeInTheDocument()
|
|
|
})
|
|
|
|
|
|
- it('supports single action mode', () => {
|
|
|
+ it('supports single action mode', async () => {
|
|
|
+ const view = await renderActionMenu([actions[0]])
|
|
|
+
|
|
|
expect(
|
|
|
view.queryByIconName('three-dots-vertical'),
|
|
|
).not.toBeInTheDocument()
|
|
@@ -92,13 +132,15 @@ describe('CommonActionMenu', () => {
|
|
|
})
|
|
|
|
|
|
it('calls onClick handler when action is clicked', async () => {
|
|
|
+ const view = await renderActionMenu([actions[0]])
|
|
|
+
|
|
|
await view.events.click(view.getByIconName('trash3'))
|
|
|
|
|
|
expect(fn).toHaveBeenCalledWith('foo-test-action')
|
|
|
})
|
|
|
|
|
|
it('renders single action if prop is set', async () => {
|
|
|
- await view.rerender({
|
|
|
+ const view = await renderActionMenu([actions[0]], {
|
|
|
noSingleActionMode: true,
|
|
|
})
|
|
|
|
|
@@ -110,19 +152,17 @@ describe('CommonActionMenu', () => {
|
|
|
})
|
|
|
|
|
|
it('sets a custom aria label on single action', async () => {
|
|
|
- await view.rerender({
|
|
|
- actions: [
|
|
|
- {
|
|
|
- key: 'delete-foo',
|
|
|
- label: 'Delete Foo',
|
|
|
- ariaLabel: 'Custom Delete Foo',
|
|
|
- icon: 'trash3',
|
|
|
- onClick: ({ id }: { id: string }) => {
|
|
|
- fn(id)
|
|
|
- },
|
|
|
+ const view = await renderActionMenu([
|
|
|
+ {
|
|
|
+ key: 'delete-foo',
|
|
|
+ label: 'Delete Foo',
|
|
|
+ ariaLabel: 'Custom Delete Foo',
|
|
|
+ icon: 'trash3',
|
|
|
+ onClick: (entity?: ObjectLike) => {
|
|
|
+ fn(entity?.id)
|
|
|
},
|
|
|
- ],
|
|
|
- })
|
|
|
+ },
|
|
|
+ ])
|
|
|
|
|
|
expect(view.getByLabelText('Custom Delete Foo')).toBeInTheDocument()
|
|
|
|
|
@@ -133,8 +173,8 @@ describe('CommonActionMenu', () => {
|
|
|
label: 'Delete Foo',
|
|
|
ariaLabel: (entity: ObjectLike) => `label ${entity.id}`,
|
|
|
icon: 'trash3',
|
|
|
- onClick: ({ id }: { id: string }) => {
|
|
|
- fn(id)
|
|
|
+ onClick: (entity?: ObjectLike) => {
|
|
|
+ fn(entity?.id)
|
|
|
},
|
|
|
},
|
|
|
],
|