79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
|
|
import { describe, it, expect } from 'vitest'
|
||
|
|
import { mkdtempSync, rmSync, existsSync, readFileSync } from 'node:fs'
|
||
|
|
import { tmpdir } from 'node:os'
|
||
|
|
import path from 'node:path'
|
||
|
|
import { cacheArtwork } from '../src/artwork.js'
|
||
|
|
|
||
|
|
function tempDir(): string {
|
||
|
|
return mkdtempSync(path.join(tmpdir(), 'rs-artwork-'))
|
||
|
|
}
|
||
|
|
|
||
|
|
function imageFetch(calls: { count: number }): typeof fetch {
|
||
|
|
return (async () => {
|
||
|
|
calls.count++
|
||
|
|
return new Response(new Uint8Array([0xff, 0xd8, 0xff, 0xe0]), {
|
||
|
|
status: 200,
|
||
|
|
headers: { 'content-type': 'image/jpeg' },
|
||
|
|
})
|
||
|
|
}) as typeof fetch
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('cacheArtwork', () => {
|
||
|
|
it('downloads and stores by url hash with content-type extension', async () => {
|
||
|
|
const dir = tempDir()
|
||
|
|
try {
|
||
|
|
const calls = { count: 0 }
|
||
|
|
const file = await cacheArtwork(dir, 'https://img.discogs.com/a.jpg', imageFetch(calls))
|
||
|
|
expect(file).toMatch(/^[0-9a-f]{64}\.jpg$/)
|
||
|
|
expect(existsSync(path.join(dir, file as string))).toBe(true)
|
||
|
|
} finally {
|
||
|
|
rmSync(dir, { recursive: true, force: true })
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
it('second call for same url does not refetch', async () => {
|
||
|
|
const dir = tempDir()
|
||
|
|
try {
|
||
|
|
const calls = { count: 0 }
|
||
|
|
const fetcher = imageFetch(calls)
|
||
|
|
await cacheArtwork(dir, 'https://img.discogs.com/a.jpg', fetcher)
|
||
|
|
const again = await cacheArtwork(dir, 'https://img.discogs.com/a.jpg', fetcher)
|
||
|
|
expect(calls.count).toBe(1)
|
||
|
|
expect(again).not.toBeNull()
|
||
|
|
} finally {
|
||
|
|
rmSync(dir, { recursive: true, force: true })
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
it('returns null for empty url and fetch failures without throwing', async () => {
|
||
|
|
const dir = tempDir()
|
||
|
|
try {
|
||
|
|
expect(await cacheArtwork(dir, '', imageFetch({ count: 0 }))).toBeNull()
|
||
|
|
const failing = (async () => {
|
||
|
|
throw new TypeError('fetch failed')
|
||
|
|
}) as unknown as typeof fetch
|
||
|
|
expect(await cacheArtwork(dir, 'https://x/y.jpg', failing)).toBeNull()
|
||
|
|
const notFound = (async () => new Response('nope', { status: 404 })) as unknown as typeof fetch
|
||
|
|
expect(await cacheArtwork(dir, 'https://x/y.jpg', notFound)).toBeNull()
|
||
|
|
} finally {
|
||
|
|
rmSync(dir, { recursive: true, force: true })
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
it('stores non-jpeg types with correct extension', async () => {
|
||
|
|
const dir = tempDir()
|
||
|
|
try {
|
||
|
|
const fetcher = (async () =>
|
||
|
|
new Response(new Uint8Array([0x89, 0x50]), {
|
||
|
|
status: 200,
|
||
|
|
headers: { 'content-type': 'image/png' },
|
||
|
|
})) as typeof fetch
|
||
|
|
const file = await cacheArtwork(dir, 'https://img.discogs.com/a.png', fetcher)
|
||
|
|
expect(file).toMatch(/\.png$/)
|
||
|
|
expect(readFileSync(path.join(dir, file as string)).length).toBeGreaterThan(0)
|
||
|
|
} finally {
|
||
|
|
rmSync(dir, { recursive: true, force: true })
|
||
|
|
}
|
||
|
|
})
|
||
|
|
})
|