4.8.11 test (#2843)

* feat: app version test

* update doc

* fix: paging num error

* fix: doc api domain

* rename variable

* perf: memment node min size
This commit is contained in:
Archer
2024-09-30 17:28:03 +08:00
committed by GitHub
parent 7c829febec
commit 7c38d1da9a
39 changed files with 427 additions and 179 deletions

View File

@@ -57,11 +57,25 @@ jest.mock('@/service/middleware/entry', () => {
});
beforeAll(async () => {
// 新建一个内存数据库,然后让 mongoose 连接这个数据库
if (!global.mongod || !global.mongodb) {
const mongod = await MongoMemoryServer.create();
global.mongod = mongod;
global.mongodb = mongoose;
await global.mongodb.connect(mongod.getUri());
await global.mongodb.connect(mongod.getUri(), {
bufferCommands: true,
maxConnecting: 50,
maxPoolSize: 50,
minPoolSize: 20,
connectTimeoutMS: 60000,
waitQueueTimeoutMS: 60000,
socketTimeoutMS: 60000,
maxIdleTimeMS: 300000,
retryWrites: true,
retryReads: true
});
await initMockData();
}
});

View File

@@ -13,34 +13,37 @@ export const root = {
};
export const initMockData = async () => {
// init root user
const rootUser = await MongoUser.create({
username: 'root',
password: '123456'
});
const initRootUser = async () => {
// init root user
const rootUser = await MongoUser.create({
username: 'root',
password: '123456'
});
const rootTeam = await MongoTeam.create({
name: 'root-default-team',
ownerId: rootUser._id
});
const rootTeam = await MongoTeam.create({
name: 'root-default-team',
ownerId: rootUser._id
});
const rootTeamMember = await MongoTeamMember.create({
teamId: rootTeam._id,
userId: rootUser._id,
name: 'root-default-team-member',
status: 'active',
role: TeamMemberRoleEnum.owner
});
const rootTeamMember = await MongoTeamMember.create({
teamId: rootTeam._id,
userId: rootUser._id,
name: 'root-default-team-member',
status: 'active',
role: TeamMemberRoleEnum.owner
});
const rootApp = await MongoApp.create({
name: 'root-default-app',
teamId: rootTeam._id,
tmbId: rootTeam._id,
type: 'advanced'
});
const rootApp = await MongoApp.create({
name: 'root-default-app',
teamId: rootTeam._id,
tmbId: rootTeam._id,
type: 'advanced'
});
root.uid = rootUser._id;
root.tmbId = rootTeamMember._id;
root.teamId = rootTeam._id;
root.appId = rootApp._id;
};
root.uid = rootUser._id;
root.tmbId = rootTeamMember._id;
root.teamId = rootTeam._id;
root.appId = rootApp._id;
await initRootUser();
};

View File

@@ -0,0 +1,55 @@
import '@/pages/api/__mocks__/base';
import { root } from '@/pages/api/__mocks__/db/init';
import { getTestRequest } from '@/test/utils';
import handler, { getLatestVersionQuery, getLatestVersionResponse } from './latest';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
beforeAll(async () => {
// 创建3个测试数据其中2个是已发布的
await MongoAppVersion.create([
{
appId: root.appId,
nodes: [1],
edges: [],
chatConfig: {},
isPublish: false,
versionName: 'v1',
tmbId: root.tmbId,
time: new Date('2023-01-01')
},
{
appId: root.appId,
nodes: [2],
edges: [],
chatConfig: {},
isPublish: true,
versionName: 'v2',
tmbId: root.tmbId,
time: new Date('2023-01-02')
},
{
appId: root.appId,
nodes: [3],
edges: [],
chatConfig: {},
isPublish: false,
versionName: 'v3',
tmbId: root.tmbId,
time: new Date('2023-01-03')
}
]);
});
test('获取最新版本并检查', async () => {
const _res = (await handler(
...getTestRequest<{}, getLatestVersionQuery>({
query: {
appId: root.appId
},
user: root
})
)) as any;
const res = _res.data as getLatestVersionResponse;
expect(res.nodes[0]).toEqual(2);
});

View File

@@ -0,0 +1,37 @@
import '@/pages/api/__mocks__/base';
import { root } from '@/pages/api/__mocks__/db/init';
import { getTestRequest } from '@/test/utils';
import handler from './publish';
import { MongoAppVersion } from '@fastgpt/service/core/app/version/schema';
import { PostPublishAppProps } from '@/global/core/app/api';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
describe('发布应用版本测试', () => {
test('发布一个未发布的版本', async () => {
const publishData: PostPublishAppProps = {
nodes: [],
edges: [],
chatConfig: {},
type: AppTypeEnum.simple,
isPublish: false,
versionName: '1'
};
await handler(
...getTestRequest<{ appId: string }, PostPublishAppProps>({
body: publishData,
query: { appId: root.appId },
user: root
})
);
// 检查数据库是否插入成功
const insertedVersion = await MongoAppVersion.countDocuments();
console.log(insertedVersion, '==-');
// expect(insertedVersion).toBeTruthy();
// expect(insertedVersion?.isPublish).toBe(false);
// expect(insertedVersion?.versionName).toBe('1');
});
});

View File

@@ -8,7 +8,6 @@ import { beforeUpdateAppFormat } from '@fastgpt/service/core/app/controller';
import { getNextTimeByCronStringAndTimezone } from '@fastgpt/global/common/string/time';
import { PostPublishAppProps } from '@/global/core/app/api';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<{}> {
const { appId } = req.query as { appId: string };

View File

@@ -9,7 +9,7 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'react-i18next';
const NodeComment = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const NodeComment = ({ data }: NodeProps<FlowNodeItemType>) => {
const { nodeId, inputs } = data;
const { commentText, commentSize } = useMemo(
() => ({
@@ -39,8 +39,8 @@ const NodeComment = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const deltaY = e.clientY - initialY.current;
const deltaX = e.clientX - initialX.current;
setSize((prevSize) => ({
width: prevSize.width + deltaX < 240 ? 240 : prevSize.width + deltaX,
height: prevSize.height + deltaY < 140 ? 140 : prevSize.height + deltaY
width: prevSize.width + deltaX < 120 ? 120 : prevSize.width + deltaX,
height: prevSize.height + deltaY < 60 ? 60 : prevSize.height + deltaY
}));
initialY.current = e.clientY;
initialX.current = e.clientX;
@@ -70,59 +70,63 @@ const NodeComment = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
[commentSize, nodeId, onChangeNode, size.height, size.width]
);
return (
<NodeCard
selected={false}
{...data}
minW={`${size.width}px`}
minH={`${size.height}px`}
menuForbid={{
debug: true
}}
border={'none'}
rounded={'none'}
bg={'#D8E9FF'}
boxShadow={
'0px 4px 10px 0px rgba(19, 51, 107, 0.10), 0px 0px 1px 0px rgba(19, 51, 107, 0.10)'
}
>
<Box w={'full'} h={'full'} position={'relative'}>
<Box
position={'absolute'}
right={'0'}
bottom={'-2'}
zIndex={9}
cursor={'nwse-resize'}
px={'2px'}
className="nodrag"
onMouseDown={handleMouseDown}
>
<MyIcon name={'common/editor/resizer'} width={'14px'} height={'14px'} />
const Render = useMemo(() => {
return (
<NodeCard
selected={false}
{...data}
minW={`${size.width}px`}
minH={`${size.height}px`}
menuForbid={{
debug: true
}}
border={'none'}
rounded={'none'}
bg={'#D8E9FF'}
boxShadow={
'0px 4px 10px 0px rgba(19, 51, 107, 0.10), 0px 0px 1px 0px rgba(19, 51, 107, 0.10)'
}
>
<Box w={'full'} h={'full'} position={'relative'}>
<Box
position={'absolute'}
right={'0'}
bottom={'-2'}
zIndex={9}
cursor={'nwse-resize'}
px={'2px'}
className="nodrag"
onMouseDown={handleMouseDown}
>
<MyIcon name={'common/editor/resizer'} width={'14px'} height={'14px'} />
</Box>
<Textarea
value={commentText?.value}
border={'none'}
rounded={'none'}
minH={`${size.height}px`}
minW={`${size.width}px`}
resize={'none'}
placeholder={t('workflow:enter_comment')}
onChange={(e) => {
commentText &&
onChangeNode({
nodeId: nodeId,
type: 'updateInput',
key: NodeInputKeyEnum.commentText,
value: {
...commentText,
value: e.target.value
}
});
}}
/>
</Box>
<Textarea
value={commentText?.value}
border={'none'}
rounded={'none'}
minH={`${size.height}px`}
minW={`${size.width}px`}
resize={'none'}
placeholder={t('workflow:enter_comment')}
onChange={(e) => {
commentText &&
onChangeNode({
nodeId: nodeId,
type: 'updateInput',
key: NodeInputKeyEnum.commentText,
value: {
...commentText,
value: e.target.value
}
});
}}
/>
</Box>
</NodeCard>
);
</NodeCard>
);
}, [commentText, data, handleMouseDown, nodeId, onChangeNode, size.height, size.width, t]);
return Render;
};
export default React.memo(NodeComment);

View File

@@ -14,7 +14,7 @@ import { useForm } from 'react-hook-form';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { useTranslation } from 'next-i18next';
import MySelect from '@fastgpt/web/components/common/MySelect';
import { fnValueTypeSelect } from '@/web/core/workflow/constants/dataType';
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
@@ -82,7 +82,7 @@ const ExtractFieldModal = ({
</FormLabel>
<Box flex={'1 0 0'}>
<MySelect<string>
list={fnValueTypeSelect}
list={toolValueTypeList}
value={valueType}
onchange={(e) => {
setValue('valueType', e as any);

View File

@@ -1,4 +1,4 @@
import { fnValueTypeSelect } from '@/web/core/workflow/constants/dataType';
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
import { Box, Button, Flex, Input, ModalBody, ModalFooter, Textarea } from '@chakra-ui/react';
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
import MyModal from '@fastgpt/web/components/common/MyModal';
@@ -121,7 +121,7 @@ const ToolParamsEditModal = ({
<FormLabel flex={'0 0 80px'}>{t('common:core.module.Data Type')}</FormLabel>
<Box flex={'1 0 0'}>
<MySelect
list={fnValueTypeSelect}
list={toolValueTypeList}
value={valueType}
onchange={(e: any) => {
setValue('valueType', e);

View File

@@ -36,7 +36,7 @@ const NodeToolParams = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
<NodeCard selected={selected} {...data}>
<Container>
<Flex alignItems={'center'} justifyContent={'space-between'} mb={1.5}>
<FormLabel>{t('workflow:custom_tool_input')}</FormLabel>
<FormLabel>{t('workflow:tool_custom_field')}</FormLabel>
<Button
variant={'whiteBase'}
leftIcon={<SmallAddIcon />}

View File

@@ -6,7 +6,6 @@ import Divider from '../components/Divider';
import Container from '../components/Container';
import RenderInput from './render/RenderInput';
import { useTranslation } from 'next-i18next';
import { ToolSourceHandle } from './render/Handle/ToolHandle';
import { Box } from '@chakra-ui/react';
import IOTitle from '../components/IOTitle';
import MyIcon from '@fastgpt/web/components/common/Icon';

View File

@@ -19,7 +19,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
import { fnValueTypeSelect } from '@/web/core/workflow/constants/dataType';
import { toolValueTypeList } from '@fastgpt/global/core/workflow/constants';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
@@ -95,7 +95,7 @@ const EditFieldModal = ({
<Box flex={'0 0 80px'}>{t('common:core.module.Data Type')}</Box>
<Box flex={'1 0 0'}>
<MySelect
list={fnValueTypeSelect}
list={toolValueTypeList}
value={valueType}
onchange={(e: any) => {
setValue('valueType', e);
@@ -150,7 +150,7 @@ export const defaultEditFormData: FlowNodeInputItemType = {
required: true,
canEdit: true,
customInputConfig: {
selectValueTypeList: Object.values(fnValueTypeSelect).map((item) => item.value),
selectValueTypeList: Object.values(toolValueTypeList).map((item) => item.value),
showDescription: true
}
};

View File

@@ -15,7 +15,6 @@ import {
putDatasetCollectionById
} from '@/web/core/dataset/api';
import { useQuery } from '@tanstack/react-query';
import { debounce } from 'lodash';
import { useTranslation } from 'next-i18next';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyInput from '@/components/MyInput';

View File

@@ -69,7 +69,7 @@ const Detail = ({ datasetId, currentTab }: Props) => {
<Flex h={'100%'} py={3} pl={1} pr={3} gap={2}>
<Flex flex={1} w={0} bg={'white'} flexDir={'column'} boxShadow={'2'} borderRadius={'md'}>
{currentTab !== TabEnum.import && <NavBar currentTab={currentTab} />}
<Box flex={'1'} overflow={'auto'}>
<Box flex={'1'} overflowY={'auto'}>
{currentTab === TabEnum.collectionCard && (
<CollectionPageContextProvider>
<CollectionCard />

View File

@@ -31,8 +31,8 @@ export function getTestRequest<Q = any, B = any>({
// authApiKey = false,
user
}: {
body?: Partial<B>;
query?: Partial<Q>;
body?: Partial<B>;
authToken?: boolean;
authRoot?: boolean;
authApiKey?: boolean;

View File

@@ -1,28 +0,0 @@
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
export const fnValueTypeSelect = [
{
label: WorkflowIOValueTypeEnum.string,
value: WorkflowIOValueTypeEnum.string
},
{
label: WorkflowIOValueTypeEnum.number,
value: WorkflowIOValueTypeEnum.number
},
{
label: WorkflowIOValueTypeEnum.boolean,
value: WorkflowIOValueTypeEnum.boolean
},
{
label: 'array<string>',
value: WorkflowIOValueTypeEnum.arrayString
},
{
label: 'array<number>',
value: WorkflowIOValueTypeEnum.arrayNumber
},
{
label: 'array<boolean>',
value: WorkflowIOValueTypeEnum.arrayBoolean
}
];

View File

@@ -1,4 +1,4 @@
export const strToBase64 = (str: string, prefix: string) => {
export const strToBase64 = (str: string, prefix: string = '') => {
const base64_string = Buffer.from(str, 'utf-8').toString('base64');
return `${prefix}${base64_string}`;