diff --git a/tests/api/icon_sets.test.js b/tests/api/icon_sets.test.js new file mode 100644 index 0000000..a379fbc --- /dev/null +++ b/tests/api/icon_sets.test.js @@ -0,0 +1,72 @@ +// tests/api/icon_sets.test.js +import { describe, it, expect, beforeAll, beforeEach } from 'vitest'; +import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import request from 'supertest'; +import { createApp } from '../../server.js'; +import * as sets from '../../lib/icons/sets.js'; + +const PNG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 0]); + +let app; +let setsDir; +let bundledDir; + +beforeAll(() => { + process.env.OWNER_TOKEN = 'test-token'; + app = createApp(); +}); + +beforeEach(() => { + // Set up fresh temp dirs with a fake bundled device icon so the bundled set is non-empty. + setsDir = mkdtempSync(path.join(tmpdir(), 'iconsets-')); + bundledDir = path.join(setsDir, '__bundled'); + mkdirSync(bundledDir, { recursive: true }); + writeFileSync(path.join(bundledDir, 'router.svg'), ''); + sets._setDirs({ setsDir, bundledDir }); +}); + +const owner = r => r.set('Authorization', 'Bearer test-token'); + +describe('GET /api/icon-sets', () => { + it('returns 200 with an array including the bundled devices set', async () => { + const res = await request(app).get('/api/icon-sets'); + expect(res.status).toBe(200); + expect(Array.isArray(res.body)).toBe(true); + const dev = res.body.find(s => s.set === 'devices'); + expect(dev).toBeDefined(); + expect(dev.readonly).toBe(true); + }); +}); + +describe('POST /api/icon-sets/:set', () => { + it('returns 401 (not 500) without auth', async () => { + const res = await request(app) + .post('/api/icon-sets/mytest') + .attach('files', PNG, { filename: 'router.png', contentType: 'image/png' }); + expect(res.status).toBe(401); + }); + + it('returns 200 and uploads the icon with owner auth', async () => { + const res = await owner( + request(app).post('/api/icon-sets/mytest') + ).attach('files', PNG, { filename: 'router.png', contentType: 'image/png' }); + expect(res.status).toBe(200); + expect(res.body.set).toBe('mytest'); + expect(res.body.icons).toContain('router.png'); + }); +}); + +describe('GET /api/icon-sets/:set/:file', () => { + it('serves a previously uploaded icon with image/png content-type', async () => { + // Upload first + await owner( + request(app).post('/api/icon-sets/mytest') + ).attach('files', PNG, { filename: 'router.png', contentType: 'image/png' }); + + const res = await request(app).get('/api/icon-sets/mytest/router.png'); + expect(res.status).toBe(200); + expect(res.headers['content-type']).toContain('image/png'); + }); +});