diff --git a/jest.config.js b/jest.config.js index d0cb5171b..5cf3c846c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -31,6 +31,12 @@ module.exports = { '@uiw/react-md-editor': '/packages/shared/lib/testUtil/mockEditor.jsx', '@actiontech/(.*)': '/packages/$1', + '@react-sigma/core(.*)$': + '/packages/shared/lib/testUtil/mockSigmaCore.tsx', + '@react-sigma/graph-search$': + '/packages/shared/lib/testUtil/mockSigmaGraphSearch.tsx', + '@sigma/node-image$': + '/packages/shared/lib/testUtil/mockSigmaNodeImage.tsx', ...pathsToModuleNameMapper(compilerOptions.paths) }, collectCoverageFrom: [ diff --git a/packages/shared/lib/testUtil/mockSigmaCore.tsx b/packages/shared/lib/testUtil/mockSigmaCore.tsx new file mode 100644 index 000000000..40237b9c7 --- /dev/null +++ b/packages/shared/lib/testUtil/mockSigmaCore.tsx @@ -0,0 +1,43 @@ +const mockSigmaGraph = { + addNode: jest.fn(), + addEdge: jest.fn(), + clear: jest.fn(), + dropNode: jest.fn(), + dropEdge: jest.fn(), + getNodeAttributes: jest.fn(), + getEdgeAttributes: jest.fn(), + forEachNode: jest.fn(), + forEachEdge: jest.fn() +}; + +const mockSigma = { + getGraph: jest.fn(() => mockSigmaGraph), + getCamera: jest.fn(() => ({ + animate: jest.fn(), + goTo: jest.fn(), + reset: jest.fn() + })), + refresh: jest.fn(), + kill: jest.fn() +}; + +export const SigmaContainer = jest.fn(({ children }) => ( +
{children}
+)); + +export const ControlsContainer = jest.fn(({ children }) => ( +
{children}
+)); + +export const FullScreenControl = jest.fn(({ children }) => ( +
{children}
+)); + +export const ZoomControl = jest.fn(({ children }) => ( +
{children}
+)); + +export const useLoadGraph = jest.fn(); +export const useRegisterEvents = jest.fn(); +export const useSigma = jest.fn(() => mockSigma); +export const useSetSettings = jest.fn(); diff --git a/packages/shared/lib/testUtil/mockSigmaGraphSearch.tsx b/packages/shared/lib/testUtil/mockSigmaGraphSearch.tsx new file mode 100644 index 000000000..d595c5bc1 --- /dev/null +++ b/packages/shared/lib/testUtil/mockSigmaGraphSearch.tsx @@ -0,0 +1,3 @@ +export const GraphSearch = jest.fn(({ children }) => ( +
{children}
+)); diff --git a/packages/shared/lib/testUtil/mockSigmaNodeImage.tsx b/packages/shared/lib/testUtil/mockSigmaNodeImage.tsx new file mode 100644 index 000000000..572c7248f --- /dev/null +++ b/packages/shared/lib/testUtil/mockSigmaNodeImage.tsx @@ -0,0 +1 @@ +export const NodeImageProgram = () => null; diff --git a/packages/shared/lib/utils/Common.ts b/packages/shared/lib/utils/Common.ts index 56c184f77..f97b7ae1d 100644 --- a/packages/shared/lib/utils/Common.ts +++ b/packages/shared/lib/utils/Common.ts @@ -2,6 +2,7 @@ import { AxiosResponse } from 'axios'; import i18n from 'i18next'; import { MIMETypeEnum, ResponseBlobJsonType } from '../enum'; import dayjs, { Dayjs } from 'dayjs'; +import queryString from 'query-string'; export const emailValidate = (email: string): boolean => { if (!email || typeof email !== 'string') { @@ -190,3 +191,9 @@ export const getCookie = (name: string): string => { } return ''; }; + +export const paramsSerializer = >(query: T) => { + return queryString.stringify(query, { + arrayFormat: 'none' + }); +}; diff --git a/packages/shared/lib/utils/__tests__/Common.test.ts b/packages/shared/lib/utils/__tests__/Common.test.ts index 2191dc510..cd3ca3793 100644 --- a/packages/shared/lib/utils/__tests__/Common.test.ts +++ b/packages/shared/lib/utils/__tests__/Common.test.ts @@ -13,7 +13,8 @@ import { getFileFromUploadChangeEvent, jsonParse, translateTimeForRequest, - findDuplicateKeys + findDuplicateKeys, + paramsSerializer } from '../Common'; import { act } from '@testing-library/react'; import 'blob-polyfill'; @@ -332,4 +333,9 @@ describe('utils/Common', () => { expect(result).toEqual([]); }); }); + + it('should stringify params', () => { + expect(paramsSerializer({ a: 1, b: 2 })).toBe('a=1&b=2'); + expect(paramsSerializer({ a: 1, b: [2, 3, 4] })).toBe('a=1&b=2&b=3&b=4'); + }); }); diff --git a/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/__tests__/index.test.tsx b/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/__tests__/index.test.tsx index 446a91b6a..ba19d7d79 100644 --- a/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/__tests__/index.test.tsx +++ b/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/__tests__/index.test.tsx @@ -10,7 +10,7 @@ import { getGlobalWorkflowsV1FilterStatusListEnum } from '@actiontech/shared/lib import { ListProjectProjectPriorityEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; import eventEmitter from '../../../../../utils/EventEmitter'; import EmitterKey from '../../../../../data/EmitterKey'; -import { paramsSerializer } from '../../../utils'; +import { paramsSerializer } from '@actiontech/shared'; describe('sqle/GlobalDashboard/InitiatedWorkOrder', () => { let getGlobalWorkflowsSpy: jest.SpyInstance; diff --git a/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/index.tsx b/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/index.tsx index 1ced38913..3f4ac8fcb 100644 --- a/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/index.tsx +++ b/packages/sqle/src/page/GlobalDashboard/List/InitiatedWorkOrder/index.tsx @@ -17,7 +17,7 @@ import { import { GlobalDashboardListProps } from '../../index.type'; import { GlobalDashboardPendingWorkflowListColumn } from '../PendingWorkOrder/column'; import { useCurrentUser } from '@actiontech/shared/lib/features'; -import { paramsSerializer } from '../../utils'; +import { paramsSerializer } from '@actiontech/shared'; const InitiatedWorkOrder: React.FC = ({ filterValues, diff --git a/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/__tests__/index.test.tsx b/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/__tests__/index.test.tsx index af4547cb9..471ad605e 100644 --- a/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/__tests__/index.test.tsx +++ b/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/__tests__/index.test.tsx @@ -10,7 +10,7 @@ import { getGlobalWorkflowsV1FilterStatusListEnum } from '@actiontech/shared/lib import { ListProjectProjectPriorityEnum } from '@actiontech/shared/lib/api/base/service/common.enum'; import eventEmitter from '../../../../../utils/EventEmitter'; import EmitterKey from '../../../../../data/EmitterKey'; -import { paramsSerializer } from '../../../utils'; +import { paramsSerializer } from '@actiontech/shared'; describe('sqle/GlobalDashboard/PendingWorkOrder', () => { let getGlobalWorkflowsSpy: jest.SpyInstance; diff --git a/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/index.tsx b/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/index.tsx index 77eeb60e9..5c520c825 100644 --- a/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/index.tsx +++ b/packages/sqle/src/page/GlobalDashboard/List/PendingWorkOrder/index.tsx @@ -16,7 +16,7 @@ import { } from '@actiontech/shared/lib/api/sqle/service/workflow/index.enum'; import { GlobalDashboardListProps } from '../../index.type'; import { GlobalDashboardPendingWorkflowListColumn } from './column'; -import { paramsSerializer } from '../../utils'; +import { paramsSerializer } from '@actiontech/shared'; const PendingWorkOrder: React.FC = ({ filterValues, diff --git a/packages/sqle/src/page/GlobalDashboard/hooks/useDashboardFilter.ts b/packages/sqle/src/page/GlobalDashboard/hooks/useDashboardFilter.ts index 943ba988b..376fa9afa 100644 --- a/packages/sqle/src/page/GlobalDashboard/hooks/useDashboardFilter.ts +++ b/packages/sqle/src/page/GlobalDashboard/hooks/useDashboardFilter.ts @@ -12,7 +12,7 @@ import { } from '@actiontech/shared/lib/api/sqle/service/workflow/index.enum'; import { useRequest } from 'ahooks'; import { ResponseCode } from '@actiontech/shared/lib/enum'; -import { paramsSerializer } from '../utils'; +import { paramsSerializer } from '@actiontech/shared'; import { useBoolean } from 'ahooks'; const useDashboardFilter = () => { diff --git a/packages/sqle/src/page/GlobalDashboard/utils.ts b/packages/sqle/src/page/GlobalDashboard/utils.ts deleted file mode 100644 index ae9376ffc..000000000 --- a/packages/sqle/src/page/GlobalDashboard/utils.ts +++ /dev/null @@ -1,7 +0,0 @@ -import queryString from 'query-string'; -import { IGetGlobalWorkflowsV1Params } from '@actiontech/shared/lib/api/sqle/service/workflow/index.d'; - -export const paramsSerializer = (params: IGetGlobalWorkflowsV1Params) => - queryString.stringify(params, { - arrayFormat: 'none' - }); diff --git a/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/TagSelectorBar.test.tsx b/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/TagSelectorBar.test.tsx new file mode 100644 index 000000000..2f67ae6a2 --- /dev/null +++ b/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/TagSelectorBar.test.tsx @@ -0,0 +1,72 @@ +import { act, cleanup, screen, fireEvent } from '@testing-library/react'; +import TagSelectorBar from '../TagSelectorBar'; +import { superRender } from '../../../../../testUtils/customRender'; +import knowledgeBase from '../../../../../testUtils/mockApi/knowledgeBase'; +import { mockKnowledgeBaseTagListData } from '../../../../../testUtils/mockApi/knowledgeBase/data'; +import { + getAllBySelector, + getBySelector +} from '@actiontech/shared/lib/testUtil/customQuery'; + +describe('TagSelectorBar', () => { + let getKnowledgeBaseTagList: jest.SpyInstance; + + beforeEach(() => { + jest.useFakeTimers(); + getKnowledgeBaseTagList = knowledgeBase.getKnowledgeBaseTagList(); + }); + + afterEach(() => { + jest.useRealTimers(); + cleanup(); + }); + + it('render init snap', () => { + const { container } = superRender( + + ); + expect(container).toMatchSnapshot(); + expect(getKnowledgeBaseTagList).toHaveBeenCalled(); + }); + + it('render select tag', async () => { + const onChangeSpy = jest.fn(); + const { baseElement } = superRender( + + ); + expect(getKnowledgeBaseTagList).toHaveBeenCalledTimes(1); + await act(async () => jest.advanceTimersByTime(3000)); + fireEvent.click(screen.getByText('已选择标签(0)')); + await act(async () => jest.advanceTimersByTime(0)); + expect(baseElement).toMatchSnapshot(); + + fireEvent.change(getBySelector('.ant-input'), { + target: { + value: 'rand' + } + }); + await act(async () => jest.advanceTimersByTime(0)); + expect(screen.getByText('RAND')).toBeInTheDocument(); + expect(getAllBySelector('.hidden-checkbox')).toHaveLength( + mockKnowledgeBaseTagListData.length - 1 + ); + fireEvent.click(getAllBySelector('.ant-checkbox-input')[0]); + await act(async () => jest.advanceTimersByTime(0)); + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith(['RAND']); + }); + + it('render delete tag', async () => { + const onChangeSpy = jest.fn(); + superRender(); + expect(getKnowledgeBaseTagList).toHaveBeenCalledTimes(1); + await act(async () => jest.advanceTimersByTime(3000)); + expect(screen.getByText('已选择标签(1)')).toBeInTheDocument(); + expect(screen.getByText('RAND')).toBeInTheDocument(); + + fireEvent.click(getBySelector('.anticon-close')); + await act(async () => jest.advanceTimersByTime(0)); + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith([]); + }); +}); diff --git a/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/__snapshots__/TagSelectorBar.test.tsx.snap b/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/__snapshots__/TagSelectorBar.test.tsx.snap new file mode 100644 index 000000000..d30627b31 --- /dev/null +++ b/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/__snapshots__/TagSelectorBar.test.tsx.snap @@ -0,0 +1,335 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TagSelectorBar render init snap 1`] = ` +
+
+
+
+ + 已选择标签 + ( + 1 + ) + + + + +
+
+
+ + RAND + + + + +
+
+
+`; + +exports[`TagSelectorBar render select tag 1`] = ` + +
+
+
+
+ + 已选择标签 + ( + 0 + ) + + + + +
+
+
+
+
+
+
+ +
+
+
+ +`; diff --git a/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/__snapshots__/index.test.tsx.snap b/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000..b19fa79a9 --- /dev/null +++ b/packages/sqle/src/page/Knowledge/Common/KnowledgeSearchBar/__tests__/__snapshots__/index.test.tsx.snap @@ -0,0 +1,96 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`KnowledgeSearchBar render init snap 1`] = ` +
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
    +
  • +
    +
    +

    +
    + + SQL绑定的变量个数不建议超过阈值 + +
    +

    +
    +
    +
    + + 过度使用绑定变量会增加查询的复杂度,从而降低查询性能。同时还会增加维护成本。SQLE设置MySQL绑定变量个数最大阈值:100 + +
    +
    +
    +
    + + + SELECT + + + * FROM test_table WHERE col1 = ? AND col2 = + +
    +
    +
    +
  • +
  • +
    +
    +

    +
    + + 建议为组成索引的字段添加非空约束,并配置合理的default值 + +
    +

    +
    +
    +
    + + 在MySQL中,NULL值表示的含义为missing unknown value,在不同的场景下MySQL存在不同的处理方式;当字段内容存在NULL值时,处理结果可能存在异常 + +
    +
    +
    +
    + + + SELECT + + + COUNT(*), COUNT(age) FROM person; + +-- + +
    +
    +
    +
  • +
+
+
+
+
    +
  • + + 共 30 条数据 + +
  • +
  • + +
  • +
  • + + 1 + +
  • +
  • + + 2 + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+ + + +