import assert from "node:assert"; import { describe, it } from "node:test"; import { AdaptiveTable } from "./index"; const withCanvasMeasurement = (callback: () => void) => { const originalGetContext = HTMLCanvasElement.prototype.getContext; HTMLCanvasElement.prototype.getContext = ((contextId: string) => { if (contextId !== "2d") { return null; } return { font: "", measureText: (text: string) => ({ width: text.length * 8 }), } as CanvasRenderingContext2D; }) as HTMLCanvasElement["getContext"]; try { callback(); } finally { HTMLCanvasElement.prototype.getContext = originalGetContext; } }; describe("AdaptiveTable plugin", () => { it("wraps regular table into adaptive container", () => { document.body.innerHTML = ""; const table = document.createElement("table"); document.body.appendChild(table); AdaptiveTable.init(document); assert.ok(table.closest(AdaptiveTable.selectors.instance)); }); it("does not wrap table with data-js-adaptiveTableExclude attribute", () => { document.body.innerHTML = ""; const table = document.createElement("table"); table.setAttribute("data-js-adaptiveTableExclude", ""); document.body.appendChild(table); AdaptiveTable.init(document); assert.ok(!table.closest(AdaptiveTable.selectors.instance)); }); it("detects if table parent matches instance selector", () => { document.body.innerHTML = ""; const wrapper = document.createElement("div"); wrapper.setAttribute("data-js-adaptiveTable", ""); const table = document.createElement("table"); wrapper.appendChild(table); document.body.appendChild(wrapper); // isAdaptive should return false when parent matches selector assert.strictEqual(AdaptiveTable.isAdaptive(table), false); }); it("adds correct wrapper structure with classes", () => { document.body.innerHTML = ""; const table = document.createElement("table"); document.body.appendChild(table); AdaptiveTable.init(document); const wrapper = table.closest(AdaptiveTable.selectors.instance); const innerWrapper = table.parentElement; assert.ok(wrapper?.classList.contains("adaptiveTable")); assert.ok(innerWrapper?.classList.contains("adaptiveTable__wrapper")); }); it("sets edge classes correctly on init", () => { document.body.innerHTML = ""; const table = document.createElement("table"); document.body.appendChild(table); AdaptiveTable.init(document); const wrapper = table.closest(AdaptiveTable.selectors.instance); assert.ok(wrapper?.classList.contains("isEdgeLeft")); }); it("sets right edge class when scroll position is within a fractional pixel from the end", () => { document.body.innerHTML = ""; const wrapper = document.createElement("div"); wrapper.setAttribute("data-js-adaptiveTable", ""); document.body.appendChild(wrapper); Object.defineProperties(wrapper, { scrollLeft: { configurable: true, value: 99.5 }, scrollWidth: { configurable: true, value: 200 }, offsetWidth: { configurable: true, value: 100 }, }); AdaptiveTable.setEdges(wrapper); assert.ok(wrapper.classList.contains("isEdgeRight")); }); it("checks isAdaptive correctly for regular table", () => { const table = document.createElement("table"); assert.strictEqual(AdaptiveTable.isAdaptive(table), true); }); it("checks isAdaptive correctly for excluded table", () => { const table = document.createElement("table"); table.setAttribute("data-js-adaptiveTableExclude", ""); assert.strictEqual(AdaptiveTable.isAdaptive(table), false); }); it("initializes scrollLeft to 0", () => { document.body.innerHTML = ""; const table = document.createElement("table"); document.body.appendChild(table); AdaptiveTable.init(document); const wrapper = table.closest(AdaptiveTable.selectors.instance) as HTMLElement; assert.strictEqual(wrapper.scrollLeft, 0); }); it("handles multiple tables in context", () => { document.body.innerHTML = ""; const table1 = document.createElement("table"); const table2 = document.createElement("table"); document.body.appendChild(table1); document.body.appendChild(table2); AdaptiveTable.init(document); assert.ok(table1.closest(AdaptiveTable.selectors.instance)); assert.ok(table2.closest(AdaptiveTable.selectors.instance)); }); it("works with custom context element", () => { const container = document.createElement("div"); const table = document.createElement("table"); container.appendChild(table); document.body.appendChild(container); AdaptiveTable.init(container); assert.ok(table.closest(AdaptiveTable.selectors.instance)); }); it("formats text by default for wide tables", () => { withCanvasMeasurement(() => { document.body.innerHTML = ""; const table = document.createElement("table"); const row = table.insertRow(); Array.from({ length: AdaptiveTable.defaultCfg.thresholdColsNumber }).forEach((_, index) => { const cell = row.insertCell(); cell.textContent = `Column ${index} with enough text content`; }); document.body.appendChild(table); AdaptiveTable.init(document); const wrapper = table.closest(AdaptiveTable.selectors.instance); assert.ok(wrapper?.classList.contains("adaptiveTable--isFormatted")); assert.ok(row.cells[0].style.minWidth); }); }); it("skips text formatting when isFormatText is false", () => { withCanvasMeasurement(() => { document.body.innerHTML = `
| Column 1 with enough text content | Column 2 with enough text content | Column 3 with enough text content | Column 4 with enough text content | Column 5 with enough text content | Column 6 with enough text content | Column 7 with enough text content |