Replace the free-text Project Code input with a native <select> carrying a fixed list of project codes (Petronet LNG Cochin, COMACOE Trombay, Haldia Reach, Haldia MMT, COMACOE Mandvi) plus an empty "— none —" option, across all three PO forms (new / edit / manager-edit). - Add a shared PROJECT_CODES constant in lib/validations/po.ts as the single source of truth. - Add a reusable <ProjectCodeField> (mirrors <DeliveryLocationField>): plain HTML select keeping name="projectCode" so the server actions are unchanged. - The field stays optional; projectCode remains a nullable free-text snapshot (no schema/migration, no validation tightening) so legacy/imported values are not rejected. On edit, a current value not in the list is preserved as a leading "(current)" option so it is never silently dropped. - Add unit tests for the new field. Fixes #124 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
2.1 KiB
TypeScript
47 lines
2.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
import { ProjectCodeField } from "@/components/po/project-code-field";
|
|
import { PROJECT_CODES } from "@/lib/validations/po";
|
|
|
|
function options(container: HTMLElement) {
|
|
return Array.from(container.querySelectorAll("option")).map((o) => ({
|
|
value: o.getAttribute("value"),
|
|
text: o.textContent,
|
|
}));
|
|
}
|
|
|
|
describe("ProjectCodeField", () => {
|
|
it("renders a select named projectCode with an empty option + every fixed code", () => {
|
|
const { container } = render(<ProjectCodeField />);
|
|
const select = container.querySelector("select");
|
|
expect(select?.getAttribute("name")).toBe("projectCode");
|
|
|
|
const opts = options(container);
|
|
// empty "none" option first, then exactly the fixed codes
|
|
expect(opts[0].value).toBe("");
|
|
expect(opts.slice(1).map((o) => o.value)).toEqual([...PROJECT_CODES]);
|
|
});
|
|
|
|
it("selects a current value that is one of the fixed codes (no duplicate option)", () => {
|
|
const { container } = render(<ProjectCodeField current="Haldia Reach" />);
|
|
const select = container.querySelector("select") as HTMLSelectElement;
|
|
expect(select.value).toBe("Haldia Reach");
|
|
// only the fixed codes + empty option — no extra "(current)" entry
|
|
expect(container.querySelectorAll("option")).toHaveLength(PROJECT_CODES.length + 1);
|
|
});
|
|
|
|
it("preserves a legacy current value not in the list as a leading (current) option", () => {
|
|
const { container } = render(<ProjectCodeField current="Legacy Project X" />);
|
|
const select = container.querySelector("select") as HTMLSelectElement;
|
|
expect(select.value).toBe("Legacy Project X");
|
|
expect(screen.getByText("Legacy Project X (current)")).toBeInTheDocument();
|
|
// empty + (current) + fixed codes
|
|
expect(container.querySelectorAll("option")).toHaveLength(PROJECT_CODES.length + 2);
|
|
});
|
|
|
|
it("defaults to the empty option when no current value is given", () => {
|
|
const { container } = render(<ProjectCodeField current={null} />);
|
|
const select = container.querySelector("select") as HTMLSelectElement;
|
|
expect(select.value).toBe("");
|
|
});
|
|
});
|