Files
gridline/desktop/src/lib/exportData.test.ts
T
adrianbonpin 5607773299
Release / windows (push) Successful in 17m5s
Release / linux (push) Successful in 24m10s
0.8.0: MariaDB + PlanetScale, TimescaleDB, multi-result sets, streaming export, schema diff (#27)
2026-09-11 17:20:41 +00:00

73 lines
3.4 KiB
TypeScript

import { describe, it, expect, vi } from "vitest";
import { exportData, csvCell, qualifiedTableSql } from "./exportData";
import type { ColumnInfo } from "./types";
const columns: ColumnInfo[] = [
{ name: "id", data_type: "int", is_nullable: false, is_pk: true, is_fk: false, fk_ref: null, default_value: null, editable: true, is_generated: false },
{ name: "v", data_type: "text", is_nullable: true, is_pk: false, is_fk: false, fk_ref: null, default_value: null, editable: true, is_generated: false },
];
describe("exportData", () => {
it("csv quotes cells and escapes quotes", () => {
const create = vi.spyOn(document, "createElement");
vi.spyOn(URL, "createObjectURL").mockReturnValue("blob:x");
vi.spyOn(URL, "revokeObjectURL").mockImplementation(() => {});
const click = vi.fn();
create.mockReturnValue({ click } as unknown as HTMLAnchorElement);
exportData([[1, "a"], [2, 'b"c']], columns, "csv", "t");
expect(click).toHaveBeenCalled();
});
it("json serializes rows as objects", () => {
vi.spyOn(URL, "createObjectURL").mockReturnValue("blob:x");
vi.spyOn(URL, "revokeObjectURL").mockImplementation(() => {});
const click = vi.fn();
vi.spyOn(document, "createElement").mockReturnValue({ click } as unknown as HTMLAnchorElement);
exportData([[1, "a"]], columns, "json", "t");
expect(click).toHaveBeenCalled();
});
it("xlsx produces a Blob with the xlsx MIME and extension download", () => {
const origCreateObjectURL = URL.createObjectURL;
const origRevokeObjectURL = URL.revokeObjectURL;
globalThis.URL.createObjectURL = vi.fn(() => "blob:x") as any;
globalThis.URL.revokeObjectURL = vi.fn() as any;
const a = { click: vi.fn(), href: "", download: "" };
vi.spyOn(document, "createElement").mockReturnValue(a as any);
const rows = [[1]];
const cols: ColumnInfo[] = [
{ name: "id", data_type: "integer", is_nullable: true, is_pk: false, is_fk: false, fk_ref: null, default_value: null, editable: true, is_generated: false },
];
try {
exportData(rows, cols, "xlsx", "t");
expect(a.download).toBe("t.xlsx");
expect((URL.createObjectURL as any).mock.calls[0][0] instanceof Blob).toBe(true);
expect((URL.createObjectURL as any).mock.calls[0][0].type).toBe("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
} finally {
globalThis.URL.createObjectURL = origCreateObjectURL;
globalThis.URL.revokeObjectURL = origRevokeObjectURL;
}
});
});
describe("csvCell (client CSV parity with streamed export)", () => {
it("quotes and guards like the Rust writer", () => {
expect(csvCell("plain")).toBe("plain");
expect(csvCell("a,b")).toBe('"a,b"');
expect(csvCell('a"b')).toBe('"a""b"');
expect(csvCell("=SUM(A1)")).toBe("'=SUM(A1)");
expect(csvCell("+x")).toBe("'+x");
expect(csvCell("-1")).toBe("'-1");
expect(csvCell("@cmd")).toBe("'@cmd");
expect(csvCell(null)).toBe("");
});
});
describe("qualifiedTableSql", () => {
it("double-quotes for PG/SQLite and backticks for MySQL/MariaDB", () => {
expect(qualifiedTableSql("postgresql", "public", "users")).toBe('SELECT * FROM "public"."users"');
expect(qualifiedTableSql("sqlite", "main", "users")).toBe('SELECT * FROM "main"."users"');
expect(qualifiedTableSql("mysql", "app", "users")).toBe("SELECT * FROM `app`.`users`");
expect(qualifiedTableSql("mariadb", "app", "users")).toBe("SELECT * FROM `app`.`users`");
});
});