From 400ad78c0597386579339145dd71b600a8360411 Mon Sep 17 00:00:00 2001 From: OM MISHRA <152969928+howwohmm@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:07:42 +0530 Subject: [PATCH 1/5] test(ui): add tests for mobile menu default state and open/close behavior Covers issue requirements: - Menu is closed by default (dialog not in DOM) - Opens when prop is set to true - Closes when prop changes back to false - Emits update:open on backdrop click - Emits update:open on close button click Co-Authored-By: Claude Opus 4.6 --- .../nuxt/components/Header/MobileMenu.spec.ts | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 test/nuxt/components/Header/MobileMenu.spec.ts diff --git a/test/nuxt/components/Header/MobileMenu.spec.ts b/test/nuxt/components/Header/MobileMenu.spec.ts new file mode 100644 index 0000000000..933e8fa8b9 --- /dev/null +++ b/test/nuxt/components/Header/MobileMenu.spec.ts @@ -0,0 +1,112 @@ +import { describe, it, expect, vi } from 'vitest' +import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime' +import { ref, computed, nextTick } from 'vue' + +// Mock useConnector +mockNuxtImport('useConnector', () => () => ({ + isConnected: computed(() => false), + npmUser: computed(() => null), + avatar: computed(() => null), +})) + +// Mock useAtproto +mockNuxtImport('useAtproto', () => () => ({ + user: computed(() => null), +})) + +// Mock useFocusTrap (from @vueuse/integrations) +vi.mock('@vueuse/integrations/useFocusTrap', () => ({ + useFocusTrap: () => ({ + activate: vi.fn(), + deactivate: vi.fn(), + }), +})) + +describe('MobileMenu', () => { + async function mountMenu(open = false) { + const { MobileMenuClient } = await import('#components') + return mountSuspended(MobileMenuClient, { + props: { + open, + links: [ + { + type: 'group' as const, + name: 'main', + label: 'Navigation', + items: [ + { name: 'home', label: 'Home', to: '/', iconClass: 'i-lucide:home' }, + ], + }, + ], + }, + attachTo: document.body, + }) + } + + it('is closed by default', async () => { + const wrapper = await mountMenu(false) + try { + // Menu content is behind v-if="isOpen" inside a Teleport + expect(document.querySelector('[role="dialog"]')).toBeNull() + } finally { + wrapper.unmount() + } + }) + + it('opens when the open prop is set to true', async () => { + const wrapper = await mountMenu(true) + try { + await nextTick() + const dialog = document.querySelector('[role="dialog"]') + expect(dialog).not.toBeNull() + expect(dialog?.getAttribute('aria-modal')).toBe('true') + } finally { + wrapper.unmount() + } + }) + + it('closes when open prop changes from true to false', async () => { + const wrapper = await mountMenu(true) + try { + await nextTick() + expect(document.querySelector('[role="dialog"]')).not.toBeNull() + + await wrapper.setProps({ open: false }) + await nextTick() + expect(document.querySelector('[role="dialog"]')).toBeNull() + } finally { + wrapper.unmount() + } + }) + + it('emits update:open false when backdrop is clicked', async () => { + const wrapper = await mountMenu(true) + try { + await nextTick() + const backdrop = document.querySelector('[role="dialog"] > button') + expect(backdrop).not.toBeNull() + backdrop?.dispatchEvent(new Event('click', { bubbles: true })) + await nextTick() + expect(wrapper.emitted('update:open')).toBeTruthy() + expect(wrapper.emitted('update:open')![0]).toEqual([false]) + } finally { + wrapper.unmount() + } + }) + + it('emits update:open false when close button is clicked', async () => { + const wrapper = await mountMenu(true) + try { + await nextTick() + // Close button has aria-label matching $t('common.close') — find it inside nav + const closeBtn = document.querySelector('nav button[aria-label]') + expect(closeBtn).not.toBeNull() + closeBtn?.dispatchEvent(new Event('click', { bubbles: true })) + await nextTick() + expect(wrapper.emitted('update:open')).toBeTruthy() + expect(wrapper.emitted('update:open')![0]).toEqual([false]) + } finally { + wrapper.unmount() + } + }) +}) From a92bbc053cf9985bc3065252587aad2f3a1d854b Mon Sep 17 00:00:00 2001 From: OM MISHRA <152969928+howwohmm@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:19:13 +0530 Subject: [PATCH 2/5] fix(test): correct component name and remove unused import The Nuxt auto-generated name for Header/MobileMenu.client.vue is HeaderMobileMenu, not MobileMenuClient. Also removes unused `ref` import. Co-Authored-By: Claude Opus 4.6 --- test/nuxt/components/Header/MobileMenu.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/nuxt/components/Header/MobileMenu.spec.ts b/test/nuxt/components/Header/MobileMenu.spec.ts index 933e8fa8b9..7caa435b41 100644 --- a/test/nuxt/components/Header/MobileMenu.spec.ts +++ b/test/nuxt/components/Header/MobileMenu.spec.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi } from 'vitest' import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime' -import { ref, computed, nextTick } from 'vue' +import { computed, nextTick } from 'vue' // Mock useConnector mockNuxtImport('useConnector', () => () => ({ @@ -24,8 +24,8 @@ vi.mock('@vueuse/integrations/useFocusTrap', () => ({ describe('MobileMenu', () => { async function mountMenu(open = false) { - const { MobileMenuClient } = await import('#components') - return mountSuspended(MobileMenuClient, { + const { HeaderMobileMenu } = await import('#components') + return mountSuspended(HeaderMobileMenu, { props: { open, links: [ From 87dad030ef4f57ca1a9213626827b2362f8e4f8c Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 22 Mar 2026 11:50:26 +0000 Subject: [PATCH 3/5] [autofix.ci] apply automated fixes --- test/nuxt/components/Header/MobileMenu.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/nuxt/components/Header/MobileMenu.spec.ts b/test/nuxt/components/Header/MobileMenu.spec.ts index 7caa435b41..2b7ab31d2e 100644 --- a/test/nuxt/components/Header/MobileMenu.spec.ts +++ b/test/nuxt/components/Header/MobileMenu.spec.ts @@ -33,9 +33,7 @@ describe('MobileMenu', () => { type: 'group' as const, name: 'main', label: 'Navigation', - items: [ - { name: 'home', label: 'Home', to: '/', iconClass: 'i-lucide:home' }, - ], + items: [{ name: 'home', label: 'Home', to: '/', iconClass: 'i-lucide:home' }], }, ], }, From 63493f889eabe3e862f663a0e216833d4828c7e8 Mon Sep 17 00:00:00 2001 From: OM MISHRA <152969928+howwohmm@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:26:41 +0530 Subject: [PATCH 4/5] fix(test): use static import and add missing type field Switch from dynamic `await import('#components')` to static top-level import to match the pattern used by HeaderConnectorModal.spec.ts. Add required `type: 'link'` to NavigationLink test data. Co-Authored-By: Claude Opus 4.6 --- test/nuxt/components/Header/MobileMenu.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nuxt/components/Header/MobileMenu.spec.ts b/test/nuxt/components/Header/MobileMenu.spec.ts index 2b7ab31d2e..4514bf68ce 100644 --- a/test/nuxt/components/Header/MobileMenu.spec.ts +++ b/test/nuxt/components/Header/MobileMenu.spec.ts @@ -1,6 +1,7 @@ import { describe, it, expect, vi } from 'vitest' import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime' import { computed, nextTick } from 'vue' +import { HeaderMobileMenu } from '#components' // Mock useConnector mockNuxtImport('useConnector', () => () => ({ @@ -24,7 +25,6 @@ vi.mock('@vueuse/integrations/useFocusTrap', () => ({ describe('MobileMenu', () => { async function mountMenu(open = false) { - const { HeaderMobileMenu } = await import('#components') return mountSuspended(HeaderMobileMenu, { props: { open, @@ -33,7 +33,7 @@ describe('MobileMenu', () => { type: 'group' as const, name: 'main', label: 'Navigation', - items: [{ name: 'home', label: 'Home', to: '/', iconClass: 'i-lucide:home' }], + items: [{ type: 'link' as const, name: 'home', label: 'Home', to: '/', iconClass: 'i-lucide:home' }], }, ], }, From dd44bf84504d84ad366da2a6536927368efa20e3 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 22 Mar 2026 11:58:25 +0000 Subject: [PATCH 5/5] [autofix.ci] apply automated fixes --- test/nuxt/components/Header/MobileMenu.spec.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/nuxt/components/Header/MobileMenu.spec.ts b/test/nuxt/components/Header/MobileMenu.spec.ts index 4514bf68ce..7298381541 100644 --- a/test/nuxt/components/Header/MobileMenu.spec.ts +++ b/test/nuxt/components/Header/MobileMenu.spec.ts @@ -33,7 +33,15 @@ describe('MobileMenu', () => { type: 'group' as const, name: 'main', label: 'Navigation', - items: [{ type: 'link' as const, name: 'home', label: 'Home', to: '/', iconClass: 'i-lucide:home' }], + items: [ + { + type: 'link' as const, + name: 'home', + label: 'Home', + to: '/', + iconClass: 'i-lucide:home', + }, + ], }, ], },