Files
cc-switch/tests/components/requestLogColumns.test.ts
T
Jason 0cfea5e325 feat(usage): pick which request log columns to show
A columns menu sits next to the status filter on the request log tab.
Columns can be ticked on and off without the menu closing, and a
"Reset to default" item appears once anything differs from the default.
The time column always stays, since it opens the request detail.

Four new columns, hidden by default:
- Cache Write: tokens written to the cache. Codex, Gemini and Grok do
  not report it, so they show "—" with a hover explanation.
- Hit Rate: per-request cache hit rate (#7298), same formula as the
  overall hit rate. It is floored to one decimal so a near-full hit
  never reads as 100%.
- Total Time: taken from latency_ms, which covers the whole streamed
  response. The duration_ms column is never written and stays NULL.
  Values estimated from session logs carry a "≈" prefix.
- Status Code: when shown, the error badge next to the time is dropped.

Only columns that differ from their default are saved
(`usageDisplay.requestLogColumns` in ~/.cc-switch/settings.json), so a
column added later still appears with its own default for existing
users. The table widens with the column count and scrolls sideways
instead of squeezing every column.
2026-10-16 19:29:23 +08:00

67 lines
1.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
REQUEST_LOG_COLUMNS,
resolveRequestLogColumns,
setRequestLogColumn,
TOGGLEABLE_REQUEST_LOG_COLUMNS,
} from "@/components/usage/requestLogColumns";
describe("request log columns", () => {
it("shows the ten original columns by default and hides the new ones", () => {
expect(resolveRequestLogColumns(undefined)).toEqual([
"time",
"app",
"provider",
"model",
"freshInput",
"output",
"cacheRead",
"cost",
"speed",
"firstToken",
]);
});
it("applies overrides in table order, keeps time, ignores unknown ids", () => {
expect(
resolveRequestLogColumns({
statusCode: true,
app: false,
time: false,
someFutureColumn: true,
}),
).toEqual([
"time",
"provider",
"model",
"freshInput",
"output",
"cacheRead",
"cost",
"speed",
"firstToken",
"statusCode",
]);
expect(TOGGLEABLE_REQUEST_LOG_COLUMNS.map((c) => c.id)).not.toContain(
"time",
);
expect(TOGGLEABLE_REQUEST_LOG_COLUMNS).toHaveLength(
REQUEST_LOG_COLUMNS.length - 1,
);
});
it("stores only columns that differ from their default", () => {
expect(setRequestLogColumn(undefined, "hitRate", true)).toEqual({
hitRate: true,
});
expect(setRequestLogColumn({ hitRate: true }, "hitRate", false)).toEqual(
{},
);
expect(setRequestLogColumn({}, "app", false)).toEqual({ app: false });
// 时间列不能关;别的版本写的未知列原样留着
expect(
setRequestLogColumn({ someFutureColumn: true }, "time", false),
).toEqual({ someFutureColumn: true });
});
});