import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { initDb, closeDb } from '../src/db/index'; import { buildDisplayJson } from '../src/modules/display/display-builder'; beforeAll(() => { const db = initDb(':memory:'); // Create a layout db.run( `INSERT INTO layouts (id, name, type, width, height, grid_cols, grid_rows) VALUES (1, 'Test Layout', 'grid', 800, 480, 2, 3)` ); // Create a display with the layout db.run( `INSERT INTO displays (id, name, layout_id, refresh_sec) VALUES (1, 'Test Display', 1, 60)` ); // Create a display without layout db.run( `INSERT INTO displays (id, name, layout_id, refresh_sec) VALUES (2, 'Empty Display', NULL, 300)` ); // Create a broker and topic for datapoint db.run( `INSERT INTO mqtt_brokers (id, name, host) VALUES (1, 'Test Broker', 'localhost')` ); db.run( `INSERT INTO mqtt_topics (id, broker_id, topic) VALUES (1, 1, 'sensors/temp')` ); // Create a datapoint db.run( `INSERT INTO datapoints (id, name, label, unit, value, source_type, source_id, topic_id, enabled) VALUES (1, 'temperature', 'Temperature', '°C', '22.5', 'mqtt', 1, 1, 1)` ); // Create layout elements // Label element db.run( `INSERT INTO layout_elements (id, layout_id, type, x, y, static_text, sort_order) VALUES (1, 1, 'label', 0, 0, 'Hello World', 0)` ); // Value element linked to datapoint db.run( `INSERT INTO layout_elements (id, layout_id, datapoint_id, type, x, y, font_size, sort_order) VALUES (2, 1, 1, 'value', 100, 0, 32, 1)` ); }); afterAll(() => { closeDb(); }); describe('buildDisplayJson', () => { it('returns null for non-existent display', () => { const result = buildDisplayJson(999); expect(result).toBeNull(); }); it('returns complete JSON for a display with layout', () => { const result = buildDisplayJson(1); expect(result).not.toBeNull(); expect(result!.display.id).toBe(1); expect(result!.display.name).toBe('Test Display'); expect(result!.display.width).toBe(800); expect(result!.display.height).toBe(480); expect(result!.display.refresh_sec).toBe(60); }); it('includes grid layout info when grid_cols and grid_rows are set', () => { const result = buildDisplayJson(1); expect(result!.layout.type).toBe('grid'); expect(result!.layout.grid_cols).toBe(2); expect(result!.layout.grid_rows).toBe(3); }); it('includes label element with text', () => { const result = buildDisplayJson(1); const labelEl = result!.elements.find((e) => e.type === 'label'); expect(labelEl).toBeDefined(); expect(labelEl!.text).toBe('Hello World'); }); it('includes value element with datapoint data', () => { const result = buildDisplayJson(1); const valueEl = result!.elements.find((e) => e.type === 'value'); expect(valueEl).toBeDefined(); expect(valueEl!.label).toBe('Temperature'); expect(valueEl!.value).toBe('22.5'); expect(valueEl!.unit).toBe('°C'); }); it('includes non-default font_size in value element', () => { const result = buildDisplayJson(1); const valueEl = result!.elements.find((e) => e.type === 'value'); expect(valueEl!.font_size).toBe(32); }); it('does not include default font_size in label element', () => { const result = buildDisplayJson(1); const labelEl = result!.elements.find((e) => e.type === 'label'); // font_size 24 is default, should not be included expect(labelEl!.font_size).toBeUndefined(); }); it('returns empty elements and default dimensions for display without layout', () => { const result = buildDisplayJson(2); expect(result).not.toBeNull(); expect(result!.elements).toHaveLength(0); expect(result!.display.width).toBe(800); expect(result!.display.height).toBe(480); }); });