import { describe, test, expect } from 'vitest'; import { SocialLinks } from './SocialLinks'; const toHtml = (SocialLinks as any).toHtml; describe('SocialLinks.toHtml accessibility (F2.5)', () => { test('icon-only links get an aria-label naming the platform', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: 'https://fb.example/x' }] }, ''); expect(html).toMatch(/]*aria-label="Facebook"/); }); test('the icon glyph itself is aria-hidden', () => { const { html } = toHtml({ links: [{ platform: 'twitter', url: '#' }] }, ''); expect(html).toMatch(/]*aria-hidden="true"/); }); }); describe('SocialLinks.toHtml XSS hardening (iconSize/iconColor/iconBgColor/gap into style=)', () => { test('an iconSize value with an attribute-breakout string cannot escape style=""', () => { const malicious = '20px" onmouseover="alert(1)'; const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconSize: malicious as any }, ''); expect(html).not.toMatch(/"\s+onmouseover="/); }); test('an iconColor value with an attribute-breakout string cannot escape style=""', () => { const malicious = '#fff" onmouseover="alert(1)'; const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconColor: malicious as any }, ''); expect(html).not.toMatch(/"\s+onmouseover="/); }); test('an iconBgColor value with an attribute-breakout string cannot escape style=""', () => { const malicious = '#374151" onmouseover="alert(1)'; const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconShape: 'circle', iconBgColor: malicious as any }, ''); expect(html).not.toMatch(/"\s+onmouseover="/); }); test('a gap value with an attribute-breakout string cannot escape the wrapper style=""', () => { const malicious = '10px" onmouseover="alert(1)'; const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], gap: malicious as any }, ''); expect(html).not.toMatch(/"\s+onmouseover="/); }); test('a malicious platform key does not produce a raw class-attribute breakout', () => { const malicious = 'x">'; const { html } = toHtml({ links: [{ platform: malicious, url: '#' }] }, ''); expect(html).not.toContain(''); }); test('a link url with a javascript: scheme is neutralized', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: 'javascript:alert(1)' }] }, ''); expect(html).not.toContain('javascript:alert(1)'); }); }); describe('SocialLinks.toHtml iconShape/gap emission (previously built but unexposed in SocialStylePanel)', () => { test('iconShape="circle" emits a 50% border-radius on the wrapping ', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconShape: 'circle' }, ''); expect(html).toMatch(/]*style="[^"]*border-radius:50%[^"]*"/); }); test('iconShape="square" emits border-radius:0', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconShape: 'square' }, ''); expect(html).toMatch(/]*style="[^"]*border-radius:0[^"]*"/); }); test('iconShape="rounded" emits a 6px border-radius', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconShape: 'rounded' }, ''); expect(html).toMatch(/]*style="[^"]*border-radius:6px[^"]*"/); }); test('iconShape="none" omits the background box entirely (transparent bg, no fixed box size)', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], iconShape: 'none' }, ''); const aTag = html.match(/]*>/)![0]; expect(aTag).toContain('background-color:transparent'); expect(aTag).not.toContain('border-radius'); }); test('gap emits on the wrapper
style', () => { const { html } = toHtml({ links: [{ platform: 'facebook', url: '#' }], gap: '24px' }, ''); expect(html).toMatch(/]*style="[^"]*gap:24px[^"]*"/); }); }); describe('SocialLinks.craft.props includes the box-model/animation/visibility rollout props', () => { test('animation, animationDelay, and all 3 hideOn* flags are declared (blank/false defaults)', () => { const props = (SocialLinks as any).craft.props; expect(props).toHaveProperty('animation', ''); expect(props).toHaveProperty('animationDelay', ''); expect(props).toHaveProperty('hideOnDesktop', false); expect(props).toHaveProperty('hideOnTablet', false); expect(props).toHaveProperty('hideOnMobile', false); }); });