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,18 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("BigQuery connection dialog", () => {
it("exposes and persists external JDBC driver configuration", () => {
const nativeAgentDriverSupport = dialogSource.match(/function supportsNativeAgentJdbcDriverConfigType\(dbType: DatabaseType\): boolean \{([\s\S]*?)\}/)?.[1] ?? "";
const jdbcBackedDatabaseTypes = dialogSource.match(/const jdbcBackedDatabaseTypes = new Set<DatabaseType>\(\[([\s\S]*?)\]\);/)?.[1] ?? "";
expect(nativeAgentDriverSupport).toContain('dbType === "bigquery"');
expect(jdbcBackedDatabaseTypes).toContain('"bigquery"');
expect(dialogSource).toContain("const supportsNativeAgentJdbcDriverConfig = computed(() => supportsNativeAgentJdbcDriverConfigType(form.value.db_type)");
expect(dialogSource).toContain('<template v-if="supportsNativeAgentJdbcDriverConfig">');
expect(dialogSource).toContain('if (profile.type === "bigquery") {');
expect(dialogSource).toContain("jdbcManualClasspathOpen.value = true;");
});
});
@@ -1,16 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
const tlsCapableDatabaseTypesSource = dialogSource.match(/const tlsCapableDatabaseTypes = new Set<DatabaseType>\(\[([\s\S]*?)\]\);/)?.[1] ?? "";
describe("Dameng SSL connection form", () => {
it("shows Dameng in the TLS tab with certificate directory and password fields", () => {
expect(tlsCapableDatabaseTypesSource).toContain('"dameng"');
expect(dialogSource).toContain("<template v-if=\"form.db_type === 'dameng'\">");
expect(dialogSource).toContain('v-model="damengSslFilesPath"');
expect(dialogSource).toContain('v-model="damengSslKeystorePassword"');
expect(dialogSource).toContain('v-model="damengSslProtocol"');
expect(dialogSource).toContain('t("connection.damengSslVerificationHint")');
});
});
@@ -1,22 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("connection dialog accessibility", () => {
it("moves initial focus to an input inside the dialog", () => {
expect(dialogSource).toContain('<Input v-model="dbSearchQuery" v-connection-dialog-auto-focus');
expect(dialogSource).toContain('<Input v-model="form.name" v-connection-dialog-auto-focus');
expect(dialogSource).toContain("const vConnectionDialogAutoFocus: ObjectDirective<HTMLInputElement>");
expect(dialogSource).toContain("input.focus({ preventScroll: true })");
expect(dialogSource).not.toMatch(/<DialogContent[^>]*\stabindex="-1"/);
});
it("reserves focus ring space around the scrollable category navigation", () => {
const nav = dialogSource.match(/<nav data-connection-category-nav class="([^"]+)"/)?.[1] ?? "";
expect(nav).toContain("px-0.5");
expect(nav).toContain("pt-0.5");
expect(nav).toContain("sm:py-0.5");
});
});
@@ -1,11 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("connection dialog corner style", () => {
it("uses the shared corner radius token for configuration controls", () => {
expect(dialogSource).toContain("border-radius: var(--dbx-radius-fixed-4, 4px);");
expect(dialogSource).not.toMatch(/\.connection-config-step[\s\S]*?border-radius:\s*4px;/);
});
});
@@ -1,30 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("connection dialog scrolling", () => {
it("keeps every configuration tab inside a shrinkable form viewport", () => {
expect(dialogSource).toContain('connection-dialog-content--config${scrollableAdvancedNacos ? " connection-dialog-content--scrollable" : ""}');
expect(dialogSource.match(/<TabsContent[^>]*class="m-0 flex min-h-0 flex-1 flex-col overflow-hidden">/g)).toHaveLength(4);
expect(dialogSource.match(/class="connection-form-body grid min-h-0 flex-1 scroll-pb-6 gap-4 overflow-y-auto/g)).toHaveLength(4);
expect(dialogSource).toMatch(/\.connection-dialog-content--scrollable\s*\{[\s\S]*?height:\s*min\(720px, calc\(var\(--dbx-viewport-height\) - 2rem\)\);/);
expect(dialogSource).toMatch(/@media \(max-height: 720px\)[\s\S]*?height:\s*calc\(var\(--dbx-viewport-height\) - 2rem\);/);
expect(dialogSource).toMatch(/\.connection-dialog-content--config \.connection-form-body\s*\{[\s\S]*?align-content:\s*start;/);
});
it("hides proxy and HTTP tunnel controls for SQLite", () => {
expect(dialogSource).toContain('v-if="!sqliteSshOnlyTransport"');
expect(dialogSource).toContain('v-if="!selectedLayerProfileId && !sqliteSshOnlyTransport"');
});
it("keeps the transport form inside a shrinkable scroll viewport", () => {
expect(dialogSource).toContain('<TabsContent v-if="canUseTransportLayers" value="transport" class="m-0 flex min-h-0 flex-1 flex-col overflow-hidden">');
expect(dialogSource).toContain('class="connection-form-body grid min-h-0 flex-1 scroll-pb-6 gap-4 overflow-y-auto overflow-x-hidden pt-4 pr-2 pb-6"');
});
it("keeps Nacos cards at their content height on both form tabs", () => {
expect(dialogSource.match(/:class="\{ 'connection-form-body--nacos': form\.db_type === 'nacos' \}"/g)).toHaveLength(2);
expect(dialogSource).toMatch(/\.connection-form-body--nacos\s*\{[\s\S]*?grid-auto-rows:\s*max-content;/);
});
});
@@ -1,25 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
function section(startMarker: string, endMarker: string): string {
const start = dialogSource.indexOf(startMarker);
const end = dialogSource.indexOf(endMarker, start);
expect(start).toBeGreaterThanOrEqual(0);
expect(end).toBeGreaterThan(start);
return dialogSource.slice(start, end);
}
describe("Consul connection dialog", () => {
it("keeps Operator feature switches in the Consul form instead of the JDBC form", () => {
const jdbcForm = section("<!-- JDBC: optional external plugin -->", "<!-- Local database files: file path only -->");
const consulForm = section("<!-- Consul KV: HTTP endpoint, ACL token and scope -->", "<!-- etcd: endpoints, user, password, TLS -->");
const operatorModels = ["consulOperatorVisible", "consulOperatorSnapshotRestoreEnabled", "consulOperatorAutopilotWriteEnabled", "consulOperatorRaftWriteEnabled", "consulOperatorKeyringWriteEnabled", "consulOperatorLicenseWriteEnabled"];
for (const model of operatorModels) {
expect(jdbcForm).not.toContain(`v-model="${model}"`);
expect(consulForm).toContain(`v-model="${model}"`);
}
});
});
@@ -1,12 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
describe("GaussDB connection dialog persistence", () => {
it("preserves count-query DOP in submitted connection configs", () => {
const source = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
const submitConfig = source.slice(source.indexOf("function connectionConfigForSubmit"), source.indexOf("function connectionNameForSubmit"));
expect(submitConfig).toContain("const countQueryDop = gaussdbCountQueryDop(config);");
expect(submitConfig).toContain("setGaussdbCountQueryDop(config, countQueryDop);");
});
});
@@ -1,11 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("MongoDB OIDC connection form", () => {
it("keeps the browser authentication hint inside a complete form row", () => {
expect(dialogSource).toContain(`<div v-if="mongoAuthMechanism === 'MONGODB-OIDC'" class="grid grid-cols-4 items-start gap-4">`);
expect(dialogSource).not.toContain(`<p v-if="mongoAuthMechanism === 'MONGODB-OIDC'" class="col-start-2 col-span-3`);
});
});
@@ -1,21 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
const mqttSectionStart = dialogSource.indexOf("<template v-else-if=\"form.db_type === 'mqtt'\">");
const mqttSectionEnd = dialogSource.indexOf("<template v-else-if=\"form.db_type === 'victoriametrics'\">", mqttSectionStart);
const mqttSection = dialogSource.slice(mqttSectionStart, mqttSectionEnd);
describe("MQTT connection dialog", () => {
it("binds TLS switches through the shared Switch model API", () => {
expect(mqttSection).toContain('<Switch v-model="mqttTls" />');
expect(mqttSection).toContain('<Switch v-model="mqttTlsSkipVerify" class="ml-4" />');
expect(mqttSection).not.toContain(":checked=");
expect(mqttSection).not.toContain("@update:checked=");
});
it("serializes both TLS choices into the MQTT external config", () => {
expect(dialogSource).toContain("tls: mqttTls.value");
expect(dialogSource).toContain("tlsSkipVerify: mqttTlsSkipVerify.value");
});
});
@@ -1,13 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("SSH agent connection form", () => {
it("offers SSH agent for a new tunnel and exposes its custom socket path", () => {
expect(dialogSource).toContain('<SelectItem value="agent">{{ t("connection.sshUseAgent") }}</SelectItem>');
expect(dialogSource).toContain('<div v-if="selectedSshLayer.auth_method === \'agent\'" class="grid grid-cols-4 items-center gap-4">');
expect(dialogSource).toContain('v-model="selectedSshLayer.ssh_agent_sock_path"');
expect(dialogSource).not.toContain('v-if="isLegacySshAgentMethod(selectedSshLayer)" value="agent" disabled');
});
});
@@ -1,21 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const managerSource = readFileSync(new URL("../../../components/connection/TunnelProfileManager.vue", import.meta.url), "utf8");
describe("SSH agent tunnel profile form", () => {
it("offers the same SSH agent login method as the connection editor", () => {
expect(managerSource).toContain('<SelectItem value="agent">{{ t("connection.sshUseAgent") }}</SelectItem>');
});
it("exposes the custom agent socket path while keeping the shared auth mapping", () => {
expect(managerSource).toContain(`<div v-if="selectedSsh.auth_method === 'agent'" class="grid grid-cols-4 items-center gap-4">`);
expect(managerSource).toContain('v-model="selectedSsh.ssh_agent_sock_path"');
expect(managerSource).toContain('import { applySshAuthMethod } from "@/lib/connection/sshAuthMethod";');
expect(managerSource).toContain("applySshAuthMethod(profile, value);");
});
it("does not keep a second auth-method mapping that could drift from applySshAuthMethod", () => {
expect(managerSource).not.toContain('value === "key+password" ? "key+password"');
});
});
@@ -1,25 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
describe("ConnectionDialog SSH tunnel test", () => {
it("exposes a dedicated SSH tunnel test without running the database test", () => {
expect(dialogSource).toContain("async function testSshTunnel()");
expect(dialogSource).toContain("await api.testSshTunnel(config)");
expect(dialogSource).toContain('@click="testSshTunnel"');
expect(dialogSource).toContain('t("connection.sshTunnelTest")');
});
it("builds the tunnel probe config without database-specific validation", () => {
const start = dialogSource.indexOf("function connectionConfigForSshTunnelTest");
const end = dialogSource.indexOf("function connectionConfigForSubmit", start);
const helperSource = dialogSource.slice(start, end);
expect(start).toBeGreaterThan(-1);
expect(end).toBeGreaterThan(start);
expect(helperSource).toContain("normalizeTransportLayersForSubmit(config)");
expect(helperSource).not.toContain("kingbaseDatabaseRequired");
expect(helperSource).not.toContain("dynamodbCredentialsRequired");
});
});
@@ -1,32 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const dialogSource = readFileSync(new URL("../../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
const enSource = readFileSync(new URL("../../../i18n/locales/en.ts", import.meta.url), "utf8");
const zhCnSource = readFileSync(new URL("../../../i18n/locales/zh-CN.ts", import.meta.url), "utf8");
const fallbackLocaleSources = ["az", "es", "it", "ja", "ko", "pt-BR", "tr", "zh-TW"].map((locale) => readFileSync(new URL(`../../../i18n/locales/${locale}.ts`, import.meta.url), "utf8"));
describe("ZooKeeper connection dialog", () => {
it("binds the existing Select component to the ZooKeeper auth_scheme helper", () => {
expect(dialogSource).toContain("setZooKeeperAuthScheme");
expect(dialogSource).toContain("resolveZooKeeperAuthScheme");
expect(dialogSource).toContain("const zookeeperAuthScheme = computed<ZooKeeperAuthScheme>");
expect(dialogSource).toContain('<Select v-model="zookeeperAuthScheme">');
expect(dialogSource).toContain('<SelectItem value="digest">');
expect(dialogSource).toContain('<SelectItem value="sasl_digest">');
});
it("uses localized auth labels and tells users both cluster input locations", () => {
for (const source of [enSource, zhCnSource]) {
expect(source).toContain("zookeeperAuthMethod:");
expect(source).toContain("zookeeperAuthDigest:");
expect(source).toContain("zookeeperAuthSaslDigest:");
expect(source).toContain("zookeeperClusterInputHint:");
}
for (const source of fallbackLocaleSources) {
expect(source).toContain("withEnglishFallback");
}
expect(dialogSource).toContain('t("connection.zookeeperAuthMethod")');
expect(dialogSource).toContain('t("connection.zookeeperClusterInputHint")');
});
});
@@ -1,24 +0,0 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
const dataGridToolbarSource = readFileSync(new URL("../../../components/grid/DataGridToolbar.vue", import.meta.url), "utf8");
const dataGridSource = readFileSync(new URL("../../../components/grid/DataGrid.vue", import.meta.url), "utf8");
describe("data grid toolbar delete row", () => {
it("declares and renders the delete-row action button", () => {
expect(dataGridToolbarSource).toMatch(/deleteRow\?: DataGridToolbarActionCapability/);
expect(dataGridToolbarSource).toMatch(/isDataGridToolbarCapabilityVisible\(deleteRow\)/);
expect(dataGridToolbarSource).toMatch(/triggerDataGridToolbarAction\(deleteRow\)/);
});
it("wires the delete-row capability into the toolbar", () => {
expect(dataGridSource).toMatch(/:delete-row="deleteRowToolbarCapability"/);
});
it("keeps the delete-row capability tied to row deletion state", () => {
expect(dataGridSource).toMatch(/deleteRowToolbarTargetCount = computed\(\(\) => deletableRowIds\(selectedOrCurrentRowIds\(\)\)\.length\)/);
expect(dataGridSource).toMatch(/visible: deleteRowToolbarState\.value\.visible/);
expect(dataGridSource).toMatch(/disabled: deleteRowToolbarState\.value\.disabled/);
expect(dataGridSource).toMatch(/onTrigger: \(\) => \{\s*deleteCurrentRow\(\);/);
});
});
@@ -1,18 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const toolbarSource = readFileSync(new URL("../../../components/grid/DataGridToolbar.vue", import.meta.url), "utf8");
const dataGridSource = readFileSync(new URL("../../../components/grid/DataGrid.vue", import.meta.url), "utf8");
describe("DataGrid geometry layer preview toolbar entry", () => {
it("opens the registered geometry preview action from a visible map button", () => {
expect(toolbarSource).toMatch(/layerPreview\?: DataGridToolbarActionCapability/);
expect(toolbarSource).toMatch(/isDataGridToolbarCapabilityVisible\(layerPreview\)/);
expect(toolbarSource).toMatch(/triggerDataGridToolbarAction\(layerPreview\)/);
expect(toolbarSource).toMatch(/<Map class="data-grid-topbar-action-icon/);
expect(dataGridSource).toMatch(/candidate\.id === "geometry-map-preview"/);
expect(dataGridSource).toMatch(/:layer-preview="layerPreviewToolbarCapability"/);
expect(dataGridSource).toMatch(/executePreviewAction\(action\)/);
});
});
@@ -1,13 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const queryEditorSource = readFileSync(new URL("../../../components/editor/QueryEditor.vue", import.meta.url), "utf8");
describe("QueryEditor column prefix cache", () => {
it("hydrates qualified completions from the persistent prefix cache", () => {
const prefixLookups = queryEditorSource.match(/lookupLocalCompletionColumnsByPrefix/g) ?? [];
expect(prefixLookups.length).toBeGreaterThanOrEqual(2);
expect(queryEditorSource).toContain("completionColumnRequestContext(reference)");
});
});
@@ -1,8 +0,0 @@
import { readFileSync } from "node:fs";
import { expect, it } from "vitest";
const queryEditorSource = readFileSync(new URL("../../../components/editor/QueryEditor.vue", import.meta.url), "utf8");
it("maps inline projected columns into local completion results", () => {
expect(queryEditorSource).toMatch(/if \(refTable\.columns\?\.length\) \{[\s\S]*?columnsByTable\.set\([\s\S]*?refTable\.columns\.map/);
});
@@ -1,45 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const queryEditorSource = readFileSync(new URL("../../../components/editor/QueryEditor.vue", import.meta.url), "utf8");
// Regression test for issue #8096: clicking a long SQL statement in the
// execution-summary panel (previewStatementRange) used to only recolor the
// gutter line number, which is easy to miss and reads as "click does
// nothing" for statements that are already scrolled into view. The fix adds
// a visible text-highlight decoration alongside the existing gutter marker.
describe("QueryEditor result-source preview highlight", () => {
it("builds a highlight decoration field in addition to the gutter line-number field", () => {
const extensionStart = queryEditorSource.indexOf("buildResultSourceRangeExtension = () => {");
expect(extensionStart).toBeGreaterThan(-1);
const extensionEnd = queryEditorSource.indexOf("\n };", extensionStart);
const extensionBody = queryEditorSource.slice(extensionStart, extensionEnd);
expect(extensionBody).toContain("lineNumberMarkers.from(field)");
expect(extensionBody).toContain("const highlightField = StateField.define({");
expect(extensionBody).toContain('Decoration.mark({ class: "cm-db-result-source-highlight" })');
expect(extensionBody).toContain("EditorView.decorations.from(field)");
expect(extensionBody).toContain("return [field, highlightField];");
});
it("drives both the gutter marker and the highlight decoration from the same effect", () => {
const extensionStart = queryEditorSource.indexOf("buildResultSourceRangeExtension = () => {");
const extensionEnd = queryEditorSource.indexOf("\n };", extensionStart);
const extensionBody = queryEditorSource.slice(extensionStart, extensionEnd);
const effectUses = extensionBody.match(/effect\.is\(effectType\)/g) ?? [];
expect(effectUses.length).toBe(2);
});
it("defines a visible background style for the highlight class", () => {
expect(queryEditorSource).toMatch(/:deep\(\.cm-db-result-source-highlight\)\s*{\s*background:/);
});
it("keeps previewStatementRange wired to setResultSourceRangeEffect via setResultSourceRange", () => {
const fnStart = queryEditorSource.indexOf("function previewStatementRange(");
const fnEnd = queryEditorSource.indexOf("\n}", fnStart);
const fnBody = queryEditorSource.slice(fnStart, fnEnd);
expect(fnBody).toContain("setResultSourceRangeEffect.of({ from, to })");
});
});
@@ -1,12 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const queryEditorSource = readFileSync(new URL("../../../components/editor/QueryEditor.vue", import.meta.url), "utf8");
describe("QueryEditor bottom scroll space", () => {
it("allows editable documents to scroll past the last line without changing read-only previews", () => {
expect(queryEditorSource).toMatch(/scrollPastEnd,\s*ViewPlugin/);
expect(queryEditorSource).toMatch(/layer,\s*RectangleMarker/);
expect(queryEditorSource).toContain("props.readOnly ? [] : scrollPastEnd()");
});
});
@@ -1,29 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const queryEditorSource = readFileSync(new URL("../../../components/editor/QueryEditor.vue", import.meta.url), "utf8");
const appSource = readFileSync(new URL("../../../App.vue", import.meta.url), "utf8");
const globalStylesSource = readFileSync(new URL("../../../styles/globals.css", import.meta.url), "utf8");
describe("QueryEditor tooltip container", () => {
it("portals CodeMirror tooltips to a zero-sized app host", () => {
expect(queryEditorSource).toContain("const editorElement = editorRef.value;");
expect(queryEditorSource).toContain("if (!editorElement) return;");
expect(queryEditorSource).toContain('querySelector<HTMLElement>("#dbx-query-editor-tooltip-root") ?? editorElement');
expect(queryEditorSource).toContain("tooltips({ parent: tooltipParent })");
expect(queryEditorSource).toContain("new EditorView({ state, parent: editorElement })");
expect(queryEditorSource).not.toContain("tooltips({ parent: document.body })");
expect(appSource).toContain('id="dbx-query-editor-tooltip-root"');
expect(appSource).toContain('class="fixed left-0 top-0 z-[70] h-0 w-0 overflow-visible"');
});
it("keeps the app root viewport-sized without a transformed containing block", () => {
const rootRule = globalStylesSource.match(/html,\s*body,\s*#root\s*\{(?<declarations>[^}]*)\}/)?.groups?.declarations;
expect(rootRule).toBeDefined();
expect(rootRule).toMatch(/width:\s*100%/);
expect(rootRule).toMatch(/height:\s*100%/);
expect(rootRule).toMatch(/overflow:\s*hidden/);
expect(rootRule).not.toMatch(/(?:^|\s)(?:transform|contain)\s*:/);
});
});
@@ -1,19 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const appSource = readFileSync(new URL("../../../App.vue", import.meta.url), "utf8");
const useSqlExecutionSource = readFileSync(new URL("../../../composables/useSqlExecution.ts", import.meta.url), "utf8");
describe("toolbar explain routing", () => {
it("passes the tab id as the execution context, not as SQL", () => {
// Regression: the injected action once called tryExplain(tabId), whose
// first parameter is sqlOverride — the id silently typed as SQL and the
// EXPLAIN button sent the tab UUID to the backend.
expect(appSource).toContain("explain: (tabId: string) => tryExplain(undefined, { tabId }),");
expect(appSource).not.toContain("explain: (tabId: string) => tryExplain(tabId),");
});
it("keeps tryExplain's first parameter an SQL override", () => {
expect(useSqlExecutionSource).toContain("async function tryExplain(sqlOverride?: SqlExecutionOverride, options: SqlExecutionOptions = {})");
});
});
@@ -1,56 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const searchableSelectSource = readFileSync(new URL("../../../components/ui/searchable-select/SearchableSelect.vue", import.meta.url), "utf8");
const editorSettingsDialogSource = readFileSync(new URL("../../../components/editor/EditorSettingsDialog.vue", import.meta.url), "utf8");
const dataTransferDialogSource = readFileSync(new URL("../../../components/transfer/DataTransferDialog.vue", import.meta.url), "utf8");
const editorToolbarSource = readFileSync(new URL("../../../components/layout/EditorToolbar.vue", import.meta.url), "utf8");
const schemaDiffConfigStepSource = readFileSync(new URL("../../../components/diff/SchemaDiffConfigStep.vue", import.meta.url), "utf8");
const dataCompareDialogSource = readFileSync(new URL("../../../components/diff/DataCompareDialog.vue", import.meta.url), "utf8");
describe("SearchableSelect layout", () => {
it("keeps slotted option labels inside a shrinkable overflow boundary", () => {
const labelBoundaries = searchableSelectSource.match(/dbx-searchable-select-option-label min-w-0 flex-1 overflow-hidden/g) ?? [];
expect(labelBoundaries).toHaveLength(3);
});
it("can preserve custom option whitespace for exact database identifiers", () => {
expect(searchableSelectSource).toContain("trimCustom?: boolean");
expect(searchableSelectSource).toContain("trimCustom: true");
expect(searchableSelectSource).toContain("props.trimCustom ? searchText.value.trim() : searchText.value");
});
it("forwards an optional style to its portaled content for local preview isolation", () => {
expect(searchableSelectSource).toContain('contentStyle?: HTMLAttributes["style"]');
expect(searchableSelectSource).toContain(':style="contentStyle"');
expect(editorSettingsDialogSource).toContain(':content-style="{ fontFamily: editUiFontFamily || DEFAULT_UI_FONT_FAMILY }"');
expect(editorSettingsDialogSource).toContain('@option-hover="previewUiFontOption"');
expect(editorSettingsDialogSource).toContain('@option-highlight="previewUiFontOption"');
expect(editorSettingsDialogSource).toContain('@option-leave="restoreUiFontFamilyPreview"');
});
it("renders data transfer connection pickers as sidebar-like trees", () => {
const treeSelects = dataTransferDialogSource.match(/<ConnectionTreeSelect/g) ?? [];
expect(treeSelects).toHaveLength(2);
expect(dataTransferDialogSource).toContain(':layout="store.sidebarLayout"');
expect(dataTransferDialogSource).not.toContain("ConnectionGroupBadge");
});
it("renders the toolbar connection picker as a sidebar-like tree", () => {
expect(editorToolbarSource).toContain("<ConnectionTreeSelect");
expect(editorToolbarSource).toContain(':connections="connectionStore.connections"');
expect(editorToolbarSource).toContain(':layout="connectionStore.sidebarLayout"');
});
it.each([
["schema compare", schemaDiffConfigStepSource],
["data compare", dataCompareDialogSource],
])("renders %s connection pickers as sidebar-like trees", (_name, source) => {
expect(source.match(/<ConnectionTreeSelect/g) ?? []).toHaveLength(2);
expect(source).toContain(':connections="sqlConnections"');
expect(source).toContain(':layout="store.sidebarLayout"');
expect(source).not.toContain("ConnectionGroupBadge");
});
});
@@ -1,13 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const settingsDialogSource = readFileSync(new URL("../../../components/editor/EditorSettingsDialog.vue", import.meta.url), "utf8");
describe("openDataTabsNextToActive settings control", () => {
it("binds the navigation switch through apply and both reset paths", () => {
expect(settingsDialogSource).toContain("const editOpenDataTabsNextToActive = ref(settingsStore.editorSettings.openDataTabsNextToActive)");
expect(settingsDialogSource).toContain("openDataTabsNextToActive: editOpenDataTabsNextToActive.value");
expect(settingsDialogSource.match(/editOpenDataTabsNextToActive\.value = DEFAULT_EDITOR_SETTINGS\.openDataTabsNextToActive/g)).toHaveLength(2);
expect(settingsDialogSource).toContain('id="open-data-tabs-next-to-active" v-model="editOpenDataTabsNextToActive"');
});
});
@@ -1,18 +0,0 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const appSource = readFileSync(new URL("../../../App.vue", import.meta.url), "utf8");
const settingsDialogSource = readFileSync(new URL("../../../components/editor/EditorSettingsDialog.vue", import.meta.url), "utf8");
const changelogPanelSource = readFileSync(new URL("../../../components/settings/ChangelogPanel.vue", import.meta.url), "utf8");
describe("about page update check", () => {
it("reuses the toolbar update check and pending state", () => {
expect(changelogPanelSource).toContain('"check-updates": []');
expect(changelogPanelSource).toContain("@click=\"emit('check-updates')\"");
expect(changelogPanelSource).toContain(':disabled="checkingUpdates"');
expect(settingsDialogSource).toContain(':checking-updates="props.checkingUpdates"');
expect(settingsDialogSource).toContain("@check-updates=\"emit('check-updates')\"");
expect(appSource).toContain(':checking-updates="checkingUpdates"');
expect(appSource).toContain('@check-updates="checkUpdates()"');
});
});