fix(tests): remove low-value source snapshots and define test standards
This commit is contained in:
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")');
|
||||
});
|
||||
});
|
||||
-14
@@ -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");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user