import { render } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { IsotypeFrames } from './IsotypeFrames'; import { ISOTYPE_FRAME_VARIANTS, ISOTYPE_FRAME_VARIANT_IDS } from './frame-variants'; import { ISOTYPE_COLORS } from './patterns'; import React from 'react'; describe('IsotypeFrames', () => { it('renders two overlapping rects', () => { const { container } = render(); expect(container.querySelectorAll('rect')).toHaveLength(2); }); it('defaults to the blue-magenta variant', () => { const { container } = render(); const rects = container.querySelectorAll('rect'); const [backKey, frontKey] = ISOTYPE_FRAME_VARIANTS['blue-magenta']; expect(rects[0].getAttribute('stroke')).toBe(ISOTYPE_COLORS[backKey]); expect(rects[1].getAttribute('stroke')).toBe(ISOTYPE_COLORS[frontKey]); }); it('renders every registered variant with the right stroke colors', () => { for (const variant of ISOTYPE_FRAME_VARIANT_IDS) { const { container } = render(); const rects = container.querySelectorAll('rect'); const [backKey, frontKey] = ISOTYPE_FRAME_VARIANTS[variant]; expect(rects[0].getAttribute('stroke')).toBe(ISOTYPE_COLORS[backKey]); expect(rects[1].getAttribute('stroke')).toBe(ISOTYPE_COLORS[frontKey]); } }); it('renders each rect hollow (fill="none")', () => { const { container } = render(); container.querySelectorAll('rect').forEach(rect => { expect(rect.getAttribute('fill')).toBe('none'); }); }); it('passes className through to the root', () => { const { container } = render(); expect((container.firstChild as HTMLElement).className).toContain('w-64'); }); it('offsets the front frame diagonally from the back frame by a sixth of the shared size', () => { const { container } = render(); const [back, front] = Array.from(container.querySelectorAll('rect')); const backX = Number(back.getAttribute('x')); const backY = Number(back.getAttribute('y')); const backSize = Number(back.getAttribute('width')); const frontX = Number(front.getAttribute('x')); const frontY = Number(front.getAttribute('y')); const frontSize = Number(front.getAttribute('width')); expect(backSize).toBe(frontSize); expect(frontX - backX).toBeCloseTo(backSize / 6); expect(frontY - backY).toBeCloseTo(backSize / 6); }); it('renders both frames fully opaque and blends their intersection via mix-blend-mode on the front frame', () => { const { container } = render(); const [back, front] = Array.from(container.querySelectorAll('rect')); expect(back.getAttribute('opacity')).toBeNull(); expect(front.getAttribute('opacity')).toBeNull(); expect(front.style.mixBlendMode).toBeTruthy(); expect(front.style.mixBlendMode).not.toBe('normal'); }); it('isolates the blend mode to the two frames via the root isolate class', () => { const { container } = render(); expect((container.firstChild as HTMLElement).className).toContain('isolate'); }); it('expands the viewBox so no edge of the stroked frames is clipped', () => { const { container } = render(); const svg = container.querySelector('svg')!; const [minX, minY, width, height] = svg.getAttribute('viewBox')!.split(' ').map(Number); container.querySelectorAll('rect').forEach(rect => { const x = Number(rect.getAttribute('x')); const y = Number(rect.getAttribute('y')); const size = Number(rect.getAttribute('width')); const half = Number(rect.getAttribute('stroke-width')) / 2; expect(x - half).toBeGreaterThanOrEqual(minX); expect(y - half).toBeGreaterThanOrEqual(minY); expect(x + size + half).toBeLessThanOrEqual(minX + width); expect(y + size + half).toBeLessThanOrEqual(minY + height); }); }); });