import { strict as assert } from 'node:assert'; import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { after, before, describe, it } from 'node:test'; import { startStaticServer, type StaticServer } from './static-server.ts'; describe('static-server', () => { let dir: string = ''; let server: StaticServer | undefined; const baseUrl = (): string => { if (!server) throw new Error('static server not started'); return server.url; }; before(async () => { dir = await mkdtemp(join(tmpdir(), 'penpot-static-server-')); await mkdir(join(dir, 'js'), { recursive: true }); await writeFile(join(dir, 'index.html'), ''); await writeFile(join(dir, 'js', 'app.js'), 'console.log("hi");'); await writeFile(join(dir, 'data.bin'), Buffer.from([0, 1, 2])); server = await startStaticServer(dir, 0); }); after(async () => { await server?.close(); // Closing twice must be safe (the driver closes unconditionally). await server?.close(); await rm(dir, { recursive: true, force: true }); }); it('serves / as index.html', async () => { const res = await fetch(`${baseUrl()}/`); assert.equal(res.status, 200); assert.match(res.headers.get('content-type') ?? '', /text\/html/); assert.match(await res.text(), //); }); it('serves nested files with a javascript content type', async () => { const res = await fetch(`${baseUrl()}/js/app.js`); assert.equal(res.status, 200); assert.match(res.headers.get('content-type') ?? '', /javascript/); assert.equal(await res.text(), 'console.log("hi");'); }); it('ignores query strings', async () => { const res = await fetch(`${baseUrl()}/index.html?rev=123`); assert.equal(res.status, 200); assert.match(await res.text(), //); }); it('falls back to octet-stream for unknown extensions', async () => { const res = await fetch(`${baseUrl()}/data.bin`); assert.equal(res.status, 200); assert.equal(res.headers.get('content-type'), 'application/octet-stream'); }); it('answers HEAD without a body', async () => { const res = await fetch(`${baseUrl()}/index.html`, { method: 'HEAD' }); assert.equal(res.status, 200); assert.match(res.headers.get('content-type') ?? '', /text\/html/); assert.equal(await res.text(), ''); }); it('rejects other methods', async () => { const res = await fetch(`${baseUrl()}/index.html`, { method: 'POST' }); assert.equal(res.status, 405); }); it('returns 404 for missing files', async () => { const res = await fetch(`${baseUrl()}/nope/missing.js`); assert.equal(res.status, 404); }); it('blocks path traversal outside the root', async () => { const res = await fetch(`${baseUrl()}/..%2f..%2fsecret`); assert.equal(res.status, 403); }); });