1import { readdirSync, readFileSync } from 'node:fs'; 2import { describe, expect, it } from 'vitest'; 3import { answersOf, pitchOf } from './pitches.mjs'; 4 5const ID = 'AbCdEfGhIjKlMnOpQrStUv'; 6 7describe('pitchOf: a site song says which pitch it answers', () => { 8 it('takes a pitch id or nothing, and fails the build on anything else', () => { 9 expect(pitchOf(undefined)).toBeNull(); 10 expect(pitchOf(null)).toBeNull(); 11 expect(pitchOf(ID)).toBe(ID); 12 expect(() => pitchOf('short', 'jev/x')).toThrow(/jev\/x: pitch must be a pitch's id/); 13 expect(() => pitchOf(42)).toThrow(/pitch must be/); 14 }); 15 16 it('holds for every song in the repo', () => { 17 const root = new URL('../../../songs/', import.meta.url); 18 for (const theme of readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory())) { 19 for (const song of readdirSync(new URL(`${theme.name}/`, root), { withFileTypes: true }).filter((d) => d.isDirectory())) { 20 const spec = readFileSync(new URL(`${theme.name}/${song.name}/SPEC.md`, root), 'utf8'); 21 const line = spec.split(/^---\s*$/m)[1]?.match(/^pitch:\s*(.*)$/m); 22 if (line) expect(() => pitchOf(line[1].trim().replace(/^["']|["']$/g, ''), song.name)).not.toThrow(); 23 } 24 } 25 }); 26}); 27 28describe('answersOf: every song answering a pitch', () => { 29 it("lists the site's songs from this build, then the listeners' the Worker sent", () => { 30 const pitch = { id: ID, answers: [{ id: 'L'.repeat(22), title: 'A LISTENER SONG' }] }; 31 const site = [ 32 { id: 'jev/hey-listen', title: 'HEY! LISTEN!', pitch: ID }, 33 { id: 'jev/dial-up', title: 'DIAL-UP', pitch: null }, 34 ]; 35 expect(answersOf(pitch, site)).toEqual([ 36 { site: 'jev/hey-listen', title: 'HEY! LISTEN!' }, 37 { listener: 'L'.repeat(22), title: 'A LISTENER SONG' }, 38 ]); 39 expect(answersOf({ id: 'x'.repeat(22) }, site)).toEqual([]); 40 }); 41});