fix(tests): remove low-value source snapshots and define test standards

This commit is contained in:
t8y2 committed 2026-09-11 11:51:24 +08:00
1 parent ead906477f
commit 8186c697d5
80 files changed
+14 -2225

No files matched your search

@@ -1,19 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const source = readFileSync(new URL("../DdlViewDialog.vue", import.meta.url), "utf8");
describe("DdlViewDialog freshness", () => {
it("uses the persisted refresh preference when the dialog opens", () => {
expect(source).toMatch(/watch\(\s*\(\) => props\.open,[\s\S]*?await loadDdl\(settingsStore\.editorSettings\.refreshDdlOnOpen\);/);
});
it("refreshes the current DDL immediately when the preference is enabled", () => {
expect(source).toMatch(/function setRefreshDdlOnOpen\(value: boolean\)[\s\S]*?if \(value\) void loadDdl\(true\);/);
});
it("explains how the refresh preference affects cached DDL", () => {
expect(source).toContain('import { HelpTooltip } from "@/components/ui/tooltip";');
expect(source).toMatch(/<HelpTooltip :label="t\('contextMenu\.refreshDdlOnOpenHint'\)"[\s\S]*?t\("contextMenu\.refreshDdlOnOpenHint"\)[\s\S]*?<\/HelpTooltip>/);
});
});
@@ -1,59 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const source = readFileSync(new URL("../ObjectBrowser.vue", import.meta.url), "utf8");
function functionBody(name: string): string {
const signature = new RegExp(`(?:async\\s+)?function\\s+${name}\\s*\\([^)]*\\)\\s*(?::\\s*[^\\{]+)?\\{`, "m").exec(source);
if (!signature) throw new Error(`Missing function ${name}`);
const bodyStart = signature.index + signature[0].length;
let depth = 1;
for (let index = bodyStart; index < source.length; index += 1) {
if (source[index] === "{") depth += 1;
else if (source[index] === "}") depth -= 1;
if (depth === 0) return source.slice(bodyStart, index);
}
throw new Error(`Unclosed function ${name}`);
}
describe("ObjectBrowser add to AI", () => {
it("declares the addToAi emit for table context hand-off", () => {
const emitDeclaration = source.slice(source.indexOf("const emit = defineEmits"), source.indexOf(">();", source.indexOf("const emit = defineEmits")));
expect(emitDeclaration).toContain("addToAi");
});
it("adds an 'Add to AI' menu item after 'New Query' in the table menu", () => {
const tableMenu = functionBody("getTableMenuItems");
const newQueryIndex = tableMenu.indexOf('t("contextMenu.newQuery")');
const addToAiIndex = tableMenu.indexOf("addToAiMenuItem(item)");
expect(newQueryIndex).toBeGreaterThan(-1);
expect(addToAiIndex).toBeGreaterThan(newQueryIndex);
});
it("guards the menu item behind supportsAiAssistantContext", () => {
const tableMenu = functionBody("getTableMenuItems");
expect(tableMenu).toContain("supportsAiAssistantContext(effectiveDatabaseType.value)");
expect(tableMenu).toContain("[addToAiMenuItem(item)]");
});
it("offers 'Add to AI' in the VictoriaMetrics early-return branch too", () => {
const tableMenu = functionBody("getTableMenuItems");
// The VM branch is the first block inside getTableMenuItems; verify it guards
// the same AI entry so ObjectBrowser stays consistent with the sidebar tree.
const vmBranchStart = tableMenu.indexOf("if (isVictoriaMetrics.value)");
const vmBranchEnd = tableMenu.indexOf("const useBatchActions", vmBranchStart);
const vmBranch = tableMenu.slice(vmBranchStart, vmBranchEnd);
expect(vmBranch).toContain("supportsAiAssistantContext(effectiveDatabaseType.value)");
expect(vmBranch).toContain("[addToAiMenuItem(item)]");
expect(vmBranch.indexOf("addToAiMenuItem(item)")).toBeGreaterThan(vmBranch.indexOf('t("contextMenu.newQuery")'));
});
it("emits selected tables (batch) or the single table with per-row schema", () => {
const addToAi = functionBody("addToAiMenuItem");
expect(addToAi).toContain("selectedTableRows.value.map((row) => ({ name: row.name, schema: row.schema }))");
expect(addToAi).toContain('emit("addToAi", targets)');
expect(addToAi).toContain('t("contextMenu.addToAiMultiple", { count })');
expect(addToAi).toContain('t("contextMenu.addToAi")');
});
});
@@ -1,14 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const objectSourceDialogSource = readFileSync(new URL("../ObjectSourceDialog.vue", import.meta.url), "utf8");
describe("ObjectSourceDialog edit draft wiring (issue #5057)", () => {
it("seeds the initial edit draft from the pretty-printed source, not the raw single-line definition", () => {
expect(objectSourceDialogSource).toMatch(/draft\.value = nextEditing && canEdit\.value \? resolveObjectSourceEditDraft\(props\.databaseType, resolvedType, formatted, editable\) : "";/);
});
it("seeds the draft opened via the Edit button from the pretty-printed source, not the raw single-line definition", () => {
expect(objectSourceDialogSource).toMatch(/function editSource\(\) \{[\s\S]*?draft\.value = resolveObjectSourceEditDraft\(props\.databaseType, resolvedObjectType\.value, content\.value, editableText\.value\);/);
});
});
@@ -1,41 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const objectBrowserSource = readFileSync(new URL("../ObjectBrowser.vue", import.meta.url), "utf8");
const databaseBrowserSource = readFileSync(new URL("../DatabaseBrowser.vue", import.meta.url), "utf8");
function functionBody(source: string, name: string): string {
const signature = new RegExp(`(?:async\\s+)?function\\s+${name}\\s*\\([^)]*\\)\\s*(?::\\s*[^\\{]+)?\\{`, "m").exec(source);
if (!signature) throw new Error(`Missing function ${name}`);
const bodyStart = signature.index + signature[0].length;
let depth = 1;
for (let index = bodyStart; index < source.length; index += 1) {
if (source[index] === "{") depth += 1;
else if (source[index] === "}") depth -= 1;
if (depth === 0) return source.slice(bodyStart, index);
}
throw new Error(`Unclosed function ${name}`);
}
describe("database and object browser search clear controls", () => {
it("renders a clear button with input padding on both search surfaces", () => {
expect(objectBrowserSource).toContain('class="h-7 pl-8 pr-6 text-xs"');
expect(objectBrowserSource).toContain(':aria-label="t(\'common.clear\')" @click="clearObjectSearch"');
expect(objectBrowserSource).toContain('<button v-if="search" type="button"');
expect(databaseBrowserSource).toContain('class="h-7 pl-8 pr-6 text-xs"');
expect(databaseBrowserSource).toContain(':aria-label="t(\'common.clear\')" @click="clearDatabaseSearch"');
expect(databaseBrowserSource).toContain('<button v-if="search" type="button"');
});
it("clears and refocuses each search input", () => {
expect(functionBody(objectBrowserSource, "clearObjectSearch")).toContain('search.value = "";');
expect(functionBody(objectBrowserSource, "clearObjectSearch")).toContain("getSearchInput()?.focus();");
expect(functionBody(databaseBrowserSource, "clearDatabaseSearch")).toContain('search.value = "";');
expect(functionBody(databaseBrowserSource, "clearDatabaseSearch")).toContain("searchInput.value?.$el?.focus();");
});
it("keeps the ObjectBrowser keyboard clear path on the shared handler", () => {
expect(functionBody(objectBrowserSource, "onSearchKeydown")).toContain("clearObjectSearch();");
});
});
@@ -1,38 +0,0 @@
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
function source(relative: string): string {
return readFileSync(fileURLToPath(new URL(relative, import.meta.url)), "utf8");
}
/**
* Slices the body of one sidebar menu builder out of SidebarTreeRuntimeHost.vue.
* Matching the builder rather than a formatted line keeps this guard indifferent
* to how oxfmt lays the menu pushes out.
*/
function sidebarMenuBuilder(name: string): string {
const text = source("../../sidebar/SidebarTreeRuntimeHost.vue");
const start = text.indexOf(`function ${name}(`);
expect(start, `${name} not found`).toBeGreaterThan(-1);
const next = text.indexOf("\nfunction ", start + 1);
return text.slice(start, next === -1 ? undefined : next);
}
describe("documentation menu placement", () => {
it("registers the entry on database and schema nodes", () => {
// The docs viewer documents a database or a schema, so it belongs on the
// tree nodes that name one. buildDatabaseSidebarMenu serves both types.
expect(sidebarMenuBuilder("buildDatabaseSidebarMenu")).toContain("docs.title");
});
it("keeps the entry off the sidebar's per-object menu", () => {
expect(sidebarMenuBuilder("buildObjectSidebarMenu")).not.toContain("docs.title");
});
it("keeps the entry off the object browser's menus", () => {
// openDocs never read the row's table: a table-level entry advertised a
// scope the viewer cannot render.
expect(source("../ObjectBrowser.vue")).not.toContain("docs.title");
});
});