import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { mount } from '@vue/test-utils' import { defineComponent, nextTick } from 'vue' import { useMobileBackButton } from '../useMobileBackButton' // Helper component that uses the composable const TestComponent = defineComponent({ setup() { return useMobileBackButton() }, template: '
{{ bottomPosition }}
', }) describe('useMobileBackButton', () => { let wrapper: ReturnType beforeEach(() => { vi.useFakeTimers() }) afterEach(() => { wrapper?.unmount() vi.useRealTimers() }) it('returns bottomPosition, bottomClass, and tabBarHeight', () => { wrapper = mount(TestComponent) const vm = wrapper.vm as unknown as { bottomPosition: string bottomClass: string tabBarHeight: number } expect(typeof vm.bottomPosition).toBe('string') expect(typeof vm.bottomClass).toBe('string') expect(typeof vm.tabBarHeight).toBe('number') }) it('defaults tabBarHeight to 72', () => { wrapper = mount(TestComponent) const vm = wrapper.vm as unknown as { tabBarHeight: number } expect(vm.tabBarHeight).toBe(72) }) it('computes bottomPosition as tabBarHeight + 8', () => { wrapper = mount(TestComponent) const vm = wrapper.vm as unknown as { bottomPosition: string tabBarHeight: number } expect(vm.bottomPosition).toBe('80px') // 72 + 8 }) it('computes bottomClass with Tailwind arbitrary value', () => { wrapper = mount(TestComponent) const vm = wrapper.vm as unknown as { bottomClass: string } expect(vm.bottomClass).toBe('bottom-[80px]') }) it('reads tabBar element if present', async () => { // Create mock tab bar element const tabBar = document.createElement('div') tabBar.setAttribute('data-mobile-tab-bar', '') Object.defineProperty(tabBar, 'offsetHeight', { value: 56 }) document.body.appendChild(tabBar) wrapper = mount(TestComponent) await nextTick() const vm = wrapper.vm as unknown as { tabBarHeight: number } expect(vm.tabBarHeight).toBe(56) document.body.removeChild(tabBar) }) it('falls back to CSS variable when no tab bar element', async () => { document.documentElement.style.setProperty('--mobile-tab-bar-height', '64') wrapper = mount(TestComponent) await nextTick() const vm = wrapper.vm as unknown as { tabBarHeight: number } expect(vm.tabBarHeight).toBe(64) document.documentElement.style.removeProperty('--mobile-tab-bar-height') }) it('keeps default when no tab bar or CSS var', async () => { wrapper = mount(TestComponent) await nextTick() const vm = wrapper.vm as unknown as { tabBarHeight: number } // Should keep the default of 72 expect(vm.tabBarHeight).toBe(72) }) it('cleans up observers on unmount', () => { wrapper = mount(TestComponent) const removeEventSpy = vi.spyOn(window, 'removeEventListener') wrapper.unmount() expect(removeEventSpy).toHaveBeenCalled() removeEventSpy.mockRestore() }) it('updates on window resize', async () => { const tabBar = document.createElement('div') tabBar.setAttribute('data-mobile-tab-bar', '') Object.defineProperty(tabBar, 'offsetHeight', { value: 48, writable: true, configurable: true, }) document.body.appendChild(tabBar) wrapper = mount(TestComponent) await nextTick() // Trigger resize window.dispatchEvent(new Event('resize')) await nextTick() const vm = wrapper.vm as unknown as { tabBarHeight: number } expect(vm.tabBarHeight).toBe(48) document.body.removeChild(tabBar) }) })