diff --git a/extralit-frontend/components/base/base-render-table/RenderTable.vue b/extralit-frontend/components/base/base-render-table/RenderTable.vue index fbfaf645b..ff6874489 100644 --- a/extralit-frontend/components/base/base-render-table/RenderTable.vue +++ b/extralit-frontend/components/base/base-render-table/RenderTable.vue @@ -335,9 +335,11 @@ export default { this.tableJSON.data.forEach((row) => { removeColumns.forEach((field) => { this.$delete(row, field); + }); }); } + } if (add) { @@ -458,7 +460,6 @@ export default { if (options?.saveData == true) { this.updateTableJsonData(); } - return isValid; }, toggleShowRefColumns() { @@ -836,6 +837,7 @@ export default { button.addEventListener('click', this.addEmptyReferenceRows); div.appendChild(button); } + return div; }, @@ -942,6 +944,7 @@ export default { this.isLoaded = true; this.tabulator?.setColumns(this.columnsConfig); this.validateTable(); + this.$emit("table-built"); }); } catch (error) { diff --git a/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.test.ts b/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.test.ts index 42ac85af3..30d5b5229 100644 --- a/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.test.ts +++ b/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.test.ts @@ -1,37 +1,14 @@ -import { mount } from "@vue/test-utils"; +import { shallowMount } from "@vue/test-utils"; import BaseSimpleTable from "./BaseSimpleTable.vue"; -// Mock Tabulator -jest.mock("tabulator-tables", () => ({ - TabulatorFull: jest.fn().mockImplementation(() => ({ - destroy: jest.fn(), - setData: jest.fn(), - setColumns: jest.fn(), - getData: jest.fn(() => []), - getSelectedData: jest.fn(() => []), - getSelectedRows: jest.fn(() => []), - selectRow: jest.fn(), - deselectRow: jest.fn(), - addRow: jest.fn(() => Promise.resolve({})), - updateRow: jest.fn(() => true), - deleteRow: jest.fn(), - clearData: jest.fn(), - setFilter: jest.fn(), - clearFilter: jest.fn(), - setSort: jest.fn(), - clearSort: jest.fn(), - redraw: jest.fn(), - scrollToRow: jest.fn(() => Promise.resolve()), - scrollToColumn: jest.fn(() => Promise.resolve()), - download: jest.fn(), - getDataCount: jest.fn(() => 0), - getColumns: jest.fn(() => []), - hideColumn: jest.fn(), - showColumn: jest.fn(), - toggleColumn: jest.fn(), - blockRedraw: jest.fn(), - restoreRedraw: jest.fn(), - })), +// Mock RenderTable component +jest.mock("~/components/base/base-render-table/RenderTable.vue", () => ({ + name: "RenderTable", + template: '
', + props: ["tableJSON", "editable", "hasValidValues", "questions"], + methods: { + validateTable: jest.fn(() => true), + }, })); describe("BaseSimpleTable", () => { @@ -39,19 +16,14 @@ describe("BaseSimpleTable", () => { { field: "name", title: "Name", - sortable: true, - filterable: true, }, { field: "age", title: "Age", - sortable: true, - width: 100, }, { field: "email", title: "Email", - filterable: true, }, ]; @@ -60,147 +32,215 @@ describe("BaseSimpleTable", () => { { name: "Jane Smith", age: 25, email: "jane@example.com" }, ]; - it("renders without crashing", () => { - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - }, + describe("rendering", () => { + it("renders without crashing", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); + + expect(wrapper.exists()).toBe(true); + expect(wrapper.find(".tabulator-container--simple").exists()).toBe(true); }); - expect(wrapper.exists()).toBe(true); - expect(wrapper.find(".tabulator-container").exists()).toBe(true); + it("renders RenderTable component", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); + + expect(wrapper.findComponent({ name: "RenderTable" }).exists()).toBe(true); + }); }); - it("accepts columns and data props", () => { - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - }, + describe("props", () => { + it("accepts columns and data props", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); + + expect(wrapper.props("columns")).toEqual(mockColumns); + expect(wrapper.props("data")).toEqual(mockData); }); - expect(wrapper.props("columns")).toEqual(mockColumns); - expect(wrapper.props("data")).toEqual(mockData); - }); + it("accepts editable prop with default false", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); - it("accepts options prop", () => { - const options = { - height: 400, - pagination: true, - paginationSize: 10, - }; - - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - options, - }, + expect(wrapper.props("editable")).toBe(false); }); - expect(wrapper.props("options")).toEqual(options); - }); + it("accepts editable prop set to true", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + editable: true, + }, + }); - it("accepts loading prop", () => { - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - loading: true, - }, + expect(wrapper.props("editable")).toBe(true); }); - expect(wrapper.props("loading")).toBe(true); - }); + it("accepts validation prop", () => { + const validation = { columns: {}, index: [], checks: {} }; + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + validation, + }, + }); + + expect(wrapper.props("validation")).toEqual(validation); + }); - it("processes columns correctly", () => { - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - }, + it("accepts validators prop", () => { + const validators = { name: ["required", "unique"] }; + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + validators, + }, + }); + + expect(wrapper.props("validators")).toEqual(validators); }); - const processedColumns = (wrapper.vm as any).processedColumns; + it("accepts hasValidValues prop", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + hasValidValues: true, + }, + }); - expect(processedColumns).toHaveLength(3); - expect(processedColumns[0]).toMatchObject({ - field: "name", - title: "Name", - headerSort: true, - headerFilter: "input", + expect(wrapper.props("hasValidValues")).toBe(true); }); - expect(processedColumns[1]).toMatchObject({ - field: "age", - title: "Age", - width: 100, - headerSort: true, + + it("accepts questions prop", () => { + const questions = [{ id: "q1", name: "Question 1" }]; + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + questions, + }, + }); + + expect(wrapper.props("questions")).toEqual(questions); }); - expect(processedColumns[2]).toMatchObject({ - field: "email", - title: "Email", - headerFilter: "input", + }); + + describe("computedTableJSON", () => { + it("converts data/columns to TableData format", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); + + const vm = wrapper.vm as any; + const computed = vm.computedTableJSON; + + expect(computed.schema).toBeDefined(); + expect(computed.schema.fields).toHaveLength(3); + expect(computed.data).toEqual(mockData); + }); + + it("includes validation when provided", () => { + const validation = { columns: { name: { dtype: "str" } }, index: [], checks: {} }; + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + validation, + }, + }); + + const vm = wrapper.vm as any; + expect(vm.computedTableJSON.validation).toEqual(validation); }); }); - it("provides public API methods", () => { - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - }, + describe("editable class modifier", () => { + it("does not have editable class when editable is false", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + editable: false, + }, + }); + + expect(wrapper.find(".tabulator-container--editable").exists()).toBe(false); }); - const vm = wrapper.vm as any; - - // Test that all public methods exist - expect(typeof vm.getData).toBe("function"); - expect(typeof vm.getSelectedData).toBe("function"); - expect(typeof vm.getSelectedRows).toBe("function"); - expect(typeof vm.selectRow).toBe("function"); - expect(typeof vm.deselectRow).toBe("function"); - expect(typeof vm.addRow).toBe("function"); - expect(typeof vm.updateRow).toBe("function"); - expect(typeof vm.deleteRow).toBe("function"); - expect(typeof vm.clearData).toBe("function"); - expect(typeof vm.setData).toBe("function"); - expect(typeof vm.setFilter).toBe("function"); - expect(typeof vm.clearFilter).toBe("function"); - expect(typeof vm.setSort).toBe("function"); - expect(typeof vm.clearSort).toBe("function"); - expect(typeof vm.redraw).toBe("function"); - expect(typeof vm.scrollToRow).toBe("function"); - expect(typeof vm.scrollToColumn).toBe("function"); - expect(typeof vm.download).toBe("function"); - expect(typeof vm.getRowCount).toBe("function"); - expect(typeof vm.getColumns).toBe("function"); - expect(typeof vm.hideColumn).toBe("function"); - expect(typeof vm.showColumn).toBe("function"); - expect(typeof vm.toggleColumn).toBe("function"); + it("has editable class when editable is true", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + editable: true, + }, + }); + + expect(wrapper.find(".tabulator-container--editable").exists()).toBe(true); + }); }); - it("emits events correctly", async () => { - const wrapper = mount(BaseSimpleTable, { - propsData: { - columns: mockColumns, - data: mockData, - }, + describe("methods", () => { + it("provides public API methods", () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); + + const vm = wrapper.vm as any; + + expect(typeof vm.getData).toBe("function"); + expect(typeof vm.setData).toBe("function"); + expect(typeof vm.getRowCount).toBe("function"); + expect(typeof vm.getColumns).toBe("function"); + expect(typeof vm.validateTable).toBe("function"); + expect(typeof vm.redraw).toBe("function"); }); + }); - // Simulate table built event - const vm = wrapper.vm as any; - vm.isInitialized = true; + describe("events", () => { + it("emits events correctly", async () => { + const wrapper = shallowMount(BaseSimpleTable, { + propsData: { + columns: mockColumns, + data: mockData, + }, + }); - // Test that events can be emitted - wrapper.vm.$emit("table-built"); - wrapper.vm.$emit("data-loaded", mockData); - wrapper.vm.$emit("data-changed", mockData); + wrapper.vm.$emit("table-built"); + wrapper.vm.$emit("row-click", {}, {}); + wrapper.vm.$emit("cell-edited", {}); - await wrapper.vm.$nextTick(); + await wrapper.vm.$nextTick(); - expect(wrapper.emitted("table-built")).toBeTruthy(); - expect(wrapper.emitted("data-loaded")).toBeTruthy(); - expect(wrapper.emitted("data-changed")).toBeTruthy(); + expect(wrapper.emitted("table-built")).toBeTruthy(); + expect(wrapper.emitted("row-click")).toBeTruthy(); + expect(wrapper.emitted("cell-edited")).toBeTruthy(); + }); }); }); diff --git a/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.vue b/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.vue index 18ea00d2a..15a62bbc4 100644 --- a/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.vue +++ b/extralit-frontend/components/base/base-simple-table/BaseSimpleTable.vue @@ -1,14 +1,34 @@ - +