import { mount } from '@vue/test-utils'; import { describe, expect, it } from 'vitest'; import ContactDestination from '@/components/ContactDestination.vue'; import InfrastructureDiagram from '@/components/InfrastructureDiagram.vue'; import ProjectCaseStudy from '@/components/ProjectCaseStudy.vue'; import ToolkitGrid from '@/components/ToolkitGrid.vue'; import type { ContactContent, InfrastructureCaseStudy, PublicProject, ToolkitGroup } from '@/content/types'; const infrastructure: InfrastructureCaseStudy = { id: 'safe-infrastructure', title: 'Secure self-hosted platform and lifecycle', summary: 'A compact infrastructure case study.', bands: [ { id: 'ingress-tls', title: 'Ingress and TLS', summary: 'Managed encrypted ingress.' }, { id: 'identity-access', title: 'Identity and access', summary: 'Protected service access.' }, ], }; const privateProject: PublicProject = { id: 'private-work', title: 'Private self-hosted medication tracker', visibility: 'private', maturity: 'active', summary: 'A private application.', problem: 'A recurring workflow needs reliable tracking.', contribution: 'Designed and maintained the application.', technicalDecisions: ['Used a synchronised client and server design.'], outcome: 'The work remains private.', assetIds: [], }; const publicProject: PublicProject = { ...privateProject, id: 'public-work', title: 'Footy Tracker', visibility: 'public', url: 'https://github.com/example/footy-tracker', }; describe('semantic section components', () => { it('gives the infrastructure graphic an accessible name, description, caption, and visible text equivalent', () => { const wrapper = mount(InfrastructureDiagram, { props: { infrastructure } }); const svg = wrapper.get('svg'); expect(svg.attributes('role')).toBe('img'); expect(svg.attributes('aria-labelledby')).toContain('safe-infrastructure-diagram-title'); expect(svg.attributes('aria-describedby')).toContain('safe-infrastructure-diagram-description'); expect(wrapper.get('figcaption').text()).toContain('Secure self-hosted platform and lifecycle'); expect(wrapper.get('[data-testid="infrastructure-text-equivalent"]').text()).toContain('Ingress and TLS'); expect(wrapper.get('[data-testid="infrastructure-text-equivalent"]').text()).toContain('Identity and access'); }); it('does not turn private project content into a link container', () => { const wrapper = mount(ProjectCaseStudy, { props: { project: privateProject, priority: 'primary' } }); expect(wrapper.get('article').findAll('a')).toHaveLength(0); expect(wrapper.get('h3').text()).toBe('Private self-hosted medication tracker'); expect(wrapper.get('article').attributes('data-project-priority')).toBe('primary'); }); it('uses a safe external link only for a public project with an approved URL', () => { const wrapper = mount(ProjectCaseStudy, { props: { project: publicProject, priority: 'supporting' } }); const link = wrapper.get('article a'); expect(link.attributes('href')).toBe('https://github.com/example/footy-tracker'); expect(link.attributes('target')).toBe('_blank'); expect(link.attributes('rel')).toBe('noopener noreferrer'); }); it('announces every toolkit technology once while hiding the decorative icon placeholder', () => { const groups: readonly ToolkitGroup[] = [{ title: 'Systems & delivery', technologies: [{ name: 'Linux' }], }]; const wrapper = mount(ToolkitGrid, { props: { groups } }); const tile = wrapper.get('[data-testid="toolkit-technology"]'); expect(tile.text()).toBe('Linux'); expect(tile.get('[aria-hidden="true"]').attributes('aria-hidden')).toBe('true'); expect(tile.findAll('[aria-label="Linux"]').length).toBe(0); }); it('renders a visible mailto contact and safe verified social links', () => { const contact: ContactContent = { email: 'hello@example.test', cvMessage: 'For a current CV or role-specific information, contact me directly.', social: [{ service: 'GitHub', url: 'https://github.com/example' }], }; const wrapper = mount(ContactDestination, { props: { contact, }, }); expect(wrapper.get('a[href="mailto:hello@example.test"]').text()).toBe('Start a conversation'); expect(wrapper.text()).toContain("Thanks for making the trip. The road's open if you'd like to build something together."); const social = wrapper.get('a[href="https://github.com/example"]'); expect(social.text()).toBe('GitHub'); expect(social.attributes('rel')).toBe('noopener noreferrer'); }); });