// What the import form reads out of a CSV file: rows as the service takes them, each with the line it came // from, chunks the service accepts, and a file it cannot read named as such. import { describe, expect, it } from "vitest" import { chunksOf, csvRows, parseProductCsv } from "../ui/import-rows.js" describe("a product CSV", () => { it("reads the required columns by name, in any order, with the line number a person sees", () => { const text = "name,base_unit,code,description\nBolt M8,C62,BOLT-M8,\n\nNut M8,C62,NUT-M8,A nut\n" expect(parseProductCsv(text)).toEqual({ kind: "rows", rows: [ { sourceRow: 2, product: { code: "BOLT-M8", name: "Bolt M8", baseUnit: "C62" } }, { sourceRow: 4, product: { code: "NUT-M8", name: "Nut M8", baseUnit: "C62", description: "A nut" } }, ], }) }) it("keeps a quoted comma, a doubled quote and a CRLF ending", () => { expect(csvRows('a,"b,c","d""e"\r\nf,,g\r\n')).toEqual([ ["a", "b,c", 'd"e'], ["f", "", "g"], ]) }) it("carries a row's revision when the file has one", () => { expect(parseProductCsv("code,name,base_unit,revision\nBOLT-M8,Bolt M8,C62,4\n")).toEqual({ kind: "rows", rows: [{ sourceRow: 2, revision: "4", product: { code: "BOLT-M8", name: "Bolt M8", baseUnit: "C62" } }], }) }) it("names what is wrong with a file it cannot read, and reads an empty one as nothing", () => { expect(parseProductCsv("code,name\nBOLT-M8,Bolt M8\n")).toEqual({ kind: "unreadable", missing: ["base_unit"] }) expect(parseProductCsv("")).toEqual({ kind: "unreadable", missing: ["code", "name", "base_unit"] }) expect(parseProductCsv("code,name,base_unit\n")).toEqual({ kind: "rows", rows: [] }) }) it("splits rows into chunks of the service's size", () => { const rows = Array.from({ length: 401 }, (_, at) => at) expect(chunksOf(rows).map((chunk) => chunk.length)).toEqual([200, 200, 1]) expect(chunksOf([])).toEqual([]) }) })