mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 16:09:05 +00:00
Co-authored-by: Kirtan Thakkar <kirtan@kiara.tech> Co-authored-by: Bhargav <BJP232004@GMAIL.COM> Co-authored-by: ktx-riya <riya.kukadiya@kiara.tech>
125 lines
5.0 KiB
TypeScript
125 lines
5.0 KiB
TypeScript
// 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);
|
||
});
|
||
});
|