import { mount } from '@vue/test-utils'; import { nextTick } from 'vue'; import { afterEach, describe, expect, it, vi } from 'vitest'; import ContactDestination from '@/components/ContactDestination.vue'; import { parsePortfolioContent } from '@/content/schemas'; import content from '@/../content/public/portfolio-content.json'; const contact = parsePortfolioContent(content).contact; afterEach(() => vi.unstubAllGlobals()); describe('contact disclosure', () => { it('assembles a mail link only after pointer or keyboard interaction', async () => { const wrapper = mount(ContactDestination, { props: { contact } }); await nextTick(); expect(wrapper.find('a[href^="mailto:"]').exists()).toBe(false); expect(wrapper.get('.contact-email__preview').text()).toBe(''); await wrapper.get('.contact-email__action').trigger('focusin'); expect(wrapper.get('a.contact-link').attributes('href')).toBe('mailto:luca.pislaru@gmail.com'); expect(wrapper.get('a.contact-link').text()).toBe('Email Me'); expect(wrapper.get('a.contact-link').attributes('target')).toBe('_blank'); expect(wrapper.get('a.contact-link').attributes('rel')).toBe('noopener noreferrer'); wrapper.unmount(); }); it('reveals a copyable address through the native disclosure', async () => { const writeText = vi.fn().mockResolvedValue(undefined); vi.stubGlobal('navigator', { clipboard: { writeText } }); const wrapper = mount(ContactDestination, { props: { contact } }); await nextTick(); const details = wrapper.get('details'); (details.element as HTMLDetailsElement).open = true; await details.trigger('toggle'); expect(wrapper.get('summary').text()).toBe('Hide email'); expect(wrapper.get('.contact-email__address').text()).toBe('luca.pislaru@gmail.com'); await wrapper.get('.contact-email__copy').trigger('click'); expect(writeText).toHaveBeenCalledWith('luca.pislaru@gmail.com'); expect(wrapper.get('[role="status"]').text()).toBe('Copied'); await wrapper.get('.contact-email').trigger('keydown', { key: 'Escape' }); expect((details.element as HTMLDetailsElement).open).toBe(false); wrapper.unmount(); }); it('keeps the address selectable when clipboard permission is unavailable', async () => { vi.stubGlobal('navigator', { clipboard: { writeText: vi.fn().mockRejectedValue(new Error('Unavailable')) } }); const wrapper = mount(ContactDestination, { props: { contact } }); await nextTick(); (wrapper.get('details').element as HTMLDetailsElement).open = true; await wrapper.get('details').trigger('toggle'); await wrapper.get('.contact-email__copy').trigger('click'); expect(wrapper.get('[role="status"]').text()).toBe('Select the address to copy it.'); expect(wrapper.get('.contact-email__address').text()).toContain('@'); wrapper.unmount(); }); });