import type { ClientPrefix } from "@/lib/types"; import { firstProblem, initPrefixEditor, isDirty, prefixEditorReducer, toInputs, type PrefixEditorState, } from "./prefixEditor"; const server: ClientPrefix[] = [ { id: 1, prefix: "192.168.1.0/24", group_id: 1, group: "default", priority: 100 }, { id: 2, prefix: "10.0.0.0/8", group_id: 2, group: "kids", priority: 50 }, ]; test("init mirrors the server rows into baseline and rows", () => { const state = initPrefixEditor(server); expect(state.rows).toEqual([ { prefix: "192.168.1.0/24", group_id: 1, priority: "100" }, { prefix: "10.0.0.0/8", group_id: 2, priority: "50" }, ]); expect(state.baseline).toEqual(state.rows); expect(isDirty(state)).toBe(false); }); test("add appends an empty row with the given group and marks dirty", () => { const state = prefixEditorReducer(initPrefixEditor(server), { type: "add", groupId: 1 }); expect(state.rows).toHaveLength(3); expect(state.rows[2]).toEqual({ prefix: "", group_id: 1, priority: "" }); expect(isDirty(state)).toBe(true); }); test("remove drops the row at the index", () => { const state = prefixEditorReducer(initPrefixEditor(server), { type: "remove", index: 0 }); expect(state.rows).toEqual([{ prefix: "10.0.0.0/8", group_id: 2, priority: "50" }]); expect(isDirty(state)).toBe(true); }); test("edit patches a single row", () => { const state = prefixEditorReducer(initPrefixEditor(server), { type: "edit", index: 1, patch: { group_id: 1, priority: "10" }, }); expect(state.rows[1]).toEqual({ prefix: "10.0.0.0/8", group_id: 1, priority: "10" }); expect(state.rows[0]).toEqual(state.baseline[0]); expect(isDirty(state)).toBe(true); }); test("editing a field back to its baseline value is clean again", () => { let state: PrefixEditorState = initPrefixEditor(server); state = prefixEditorReducer(state, { type: "edit", index: 0, patch: { priority: "7" } }); expect(isDirty(state)).toBe(true); state = prefixEditorReducer(state, { type: "edit", index: 0, patch: { priority: "100" } }); expect(isDirty(state)).toBe(false); }); test("reset adopts new server rows and clears dirtiness", () => { let state = prefixEditorReducer(initPrefixEditor(server), { type: "add", groupId: 1 }); state = prefixEditorReducer(state, { type: "reset", prefixes: server }); expect(isDirty(state)).toBe(false); expect(state.rows).toHaveLength(2); }); test("toInputs trims prefixes, parses priorities and omits empty ones", () => { expect( toInputs([ { prefix: " 192.168.1.0/24 ", group_id: 1, priority: "25" }, { prefix: "10.0.0.0/8", group_id: 2, priority: "" }, ]), ).toEqual([ { prefix: "192.168.1.0/24", group_id: 1, priority: 25 }, { prefix: "10.0.0.0/8", group_id: 2 }, ]); }); test("firstProblem flags empty prefixes and non-integer priorities", () => { expect(firstProblem([{ prefix: "10.0.0.0/8", group_id: 1, priority: "" }])).toBeNull(); expect(firstProblem([{ prefix: " ", group_id: 1, priority: "" }])).toEqual({ index: 0, field: "prefix", message: "Row 1: prefix is required.", }); expect( firstProblem([ { prefix: "10.0.0.0/8", group_id: 1, priority: "100" }, { prefix: "10.1.0.0/16", group_id: 1, priority: "abc" }, ]), ).toEqual({ index: 1, field: "priority", message: "Row 2: priority must be a whole number." }); });