import { readFileSync } from 'node:fs'; import { join } from 'node:path'; const REVEAL_SCSS = readFileSync(join(process.cwd(), 'src/app/shared/motion/_reveal.scss'), 'utf8'); function mixinBody(source: string): string { const start = source.indexOf('@mixin reveal-target'); expect(start).toBeGreaterThan(-1); return source.slice(start); } describe('reveal-target mixin', () => { it('keeps transition on the base selector so the revealed state can animate', () => { const mixin = mixinBody(REVEAL_SCSS); const transitionIndex = mixin.search(/transition\s*:/); const pendingIndex = mixin.indexOf('&.reveal-pending'); const revealedIndex = mixin.indexOf('&.is-revealed'); expect(transitionIndex).toBeGreaterThan(-1); expect(pendingIndex).toBeGreaterThan(-1); expect(revealedIndex).toBeGreaterThan(pendingIndex); expect(transitionIndex).toBeLessThan(pendingIndex); const pendingBlock = mixin.match(/&\.reveal-pending\s*\{([^}]*)\}/)?.[1] ?? ''; expect(pendingBlock).toMatch(/opacity\s*:/); expect(pendingBlock).not.toMatch(/transition\s*:/); const revealedBlock = mixin.match(/&\.is-revealed\s*\{([^}]*)\}/)?.[1] ?? ''; expect(revealedBlock).toMatch(/opacity\s*:\s*1/); expect(revealedBlock).not.toMatch(/transition\s*:/); expect(mixin).toMatch(/prefers-reduced-motion:\s*reduce/); expect(mixin).toMatch(/&\s*,\s*&\.reveal-pending/); expect(mixin).toMatch(/&\.is-revealed\s*\{[\s\S]*transition:\s*none/); }); });