Files
openobserve/web/src/lib/core/Table/OTable.flexwidth.spec.ts
T
d79bbbe9e8 fix: layout bugs 2 (#12594)
Co-authored-by: Kirtan Thakkar <kirtan@kiara.tech>
Co-authored-by: Bhargav <BJP232004@GMAIL.COM>
Co-authored-by: ktx-riya <riya.kukadiya@kiara.tech>
2026-06-11 12:59:57 +05:30

125 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2026 OpenObserve Inc.
import { describe, it, expect, beforeAll } from "vitest";
import { mount, config, flushPromises } from "@vue/test-utils";
import { createI18n } from "vue-i18n";
const i18n = createI18n({ legacy: false, locale: "en", messages: { en: {} } });
beforeAll(() => {
config.global.plugins.unshift([i18n as any]);
(globalThis as any).requestAnimationFrame = (cb: any) => cb();
});
import OTable from "./OTable.vue";
import type { OTableColumnDef } from "./OTable.types";
const columns: OTableColumnDef[] = [
{ id: "name", header: "Name", accessorKey: "name", size: 200, minSize: 160, meta: { align: "left", flex: true } },
{ id: "type", header: "Type", accessorKey: "type", size: 100 },
{ id: "actions", header: "Actions", isAction: true, size: 80 },
];
const data = [{ name: "a", type: "logs" }, { name: "b", type: "logs" }];
function tableWidth(wrapper: any): number {
const style = wrapper.find('[data-test="o2-table"]').attributes("style") || "";
const m = style.match(/(?:^|[^-])width:\s*(\d+(?:\.\d+)?)px/);
return m ? parseFloat(m[1]) : -1;
}
function colVar(wrapper: any, id: string): number {
const style = wrapper.find('[data-test="o2-table"]').attributes("style") || "";
const m = style.match(new RegExp(`--col-${id}-size:\\s*(\\d+(?:\\.\\d+)?)px`));
return m ? parseFloat(m[1]) : -1;
}
function isWFull(wrapper: any): boolean {
return (wrapper.find('[data-test="o2-table"]').attributes("class") || "").includes("w-full");
}
function headerVar(wrapper: any, safeId: string): number {
const style = wrapper.find('[data-test="o2-table"]').attributes("style") || "";
const m = style.match(new RegExp(`--header-${safeId}-size:\\s*(\\d+(?:\\.\\d+)?)px`));
return m ? parseFloat(m[1]) : -1;
}
function thHasExplicitWidth(wrapper: any, id: string): boolean {
const style = wrapper.find(`[data-test="o2-table-th-${id}"]`).attributes("style") || "";
return /(?:^|[^-])width:/.test(style);
}
// Regression: a `meta.flex` column fills the leftover width on load, and the
// first resize freezes it so the table grows + scrolls (only the dragged column
// changes) instead of squeezing the flex/rigid columns.
describe("OTable flex column width", () => {
it("fills initially, then grows + holds the flex column on resize", async () => {
const wrapper = mount(OTable, {
props: {
data, columns,
selection: "multiple",
showIndex: true,
enableColumnResize: true,
defaultColumns: false,
tableId: "flexdiag",
} as any,
});
await flushPromises();
const st: any = (wrapper.vm.$ as any).setupState;
st.containerWidth = 1000;
await flushPromises();
// Fill state: width:100% (w-full), no explicit px width → can't overflow →
// no stray scrollbar. Name absorbs the leftover via the browser.
expect(isWFull(wrapper)).toBe(true);
expect(tableWidth(wrapper)).toBe(-1);
// Resize freezes the flex column at its current fill width. With no layout,
// the arithmetic fallback = container − nonFlex (1000 − 272) = 728 is pinned
// into columnSizing. Then widen Type to 400 (TanStack preserves name).
st.freezeFlexColumns();
st.columnSizing = { ...st.columnSizing, type: 400 };
await flushPromises();
// Now explicit width: Name HOLDS at 728, table grows to 1300 (scroll),
// # stays 44, and w-full is dropped.
expect(isWFull(wrapper)).toBe(false);
expect(colVar(wrapper, "name")).toBe(728);
expect(tableWidth(wrapper)).toBe(1300);
expect(colVar(wrapper, "#")).toBe(44);
// DECREASE Type to 50 (below its original 100). Name must NOT grow to
// absorb the freed space — it stays frozen at 728. Real columns sum to 950
// (< container) so the invisible spacer absorbs the 50px (its var) and the
// table stays at the container width (1000) → actions flush-right.
st.columnSizing = { ...st.columnSizing, type: 50 };
await flushPromises();
expect(colVar(wrapper, "name")).toBe(728);
expect(colVar(wrapper, "#")).toBe(44);
expect(colVar(wrapper, "__spacer__")).toBe(50);
expect(tableWidth(wrapper)).toBe(1000);
// Reset → frozen cleared → back to pure-fill (w-full, Name re-fills).
st.frozen = false;
st.columnSizing = {};
await flushPromises();
expect(isWFull(wrapper)).toBe(true);
});
it("fill state: flex column has explicit fill width and spacer is 0", async () => {
const wrapper = mount(OTable, {
props: {
data, columns,
selection: "multiple",
showIndex: true,
enableColumnResize: true,
defaultColumns: false,
tableId: "flexdiag2",
} as any,
});
await flushPromises();
(wrapper.vm.$ as any).setupState.containerWidth = 1000;
await flushPromises();
// The flex (name) column fills explicitly (container 1000 − nonFlex 272).
expect(thHasExplicitWidth(wrapper, "name")).toBe(true);
expect(headerVar(wrapper, "name")).toBe(728);
// The invisible spacer must be 0 in the fill state — no trailing gap.
expect(headerVar(wrapper, "--spacer--")).toBe(0);
});
});