import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils' import UserMenu from '../../src/components/shell/UserMenu.vue' import { currentUser } from '../../src/state/useAuth' import { API, profile, requestsTo, resetState, routerAt, signIn, wait } from '../helpers' async function mountMenu(user: Partial | null) { let calls: Request[] = [] if (user) { calls = await signIn({ [`GET ${API}/auth/me`]: { body: { data: { ...profile.data, ...user }, meta: {} } }, [`POST ${API}/auth/logout`]: { body: { data: { status: 'logged_out' }, meta: {} } }, }) } const router = await routerAt('/acme/demo/widgets') const wrapper = mount(UserMenu, { global: { plugins: [router] }, attachTo: document.body }) await flushPromises() return { wrapper, router, calls } } async function open(wrapper: ReturnType): Promise { const trigger = wrapper.find('[data-user-menu]') await trigger.trigger('keydown', { key: 'Enter' }) await flushPromises() const content = document.querySelector('[data-user-menu-content]') expect(content).not.toBeNull() return content! } beforeEach(() => { resetState() }) afterEach(() => { document.body.innerHTML = '' }) enableAutoUnmount(afterEach) describe('user menu', () => { it('labels the trigger with the name and shows initials, name and role', async () => { const { wrapper } = await mountMenu({}) const trigger = wrapper.find('[data-user-menu]') expect(trigger.attributes('aria-label')).toBe('Menu użytkownika: Dana Dev') expect(trigger.attributes('aria-haspopup')).toBe('menu') expect(trigger.attributes('disabled')).toBeUndefined() expect(wrapper.find('[data-user-initials]').text()).toBe('DD') expect(wrapper.find('[data-user-initials]').attributes('aria-hidden')).toBe('true') expect(wrapper.find('[data-user-role]').text()).toBe('Developer') }) it('falls back to the login for the name and initials and hides a missing role', async () => { const { wrapper } = await mountMenu({ first_name: ' ', last_name: '', login: 'root', role: undefined }) expect(wrapper.find('[data-user-identity]').text()).toBe('root') expect(wrapper.find('[data-user-initials]').text()).toBe('RO') expect(wrapper.find('[data-user-role]').exists()).toBe(false) }) it('uses a single initial for a single name', async () => { const { wrapper } = await mountMenu({ first_name: 'ada', last_name: '' }) expect(wrapper.find('[data-user-initials]').text()).toBe('A') }) it('is disabled without a signed-in admin', async () => { const { wrapper } = await mountMenu(null) expect(currentUser.value).toBeNull() expect(wrapper.find('[data-user-menu]').attributes('disabled')).toBeDefined() expect(wrapper.find('[data-user-initials]').text()).toBe('') }) it('opens a menu with the e-mail and logs out to the login route', async () => { const { wrapper, router, calls } = await mountMenu({}) const content = await open(wrapper) expect(content.getAttribute('role')).toBe('menu') expect(content.textContent).toContain('dev@example.test') const item = content.querySelector('[data-action="logout"]')! expect(item.getAttribute('role')).toBe('menuitem') expect(item.textContent?.trim()).toBe('Wyloguj') item.click() await flushPromises() await wait(0) await flushPromises() expect(requestsTo(calls, 'POST', `${API}/auth/logout`)).toHaveLength(1) expect(currentUser.value).toBeNull() expect(router.currentRoute.value.name).toBe('login') }) })