feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { workflowApi as archWorkflowApi } from '@coze-arch/bot-api';
import { workflowApi, workflowQueryClient } from '../../src/api';
vi.mock('@coze-arch/bot-api', () => ({
workflowApi: {
GetHistorySchema: vi.fn(),
GetWorkFlowProcess: vi.fn(),
GetCanvasInfo: vi.fn(),
OPGetHistorySchema: vi.fn(),
OPGetWorkFlowProcess: vi.fn(),
OPGetCanvasInfo: vi.fn(),
},
}));
const mockParams = {
space_id: '123',
workflow_id: '456',
commit_id: '789',
type: 1,
};
describe('api/index.ts', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should export workflowApi', () => {
expect(workflowApi).toBeDefined();
});
it('should export workflowQueryClient', () => {
expect(workflowQueryClient).toBeDefined();
});
describe('workflowApi proxy', () => {
it('should call original API methods in non-OP environment', () => {
// @ts-expect-error IS_BOT_OP is a global variable defined in runtime
global.IS_BOT_OP = false;
workflowApi.GetHistorySchema(mockParams);
expect(archWorkflowApi.GetHistorySchema).toHaveBeenCalledWith(mockParams);
workflowApi.GetWorkFlowProcess({
space_id: mockParams.space_id,
workflow_id: mockParams.workflow_id,
});
expect(archWorkflowApi.GetWorkFlowProcess).toHaveBeenCalledWith({
space_id: mockParams.space_id,
workflow_id: mockParams.workflow_id,
});
workflowApi.GetCanvasInfo({ space_id: mockParams.space_id });
expect(archWorkflowApi.GetCanvasInfo).toHaveBeenCalledWith({
space_id: mockParams.space_id,
});
});
it('should call OP API methods in OP environment', () => {
// @ts-expect-error IS_BOT_OP is a global variable defined in runtime
global.IS_BOT_OP = true;
workflowApi.GetHistorySchema(mockParams);
expect(archWorkflowApi.OPGetHistorySchema).toHaveBeenCalledWith(
mockParams,
);
workflowApi.GetWorkFlowProcess({
space_id: mockParams.space_id,
workflow_id: mockParams.workflow_id,
});
expect(archWorkflowApi.OPGetWorkFlowProcess).toHaveBeenCalledWith({
space_id: mockParams.space_id,
workflow_id: mockParams.workflow_id,
});
workflowApi.GetCanvasInfo({ space_id: mockParams.space_id });
expect(archWorkflowApi.OPGetCanvasInfo).toHaveBeenCalledWith({
space_id: mockParams.space_id,
});
});
});
});

View File

@@ -0,0 +1,214 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, waitFor } from '@testing-library/react';
import { useQuery } from '@tanstack/react-query';
import {
workflowQueryClient,
withQueryClient,
} from '../../src/api/with-query-client';
describe('with-query-client.tsx', () => {
beforeEach(() => {
// 清理 QueryClient 缓存
workflowQueryClient.clear();
});
describe('workflowQueryClient', () => {
it('should export a QueryClient instance', () => {
expect(workflowQueryClient).toBeDefined();
expect(workflowQueryClient.constructor.name).toBe('QueryClient');
});
it('should have default configuration', () => {
const defaultOptions = workflowQueryClient.getDefaultOptions();
expect(defaultOptions).toBeDefined();
});
it('should be able to manage queries', async () => {
const queryKey = ['test'];
const queryFn = vi.fn().mockResolvedValue('test data');
const result = await workflowQueryClient.fetchQuery({
queryKey,
queryFn,
});
expect(result).toBe('test data');
expect(queryFn).toHaveBeenCalled();
expect(workflowQueryClient.getQueryData(queryKey)).toBe('test data');
});
});
describe('withQueryClient', () => {
it('should wrap component with QueryClientProvider', () => {
const TestComponent = () => <div>Test Component</div>;
const WrappedComponent = withQueryClient(TestComponent);
const { container } = render(<WrappedComponent />);
expect(container.innerHTML).toContain('Test Component');
});
it('should pass props to wrapped component', () => {
const TestComponent = ({ text }: { text: string }) => <div>{text}</div>;
const WrappedComponent = withQueryClient(TestComponent);
const { container } = render(<WrappedComponent text="Hello" />);
expect(container.innerHTML).toContain('Hello');
});
it('should provide QueryClient context to wrapped component', async () => {
const queryKey = ['test'];
const queryFn = vi.fn().mockResolvedValue('test data');
const TestComponent = () => {
const { data, isLoading } = useQuery({ queryKey, queryFn });
if (isLoading) {
return <div>Loading...</div>;
}
return <div>{data}</div>;
};
const WrappedComponent = withQueryClient(TestComponent);
const { container } = render(<WrappedComponent />);
// 初始加载状态
expect(container.innerHTML).toContain('Loading...');
// 等待数据加载完成
await waitFor(() => {
expect(container.innerHTML).toContain('test data');
});
expect(queryFn).toHaveBeenCalledTimes(1);
});
it('should handle query errors gracefully', () => {
const queryKey = ['test-error'];
const queryFn = vi.fn().mockRejectedValue(new Error('Test error'));
const TestComponent = () => {
const { error, isError } = useQuery({ queryKey, queryFn });
if (isError) {
return <div>Error: {error.message}</div>;
}
return <div>Loading...</div>;
};
const WrappedComponent = withQueryClient(TestComponent);
render(<WrappedComponent />);
expect(queryFn).toHaveBeenCalledTimes(1);
});
it('should maintain component type and handle complex props', () => {
interface ComplexProps {
text: string;
count: number;
items: string[];
onClick: () => void;
}
const TestComponent: React.FC<ComplexProps> = ({
text,
count,
items,
onClick,
}) => (
<div onClick={onClick}>
<span>{text}</span>
<span>{count}</span>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
const WrappedComponent = withQueryClient(TestComponent);
const handleClick = vi.fn();
const { container } = render(
<WrappedComponent
text="Complex Test"
count={42}
items={['a', 'b', 'c']}
onClick={handleClick}
/>,
);
expect(container.innerHTML).toContain('Complex Test');
expect(container.innerHTML).toContain('42');
expect(container.innerHTML).toContain('<li>a</li>');
expect(container.innerHTML).toContain('<li>b</li>');
expect(container.innerHTML).toContain('<li>c</li>');
});
it('should work with nested queries', async () => {
const parentQueryKey = ['parent'];
const childQueryKey = ['child'];
const parentQueryFn = vi.fn().mockResolvedValue('parent data');
const childQueryFn = vi.fn().mockResolvedValue('child data');
const ChildComponent = () => {
const { data, isLoading } = useQuery({
queryKey: childQueryKey,
queryFn: childQueryFn,
});
if (isLoading) {
return <div>Loading Child...</div>;
}
return <div className="child">{data}</div>;
};
const ParentComponent = () => {
const { data, isLoading } = useQuery({
queryKey: parentQueryKey,
queryFn: parentQueryFn,
});
if (isLoading) {
return <div>Loading Parent...</div>;
}
return (
<div className="parent">
{data}
<ChildComponent />
</div>
);
};
const WrappedComponent = withQueryClient(ParentComponent);
const { container } = render(<WrappedComponent />);
// 初始加载状态
expect(container.innerHTML).toContain('Loading Parent...');
// 等待所有查询完成
await waitFor(() => {
expect(container.innerHTML).toContain('parent data');
expect(container.innerHTML).toContain('child data');
});
expect(parentQueryFn).toHaveBeenCalledTimes(1);
expect(childQueryFn).toHaveBeenCalledTimes(1);
});
});
});