// Tests of create-words.ts: the list of the page, fetched once, with its // pinned SHA-256, and fetched again after a failure. import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; import { type Fetcher, wordListLoader, WORDS_LANGUAGE } from './create-words.ts'; const list = new Uint8Array(readFileSync(fileURLToPath(new URL('../../../wordlists/es.txt', import.meta.url)))); describe('wordListLoader', () => { it('fetches the Spanish list of the site once, and reads it with its pinned SHA-256', async () => { const urls: string[] = []; const load = wordListLoader(async (url) => { urls.push(url); return new Response(list.slice()); }); const [a, b] = await Promise.all([load(), load()]); expect(WORDS_LANGUAGE).toBe('es'); expect(a).toHaveLength(7776); expect(b).toBe(a); expect(await load()).toBe(a); expect(urls).toHaveLength(1); expect(urls[0]).toMatch(/wordlists\/es\.txt$/); }); it('tries again after a failure: an answer that is not 200, another list, a fetch that fails', async () => { const changed = list.slice(); changed[0]! ^= 1; const answers: (() => Promise)[] = [ async () => new Response('missing', { status: 404 }), async () => new Response(changed), async () => { throw new TypeError('Failed to fetch'); }, async () => new Response(list.slice()), ]; let calls = 0; const fetcher: Fetcher = () => answers[calls++]!(); const load = wordListLoader(fetcher); await expect(load()).rejects.toThrow(/^the site answered 404 for the word list$/); await expect(load()).rejects.toThrow(/^wordkey: the list "es" has the SHA-256 [0-9a-f]{64}, not ff77b487/); await expect(load()).rejects.toThrow('Failed to fetch'); expect(await load()).toHaveLength(7776); expect(calls).toBe(4); }); it('fetches with the fetch of the page by default', async () => { const real = globalThis.fetch; globalThis.fetch = async () => new Response(list.slice()); try { expect(await wordListLoader()()).toHaveLength(7776); } finally { globalThis.fetch = real; } }); });