mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-11 09:13:36 +08:00
✅ test(frontend): 同步现有组件行为契约
This commit is contained in:
@@ -4134,7 +4134,6 @@ describe('DataGrid DDL interactions', () => {
|
||||
|
||||
const content = textContent(renderer!.root);
|
||||
expect(content).toContain('SCHEMA DESIGNER');
|
||||
expect(content).toContain('字段');
|
||||
expect(content).toContain('id');
|
||||
expect(content).toContain('name');
|
||||
});
|
||||
@@ -4168,7 +4167,6 @@ describe('DataGrid DDL interactions', () => {
|
||||
|
||||
const content = textContent(renderer!.root);
|
||||
expect(content).toContain('SCHEMA DESIGNER');
|
||||
expect(content).toContain('字段');
|
||||
expect(content).toContain('id');
|
||||
expect(content).toContain('name');
|
||||
});
|
||||
@@ -4256,7 +4254,7 @@ describe('DataGrid DDL interactions', () => {
|
||||
expect(content).not.toContain('gn-v2-data-grid-fields-view');
|
||||
expect(content).toContain('数据预览');
|
||||
expect(content).toContain('结果视图');
|
||||
expect(content).toContain('字段信息');
|
||||
expect(findButton(renderer!, '字段信息')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('keeps the v2 fields tab as read-only field info for views', async () => {
|
||||
@@ -4285,8 +4283,8 @@ describe('DataGrid DDL interactions', () => {
|
||||
});
|
||||
await waitForEffects();
|
||||
|
||||
expect(textContent(renderer!.root)).toContain('字段信息');
|
||||
expect(textContent(renderer!.root)).not.toContain('对象设计');
|
||||
expect(findButton(renderer!, '字段信息')).toBeTruthy();
|
||||
expect(findButton(renderer!, '对象设计')).toBeUndefined();
|
||||
|
||||
await act(async () => {
|
||||
findButton(renderer!, '字段信息').props.onClick();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { getCurrentLanguage, setCurrentLanguage } from '../i18n';
|
||||
import JVMResourceBrowser from './JVMResourceBrowser';
|
||||
|
||||
vi.mock('@monaco-editor/react', () => ({
|
||||
@@ -53,6 +54,17 @@ vi.mock('./jvm/JVMChangePreviewModal', () => ({
|
||||
}));
|
||||
|
||||
describe('JVMResourceBrowser layout', () => {
|
||||
let previousLanguage: ReturnType<typeof getCurrentLanguage>;
|
||||
|
||||
beforeEach(() => {
|
||||
previousLanguage = getCurrentLanguage();
|
||||
setCurrentLanguage('zh-CN');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setCurrentLanguage(previousLanguage);
|
||||
});
|
||||
|
||||
it('renders a dedicated vertical scroll shell for tall snapshot content', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<JVMResourceBrowser
|
||||
|
||||
@@ -954,7 +954,7 @@ describe('Sidebar locate toolbar', () => {
|
||||
expect(source).toContain('refreshGlobalExternalSQLRootNode(false)');
|
||||
expect(source).toContain("request.objectGroup === 'externalSqlFiles'");
|
||||
expect(source).toContain("t('sidebar.message.locate_external_sql_file_not_found', { path: request.filePath })");
|
||||
expect(source).toContain('filePath: data.filePath || undefined');
|
||||
expect(source).toContain('filePath: data.filePath');
|
||||
expect(source).toContain("key: 'add-external-sql-directory'");
|
||||
expect(source).toContain("key: 'new-external-sql-file'");
|
||||
expect(source).toContain("key: 'rename-external-sql-file'");
|
||||
@@ -1645,7 +1645,7 @@ describe('Sidebar locate toolbar', () => {
|
||||
it('remounts the v2 tree when object filters change to avoid rc-tree node reuse drift', () => {
|
||||
const source = readSidebarSource();
|
||||
|
||||
expect(source).toContain("key={isV2Ui ? `v2-tree-${v2ExplorerFilter}` : 'legacy-tree'}");
|
||||
expect(source).toContain("key={`${isV2Ui ? `v2-tree-${v2ExplorerFilter}` : 'legacy-tree'}-${sidebarObjectVisibilitySignature}`}");
|
||||
expect(source).toContain('treeData={isV2Ui ? v2VisibleTreeData : displayTreeData}');
|
||||
});
|
||||
|
||||
@@ -2697,15 +2697,17 @@ describe('Sidebar locate toolbar', () => {
|
||||
|
||||
it('routes v2 database context menu shell copy through i18n wrappers in Sidebar', () => {
|
||||
const source = readSidebarSource();
|
||||
const entityModalsSource = readSourceFile('./sidebar/SidebarEntityModals.tsx');
|
||||
const externalSqlWorkflowSource = readSourceFile('./sidebar/SidebarExternalSqlWorkflow.tsx');
|
||||
const objectActionsSource = readSourceFile('./sidebar/useSidebarObjectActions.tsx');
|
||||
const v2ActionHandlersSource = readSourceFile('./sidebar/useSidebarV2ActionHandlers.tsx');
|
||||
const createSchemaSource = objectActionsSource.slice(
|
||||
objectActionsSource.indexOf('const openCreateSchemaModal = (node: any) => {'),
|
||||
objectActionsSource.indexOf('const openRenameSchemaModal = (node: any) => {'),
|
||||
);
|
||||
const runSqlSource = source.slice(
|
||||
source.indexOf('const handleRunSQLFile = async (node: any) => {'),
|
||||
source.indexOf('const handleOpenSQLFileFromToolbar = async () => {'),
|
||||
const runSqlSource = externalSqlWorkflowSource.slice(
|
||||
externalSqlWorkflowSource.indexOf('const handleRunSQLFile = async (node: any) => {'),
|
||||
externalSqlWorkflowSource.indexOf('const handleOpenSQLFileFromToolbar = async () => {'),
|
||||
);
|
||||
const databaseShellSource = objectActionsSource.slice(
|
||||
objectActionsSource.indexOf('const handleRenameDatabase = async () => {'),
|
||||
@@ -2724,12 +2726,12 @@ describe('Sidebar locate toolbar', () => {
|
||||
expect(createSchemaSource).toContain("message.error(t('sidebar.message.schema_target_missing'))");
|
||||
expect(createSchemaSource).toContain("message.success(t('sidebar.message.schema_created'))");
|
||||
expect(createSchemaSource).toContain("message.error(t('sidebar.message.operation_create_failed'");
|
||||
expect(source).toContain("t('sidebar.v2_database_menu.new_schema')");
|
||||
expect(source).toContain("t('sidebar.field.schema_name')");
|
||||
expect(source).toContain("t('sidebar.validation.schema_name_required')");
|
||||
expect(entityModalsSource).toContain("t('sidebar.v2_database_menu.new_schema')");
|
||||
expect(entityModalsSource).toContain("t('sidebar.field.schema_name')");
|
||||
expect(entityModalsSource).toContain("t('sidebar.validation.schema_name_required')");
|
||||
|
||||
expect(runSqlSource).toContain("message.error(t('sidebar.message.connection_config_not_found'))");
|
||||
expect(runSqlSource).toContain("data.fileName || t('sidebar.sql_file_exec.title')");
|
||||
expect(runSqlSource).toContain("message.warning(t('sidebar.message.select_connection_or_database_first'))");
|
||||
expect(runSqlSource).toContain('fileName: data.fileName');
|
||||
expect(runSqlSource).toContain("message.error(t('sidebar.message.read_file_failed'");
|
||||
|
||||
expect(databaseShellSource).toContain("message.error(t('sidebar.message.database_name_required'))");
|
||||
@@ -2740,9 +2742,9 @@ describe('Sidebar locate toolbar', () => {
|
||||
expect(databaseShellSource).toContain("content: t('sidebar.modal.confirm_delete_database.content', { name: dbName })");
|
||||
expect(databaseShellSource).toContain("message.success(t('sidebar.message.database_deleted'))");
|
||||
expect(databaseShellSource).toContain("message.error(t('sidebar.message.operation_drop_failed'");
|
||||
expect(source).toContain("t('sidebar.modal.rename_database.title'");
|
||||
expect(source).toContain("t('sidebar.field.new_database_name')");
|
||||
expect(source).toContain("t('sidebar.validation.new_database_name_required')");
|
||||
expect(entityModalsSource).toContain("t('sidebar.modal.rename_database.title'");
|
||||
expect(entityModalsSource).toContain("t('sidebar.field.new_database_name')");
|
||||
expect(entityModalsSource).toContain("t('sidebar.validation.new_database_name_required')");
|
||||
|
||||
expect(databaseActionSource).toContain("message.success(t('sidebar.message.database_closed'))");
|
||||
|
||||
@@ -3020,13 +3022,14 @@ describe('Sidebar locate toolbar', () => {
|
||||
|
||||
it('localizes v2 saved-query and external SQL root shell copy', () => {
|
||||
const source = readSidebarSource();
|
||||
const externalSqlWorkflowSource = readSourceFile('./sidebar/SidebarExternalSqlWorkflow.tsx');
|
||||
const legacyMenuSource = readLegacyNodeMenuSource();
|
||||
const loadTablesStart = source.indexOf('const loadTables = async (node: any) => {');
|
||||
const loadTablesEnd = source.indexOf('const config = {', loadTablesStart);
|
||||
const loadTablesSource = source.slice(loadTablesStart, loadTablesEnd);
|
||||
const externalSqlFlowStart = source.indexOf('const handleAddExternalSQLDirectory = async (node: any) => {');
|
||||
const externalSqlFlowEnd = source.indexOf('const cancelSQLFileExecution = () => {', externalSqlFlowStart);
|
||||
const externalSqlFlowSource = source.slice(externalSqlFlowStart, externalSqlFlowEnd);
|
||||
const externalSqlFlowStart = externalSqlWorkflowSource.indexOf('const handleAddExternalSQLDirectory = async (node: any) => {');
|
||||
const externalSqlFlowEnd = externalSqlWorkflowSource.indexOf('\n return {', externalSqlFlowStart);
|
||||
const externalSqlFlowSource = externalSqlWorkflowSource.slice(externalSqlFlowStart, externalSqlFlowEnd);
|
||||
const treeTitleSource = readSourceFile('./sidebar/SidebarTreeTitle.tsx');
|
||||
const treeTitleStart = 0;
|
||||
const treeTitleEnd = treeTitleSource.length;
|
||||
|
||||
@@ -100,6 +100,7 @@ describe('Sidebar nested group menu', () => {
|
||||
editItem.onClick();
|
||||
expect(createTagForm.setFieldsValue).toHaveBeenLastCalledWith({
|
||||
name: 'Group 1',
|
||||
environmentType: 'local',
|
||||
parentTagId: 'root',
|
||||
connectionIds: ['host-1'],
|
||||
});
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('TabManager hover info', () => {
|
||||
it('memoizes the tab workbench so parent-only modal state does not repaint open tabs', () => {
|
||||
const source = readFileSync(new URL('./TabManager.tsx', import.meta.url), 'utf8');
|
||||
|
||||
expect(source).toContain('const TabManager: React.FC = React.memo(() => {');
|
||||
expect(source).toContain('const TabManager: React.FC<TabManagerProps> = React.memo<TabManagerProps>(({ onFocusSidebarSearch }) => {');
|
||||
});
|
||||
|
||||
it('routes the workspace close command through the docked active tab close coordinator', () => {
|
||||
@@ -473,7 +473,8 @@ describe('TabManager hover info', () => {
|
||||
expect(source).not.toContain(text);
|
||||
});
|
||||
expect(source).toContain('confirmDirtyTabsOrClose();');
|
||||
expect(source).toContain("getSQLFileTabDraft(tab.id, String(tab.query ?? ''))");
|
||||
expect(source).toContain('const latestTab = useStore.getState().tabs.find((candidate) => candidate.id === tab.id);');
|
||||
expect(source).toContain("String(latestTab?.query ?? tab.query ?? '')");
|
||||
expect(source).toContain('hasSQLFileTabUnsavedChanges({ ...tab, query: draft }, normalizeSQLFileReadContent(res.data))');
|
||||
expect(source).toContain('WriteSQLFile(filePath, draft)');
|
||||
expect(source).toContain('clearSQLFileTabDraft(tab.id)');
|
||||
|
||||
@@ -142,12 +142,18 @@ describe("connectionModalConfig keepalive", () => {
|
||||
expect(config.keepAliveSQL).toBe("");
|
||||
});
|
||||
|
||||
it("persists readOnly only for datasource types that support production guard", async () => {
|
||||
it("persists protection only for datasource types that support production guard", async () => {
|
||||
const protection = {
|
||||
restrictDataEdit: true,
|
||||
restrictStructureEdit: true,
|
||||
restrictScriptExecution: true,
|
||||
restrictDataImport: true,
|
||||
};
|
||||
const sqlConfig = await buildConnectionConfig({
|
||||
values: {
|
||||
...buildBaseValues(),
|
||||
type: "postgres",
|
||||
readOnly: true,
|
||||
...protection,
|
||||
},
|
||||
forPersist: true,
|
||||
translate,
|
||||
@@ -157,13 +163,15 @@ describe("connectionModalConfig keepalive", () => {
|
||||
...buildBaseValues(),
|
||||
type: "redis",
|
||||
port: 6379,
|
||||
readOnly: true,
|
||||
...protection,
|
||||
},
|
||||
forPersist: true,
|
||||
translate,
|
||||
});
|
||||
|
||||
expect(sqlConfig.protection).toEqual(protection);
|
||||
expect(sqlConfig.readOnly).toBe(true);
|
||||
expect(redisConfig.protection).toBeUndefined();
|
||||
expect(redisConfig.readOnly).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user