Files
dbx/tests/dataGridEditor.test.ts
T

273 lines
7.6 KiB
TypeScript

import { strict as assert } from "node:assert";
import test from "node:test";
import { computed, nextTick, ref } from "vue";
import { createPinia, setActivePinia } from "pinia";
import { useDataGridEditor } from "../src/composables/useDataGridEditor.ts";
import type { ColumnInfo } from "../src/types/database.ts";
type CellValue = string | number | boolean | null;
function installBrowserTestGlobals() {
globalThis.document = { querySelector: () => null } as unknown as Document;
globalThis.localStorage = {
getItem: () => null,
setItem: () => {},
removeItem: () => {},
clear: () => {},
key: () => null,
length: 0,
};
}
function column(name: string, isPrimaryKey = false, extra: string | null = null): ColumnInfo {
return {
name,
data_type: "VARCHAR",
is_nullable: true,
column_default: null,
is_primary_key: isPrimaryKey,
extra,
};
}
test("cloning a row copies non-generated primary key values without executing save", async () => {
setActivePinia(createPinia());
installBrowserTestGlobals();
const result = computed(() => ({
columns: ["code", "year", "score"],
rows: [["AFW", 1995, 35271.907090628745] as CellValue[]],
}));
const rowStatusFilter = ref<"all" | "changed" | "edited" | "new" | "deleted">("all");
let saveCalls = 0;
let editor: ReturnType<typeof useDataGridEditor>;
editor = useDataGridEditor({
result,
editable: computed(() => true),
databaseType: computed(() => "postgres"),
connectionId: computed(() => undefined),
database: computed(() => undefined),
tableMeta: computed(() => ({
tableName: "metrics",
columns: [column("code", true), column("year", true), column("score")],
primaryKeys: ["code", "year"],
})),
onExecuteSql: computed(() => undefined),
customSave: computed(() => async () => {
saveCalls += 1;
}),
sql: computed(() => undefined),
searchText: ref(""),
whereFilterInput: ref(""),
orderByInput: ref(""),
rowStatusFilter,
pageSize: ref(100),
currentPage: ref(1),
getRowItem: (rowId) => {
if (rowId === 0) {
return {
id: 0,
sourceIndex: 0,
data: result.value.rows[0],
isNew: false,
isDeleted: false,
isDirtyCol: [false, false, false],
status: "clean",
};
}
if (rowId < 0) {
const newIndex = -rowId - 1;
const row = editor.newRows.value[newIndex];
if (!row) return undefined;
return {
id: rowId,
newIndex,
data: row,
isNew: true,
isDeleted: false,
isDirtyCol: [false, false, false],
status: "new",
};
}
return undefined;
},
emit: () => {},
});
editor.cloneRow(0);
await nextTick();
assert.equal(saveCalls, 0);
assert.deepEqual(editor.newRows.value, [["AFW", 1995, 35271.907090628745]]);
assert.equal(editor.transactionActive.value, true);
assert.deepEqual(editor.editingCell.value, { rowId: -1, col: 0 });
await editor.saveChanges();
assert.equal(saveCalls, 1);
assert.deepEqual(editor.newRows.value, []);
});
test("cloning a row clears auto-generated key columns", async () => {
setActivePinia(createPinia());
installBrowserTestGlobals();
const result = computed(() => ({
columns: ["id", "name"],
rows: [[1, "Ada"] as CellValue[]],
}));
const rowStatusFilter = ref<"all" | "changed" | "edited" | "new" | "deleted">("all");
let editor: ReturnType<typeof useDataGridEditor>;
editor = useDataGridEditor({
result,
editable: computed(() => true),
databaseType: computed(() => "mysql"),
connectionId: computed(() => undefined),
database: computed(() => undefined),
tableMeta: computed(() => ({
tableName: "people",
columns: [column("id", true, "auto_increment"), column("name")],
primaryKeys: ["id"],
})),
onExecuteSql: computed(() => undefined),
customSave: computed(() => undefined),
sql: computed(() => undefined),
searchText: ref(""),
whereFilterInput: ref(""),
orderByInput: ref(""),
rowStatusFilter,
pageSize: ref(100),
currentPage: ref(1),
getRowItem: (rowId) => {
if (rowId !== 0) return undefined;
return {
id: 0,
sourceIndex: 0,
data: result.value.rows[0],
isNew: false,
isDeleted: false,
isDirtyCol: [false, false],
status: "clean",
};
},
emit: () => {},
});
editor.cloneRow(0);
await nextTick();
assert.deepEqual(editor.newRows.value, [[null, "Ada"]]);
});
test("saving deleted rows reloads current table data", async () => {
setActivePinia(createPinia());
installBrowserTestGlobals();
const result = computed(() => ({
columns: ["id", "name"],
rows: [[1, "Ada"] as CellValue[]],
}));
const rowStatusFilter = ref<"all" | "changed" | "edited" | "new" | "deleted">("all");
const emitted: unknown[][] = [];
let editor: ReturnType<typeof useDataGridEditor>;
editor = useDataGridEditor({
result,
editable: computed(() => true),
databaseType: computed(() => "postgres"),
connectionId: computed(() => "conn-1"),
database: computed(() => "main"),
tableMeta: computed(() => ({
tableName: "people",
columns: [column("id", true), column("name")],
primaryKeys: ["id"],
})),
onExecuteSql: computed(() => undefined),
customSave: computed(() => async () => {}),
sql: computed(() => "SELECT id, name FROM people"),
searchText: ref("ada"),
whereFilterInput: ref("name ILIKE '%a%'"),
orderByInput: ref("id DESC"),
rowStatusFilter,
pageSize: ref(50),
currentPage: ref(3),
getRowItem: (rowId) => {
if (rowId !== 0) return undefined;
return {
id: 0,
sourceIndex: 0,
data: result.value.rows[0],
isNew: false,
isDeleted: false,
isDirtyCol: [false, false],
status: "clean",
};
},
emit: (...args) => {
emitted.push(args);
},
});
editor.applyDeleteRow(0);
await editor.saveChanges();
assert.deepEqual(emitted, [["reload", "SELECT id, name FROM people", "ada", "name ILIKE '%a%'", "id DESC", 50, 100]]);
});
test("saving edited rows without deletes does not reload table data", async () => {
setActivePinia(createPinia());
installBrowserTestGlobals();
const result = computed(() => ({
columns: ["id", "name"],
rows: [[1, "Ada"] as CellValue[]],
}));
const rowStatusFilter = ref<"all" | "changed" | "edited" | "new" | "deleted">("all");
const emitted: unknown[][] = [];
let editor: ReturnType<typeof useDataGridEditor>;
editor = useDataGridEditor({
result,
editable: computed(() => true),
databaseType: computed(() => "postgres"),
connectionId: computed(() => "conn-1"),
database: computed(() => "main"),
tableMeta: computed(() => ({
tableName: "people",
columns: [column("id", true), column("name")],
primaryKeys: ["id"],
})),
onExecuteSql: computed(() => undefined),
customSave: computed(() => async () => {}),
sql: computed(() => "SELECT id, name FROM people"),
searchText: ref(""),
whereFilterInput: ref(""),
orderByInput: ref(""),
rowStatusFilter,
pageSize: ref(50),
currentPage: ref(1),
getRowItem: (rowId) => {
if (rowId !== 0) return undefined;
return {
id: 0,
sourceIndex: 0,
data: result.value.rows[0],
isNew: false,
isDeleted: false,
isDirtyCol: [false, false],
status: "clean",
};
},
emit: (...args) => {
emitted.push(args);
},
});
editor.applyCellValue(0, 1, "Ada Lovelace");
await editor.saveChanges();
assert.deepEqual(emitted, []);
});