mirror of
https://github.com/lobehub/lobehub.git
synced 2026-09-20 04:56:13 +08:00
✅ test: sweep per-file UI mocks, lift shared mocks to global setup, prebundle @lobehub/ui (#18761)
* ✅ test: sweep per-file base-ui mocks now real components render 101 test files audited: 28 mocks deleted outright, 10 switched to the canonical composed stubs, 42 trimmed to only the assertion-bound entries over an importOriginal spread, 21 left as-is (closed antd-style factories or already minimal). toast.loading stub now returns a close/update handle. Claude-Session: https://claude.ai/code/session_01UTDivfaszDuBjpPn7PV7gQ * ✅ test: sweep remaining ui/antd mocks, lift zustand/i18n mocks to global setup, prebundle @lobehub/ui - delete closed @lobehub/ui, base-ui, antd, antd-style render stubs across 150+ test files; keep only assertion-bound spies composed over importOriginal - register zustand/traditional and react-i18next key-passthrough (defaultValue-aware) mocks once in tests/setup.ts; drop 51 + 94 identical per-file copies - drop 18 usePermission mocks whose real implementation already returns allowed:true - prebundle @lobehub/ui (all subpaths) and motion via deps.optimizer so workers share one chunk instead of re-evaluating the ESM graph per file (585s -> 383s) - fix tests exposed by store auto-reset / prebundling: displayMessage leaked historyCount, copyToClipboard spyOn on ESM namespace, ApiKey defaultValue assertions, lazy executor timeout Claude-Session: https://claude.ai/code/session_01EjmRHEnEMf5mEDRFCDAjy1 * 🐛 fix(test): widen registerBeforeApprove callback type in webOnboarding test Claude-Session: https://claude.ai/code/session_01SoctQBoW5DDXH1brMcJ6yd * 🐛 fix(test): raise timeout for channel discard test rendering real form Claude-Session: https://claude.ai/code/session_01SoctQBoW5DDXH1brMcJ6yd
This commit is contained in:
@@ -1,12 +1 @@
|
||||
{
|
||||
"src/features/Conversation/Error/index.test.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/store/chat/slices/message/action.test.ts": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -24,20 +24,15 @@ vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key.split('.').at(-1) || key }),
|
||||
}));
|
||||
|
||||
// Headless stubs for @lobehub/ui so we exercise our own markup, not the design
|
||||
// system internals (which would need a theme provider in jsdom).
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({ title }: { title?: string }) => <button data-testid="action-icon" title={title} />,
|
||||
Block: ({ children, onClick }: { children?: ReactNode; onClick?: () => void }) => (
|
||||
<div data-testid="block" onClick={onClick}>
|
||||
// base-ui Button requires the app-level motion provider (this package has no
|
||||
// shared vitest setup, unlike src tests which stub it globally).
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
Button: ({ children, ...props }: { children?: ReactNode }) => (
|
||||
<button type="button" {...props}>
|
||||
{children}
|
||||
</div>
|
||||
</button>
|
||||
),
|
||||
Icon: () => <span data-testid="icon" />,
|
||||
Markdown: ({ children }: { children?: ReactNode }) => (
|
||||
<div data-testid="markdown">{children}</div>
|
||||
),
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@/features/AgentTasks/features/AssigneeAvatar', () => ({
|
||||
@@ -111,7 +106,7 @@ describe('EditTaskRender', () => {
|
||||
it('renders the instruction preview as markdown', () => {
|
||||
renderEdit({ instruction: '# Do the thing' });
|
||||
|
||||
expect(screen.getByTestId('markdown').textContent).toContain('# Do the thing');
|
||||
expect(screen.getByRole('heading', { name: 'Do the thing' })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders dependency changes', () => {
|
||||
@@ -125,7 +120,7 @@ describe('EditTaskRender', () => {
|
||||
renderEdit({});
|
||||
|
||||
expect(screen.getByText('T-1')).toBeTruthy();
|
||||
expect(screen.queryByTestId('markdown')).toBeNull();
|
||||
expect(screen.queryByRole('heading')).toBeNull();
|
||||
expect(screen.queryByTestId('assignee-avatar')).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -166,7 +161,7 @@ describe('SetTaskVerifyRender', () => {
|
||||
});
|
||||
|
||||
// Body is just the requirement markdown — verifier / iterations are not shown.
|
||||
expect(screen.getByTestId('markdown').textContent).toContain('## Acceptance');
|
||||
expect(screen.getByRole('heading', { name: 'Acceptance' })).toBeTruthy();
|
||||
expect(screen.queryByTestId('assignee-avatar')).toBeNull();
|
||||
expect(screen.queryByText('3')).toBeNull();
|
||||
});
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
const packageDir = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(packageDir, '../..');
|
||||
const packageDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = path.resolve(packageDir, '../..');
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
{
|
||||
enforce: 'pre',
|
||||
name: 'stub-lobehub-ui-motion-provider',
|
||||
resolveId(id, importer) {
|
||||
if (!importer || !importer.includes('/@lobehub/ui/')) return null;
|
||||
if (/MotionProvider(?:\/index(?:\.(?:mjs|js|tsx))?)?$/.test(id))
|
||||
return path.resolve(repoRoot, 'tests/mocks/lobehubUiMotionProvider.tsx');
|
||||
return null;
|
||||
},
|
||||
},
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(repoRoot, 'src'),
|
||||
'@': path.resolve(repoRoot, 'src'),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
environment: 'happy-dom',
|
||||
server: {
|
||||
deps: {
|
||||
inline: [/@lobehub\//],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+1
-4
@@ -19,10 +19,7 @@ vi.mock('@lobechat/shared-tool-ui/styles', () => ({
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => new Proxy({}, { get: (_target, property) => String(property) }),
|
||||
cx: (...classNames: Array<string | false | undefined>) => classNames.filter(Boolean).join(' '),
|
||||
}));
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({}));
|
||||
|
||||
describe('AskUserQuestionInspector', () => {
|
||||
afterEach(cleanup);
|
||||
|
||||
@@ -17,22 +17,11 @@ vi.mock('@lobechat/shared-tool-ui/styles', () => ({
|
||||
shinyTextStyles: { shinyText: 'shiny-text' },
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: ({ className }: { className?: string }) => (
|
||||
<span className={className} data-testid="icon" />
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => new Proxy({}, { get: (_target, property) => String(property) }),
|
||||
cx: (...classNames: Array<string | false | undefined>) => classNames.filter(Boolean).join(' '),
|
||||
}));
|
||||
|
||||
describe('Codex ErrorInspector', () => {
|
||||
afterEach(cleanup);
|
||||
|
||||
it('renders the warning icon and error message', () => {
|
||||
render(
|
||||
const { container } = render(
|
||||
<ErrorInspector
|
||||
apiName="error"
|
||||
args={{ id: 'item_0', message: 'The session model changed.', type: 'error' }}
|
||||
@@ -40,7 +29,7 @@ describe('Codex ErrorInspector', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('icon')).toBeTruthy();
|
||||
expect(container.querySelector('svg')).toBeTruthy();
|
||||
expect(screen.getByText('The session model changed.')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
@@ -3,5 +3,10 @@ import { defineConfig } from 'vitest/config';
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: 'node',
|
||||
server: {
|
||||
deps: {
|
||||
inline: [/@lobehub\//],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -11,7 +11,8 @@ const mockUseApp = {
|
||||
notification: { open: vi.fn() },
|
||||
};
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: vi.fn(() => mockUseApp),
|
||||
},
|
||||
|
||||
@@ -3,15 +3,6 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import AsyncBoundary from './index';
|
||||
|
||||
// Stub the base-ui Button (the failure state's Retry) to a native button — it
|
||||
// needs a MotionProvider the app sets up globally but the unit env doesn't; the
|
||||
// state-machine assertions only care that a button is/isn't present. vitest
|
||||
// hoists this above the imports regardless of position.
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({ children, onClick }: any) => <button onClick={onClick}>{children}</button>,
|
||||
Text: ({ children }: any) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
const DATA = <div>DATA_CONTENT</div>;
|
||||
const EMPTY = <div>EMPTY_ONBOARDING</div>;
|
||||
const LOADING = <div>LOADING_SKELETON</div>;
|
||||
|
||||
@@ -12,9 +12,10 @@ import { getContainer, useDragUpload } from './useDragUpload';
|
||||
// Mock the hooks and components
|
||||
vi.mock('@/hooks/useMediaUploadAbility');
|
||||
vi.mock('@/store/agent');
|
||||
vi.mock('@lobehub/ui/base-ui', () => {
|
||||
return { toast: { warning: vi.fn() } };
|
||||
});
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
...(await import('~base-ui-stubs')).baseUiStubs,
|
||||
}));
|
||||
|
||||
describe('useDragUpload', () => {
|
||||
let mockOnUploadFiles: Mock;
|
||||
|
||||
@@ -4,7 +4,8 @@ import { remoteServerErrorToast } from './remoteServerErrorToast';
|
||||
|
||||
const toastError = vi.fn();
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: (...args: unknown[]) => toastError(...args) },
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,46 +1,29 @@
|
||||
import type { BlockProps } from '@lobehub/ui';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { type ComponentProps, type ReactNode } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { ComponentType } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import StatisticCard from './index';
|
||||
|
||||
const blockPropsSpy = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => {
|
||||
const actual = await importOriginal<Record<string, unknown>>();
|
||||
const ActualBlock = actual.Block as ComponentType<BlockProps>;
|
||||
return {
|
||||
...actual,
|
||||
Block: ({
|
||||
children,
|
||||
className,
|
||||
padding,
|
||||
paddingBlock,
|
||||
paddingInline,
|
||||
style,
|
||||
variant,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
padding?: number | string;
|
||||
paddingBlock?: number | string;
|
||||
paddingInline?: number | string;
|
||||
style?: ComponentProps<'div'>['style'];
|
||||
variant?: string;
|
||||
}) => (
|
||||
<div
|
||||
className={className}
|
||||
data-padding={padding}
|
||||
data-padding-block={paddingBlock}
|
||||
data-padding-inline={paddingInline}
|
||||
data-testid="block"
|
||||
data-variant={variant}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
Block: (props: BlockProps) => {
|
||||
blockPropsSpy(props);
|
||||
return <ActualBlock {...props} />;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('StatisticCard', () => {
|
||||
beforeEach(() => {
|
||||
blockPropsSpy.mockClear();
|
||||
});
|
||||
|
||||
it('renders title and formatted value with prefix, suffix and precision', () => {
|
||||
render(
|
||||
<StatisticCard
|
||||
@@ -115,16 +98,19 @@ describe('StatisticCard', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
const block = screen.getByTestId('block');
|
||||
expect(block).toHaveAttribute('data-variant', 'outlined');
|
||||
expect(block).toHaveAttribute('data-padding', '24');
|
||||
expect(block).toHaveAttribute('data-padding-block', '8');
|
||||
expect(block).toHaveAttribute('data-padding-inline', '16');
|
||||
expect(blockPropsSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
padding: 24,
|
||||
paddingBlock: 8,
|
||||
paddingInline: 16,
|
||||
variant: 'outlined',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('defaults to the borderless variant', () => {
|
||||
render(<StatisticCard title="T" />);
|
||||
|
||||
expect(screen.getByTestId('block')).toHaveAttribute('data-variant', 'borderless');
|
||||
expect(blockPropsSpy).toHaveBeenCalledWith(expect.objectContaining({ variant: 'borderless' }));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,16 +11,9 @@ vi.mock('@lobehub/ui', () => ({
|
||||
TextArea: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: () => null,
|
||||
Select: () => null,
|
||||
Switch: () => null,
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
createModal: mocks.createModal,
|
||||
useModalContext: () => ({ close: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
describe('openCriterionEditModal', () => {
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import { createElement, type ReactNode } from 'react';
|
||||
import { createElement } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TopicPanel from './TopicPanel';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => createElement('div', null, children),
|
||||
Icon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
// Real base-ui ActionIcon only surfaces its title via a hover Tooltip, so the
|
||||
// static DOM has no accessible name to query.
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({ onClick, title }: { onClick?: () => void; title?: string }) =>
|
||||
createElement('button', { onClick, title }, title),
|
||||
Text: ({ children }: { children?: ReactNode }) => createElement('span', null, children),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/AgentTasks/AgentTaskDetail/TopicChatDrawer', () => ({
|
||||
@@ -41,10 +38,6 @@ vi.mock('@/features/AgentTasks/AgentTaskDetail/TopicChatDrawer', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
describe('TopicPanel', () => {
|
||||
it('renders the topic conversation in the right rail and returns to runs', () => {
|
||||
const onBack = vi.fn();
|
||||
|
||||
@@ -4,25 +4,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { AttachmentThumbs } from './attachments';
|
||||
|
||||
// The unit env has neither the MotionProvider nor the image-preview portal the real
|
||||
// components need; stub them down to the DOM the assertions actually read.
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children, onClick }: any) => <div onClick={onClick}>{children}</div>,
|
||||
Icon: () => null,
|
||||
Image: ({ alt, src }: any) => <img alt={alt} src={src} />,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({ children, onClick }: any) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
toast: { error: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({ Upload: ({ children }: any) => <div>{children}</div> }));
|
||||
|
||||
vi.mock('@/store/file', () => ({ useFileStore: () => vi.fn() }));
|
||||
|
||||
const attachments = [{ id: 'att-1', name: 'screenshot.png', url: 'https://example.com/a.png' }];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -16,26 +15,6 @@ const mocks = vi.hoisted(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => <span />,
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('antd', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as Record<string, unknown>;
|
||||
|
||||
return {
|
||||
...actual,
|
||||
Breadcrumb: ({ items }: { items: Array<{ title: ReactNode }> }) => (
|
||||
<nav>
|
||||
{items.map((item, index) => (
|
||||
<span key={index}>{item.title}</span>
|
||||
))}
|
||||
</nav>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => (key === 'inbox.title' ? 'Lobe AI' : key),
|
||||
|
||||
@@ -9,12 +9,10 @@ import TopicSelector from './TopicSelector';
|
||||
const switchTopic = vi.fn();
|
||||
const useFetchTopics = vi.fn();
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
DropdownMenu: ({ children }: any) => <div>{children}</div>,
|
||||
Flexbox: ({ children }: any) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
// Real base-ui ActionIcon only surfaces its title via a hover Tooltip, so the
|
||||
// static DOM has no accessible name to query.
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({ disabled, onClick, title }: any) => (
|
||||
<button disabled={disabled} type="button" onClick={onClick}>
|
||||
{title}
|
||||
@@ -22,13 +20,6 @@ vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({
|
||||
time: 'time',
|
||||
title: 'title',
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('dayjs', () => {
|
||||
const dayjs = () => ({
|
||||
diff: () => 0,
|
||||
@@ -38,10 +29,6 @@ vi.mock('dayjs', () => {
|
||||
return { default: dayjs };
|
||||
});
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/const/layoutTokens', () => ({
|
||||
DESKTOP_HEADER_ICON_SMALL_SIZE: 24,
|
||||
}));
|
||||
|
||||
@@ -13,12 +13,6 @@ vi.mock('react-router', () => ({
|
||||
useParams: () => ({ aid: 'agent-from-url' }),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<div {...(props as Record<string, unknown>)}>{children}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
const pageEditorProps = vi.hoisted(() => ({
|
||||
current: undefined as undefined | Record<string, unknown>,
|
||||
}));
|
||||
|
||||
@@ -22,29 +22,6 @@ const modalConfirm = vi.hoisted(() => vi.fn());
|
||||
const openDocumentMock = vi.hoisted(() => vi.fn());
|
||||
const removeDocumentMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({
|
||||
icon,
|
||||
onClick,
|
||||
title,
|
||||
}: {
|
||||
icon?: { displayName?: string; name?: string };
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
}) => (
|
||||
<button aria-label={title} data-icon={icon?.displayName ?? icon?.name} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span />,
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/icons', () => ({
|
||||
SkillsIcon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...((await importOriginal()) as Record<string, unknown>),
|
||||
ActionIcon: ({
|
||||
@@ -79,7 +56,8 @@ vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: { error: messageError, success: messageSuccess, warning: messageWarning },
|
||||
@@ -98,12 +76,6 @@ vi.mock('@/features/Workspace/useWorkspaceAwareNavigate', () => ({
|
||||
useWorkspaceAwareNavigate: () => navigateMock,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/ExplorerTree', () => {
|
||||
interface MockExplorerTreeProps {
|
||||
canDrag?: (node: ExplorerTreeNode<unknown>) => boolean;
|
||||
|
||||
@@ -16,10 +16,6 @@ vi.mock('@/store/home', () => ({
|
||||
selector({ refreshAgentList: mocks.refreshAgentList }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/services/agent', () => ({
|
||||
agentService: {
|
||||
updateAgentSlug: (...args: unknown[]) => mocks.updateAgentSlug(...args),
|
||||
|
||||
@@ -26,31 +26,6 @@ vi.mock('@/features/ResourcePermission/useResourceAccess', () => ({
|
||||
useResourceAccess: () => ({ canEditResource: true, isAccessResolved: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<div {...props}>{children}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/icons', () => ({
|
||||
BotPromptIcon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('lucide-react', () => ({
|
||||
DnaIcon: () => null,
|
||||
ListTodoIcon: () => null,
|
||||
MessageSquarePlusIcon: () => null,
|
||||
MessagesSquareIcon: () => null,
|
||||
SearchIcon: () => null,
|
||||
TargetIcon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('react-router', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
const actual = (await vi.importActual('react-router')) as typeof import('react-router');
|
||||
|
||||
@@ -12,10 +12,6 @@ const mocks = vi.hoisted(() => ({
|
||||
params: {} as { aid?: string },
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@/features/NavPanel/components/NavItem', () => ({
|
||||
default: ({
|
||||
active,
|
||||
|
||||
@@ -9,34 +9,11 @@ import MetaHoverCard from './MetaHoverCard';
|
||||
|
||||
const fetchTopicLinkedPullRequestMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => <span data-testid="meta-card-icon" />,
|
||||
}));
|
||||
|
||||
vi.mock('@/store/chat', () => ({
|
||||
useChatStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({ useFetchTopicLinkedPullRequest: fetchTopicLinkedPullRequestMock }),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({
|
||||
card: 'card',
|
||||
header: 'header',
|
||||
headerTime: 'headerTime',
|
||||
headerTitle: 'headerTitle',
|
||||
prLink: 'prLink',
|
||||
row: 'row',
|
||||
rowIcon: 'rowIcon',
|
||||
rowText: 'rowText',
|
||||
}),
|
||||
cssVar: {
|
||||
colorError: '#f00',
|
||||
colorSuccess: '#0f0',
|
||||
colorTextTertiary: '#999',
|
||||
colorWarning: '#fa0',
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, values?: Record<string, string>) =>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TopicItem from './index';
|
||||
@@ -17,43 +17,13 @@ const topicMetaCardMock = vi.hoisted(() => ({
|
||||
value: undefined as { pullRequest?: { state: string } } | undefined,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<div {...props}>{children}</div>
|
||||
),
|
||||
// Assertions key on the raw lucide displayName, which the real Icon does not
|
||||
// expose in the DOM.
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
Icon: ({ icon }: { icon?: { displayName?: string } }) => (
|
||||
<div data-icon={icon?.displayName} data-testid="topic-item-icon" />
|
||||
),
|
||||
Popover: ({ children }: { children?: ReactNode }) => <>{children}</>,
|
||||
Skeleton: {
|
||||
Button: (props: Record<string, unknown>) => <div {...props} />,
|
||||
},
|
||||
Tooltip: ({ children }: { children?: ReactNode }) => <>{children}</>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ContextMenuTrigger: ({ children }: { children?: ReactNode }) => <>{children}</>,
|
||||
Tag: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Text: ({ children, style }: { children?: ReactNode; style?: CSSProperties }) => (
|
||||
<span style={style}>{children}</span>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
// `ContextMenuTrigger` comes from the base-ui barrel, which pulls in
|
||||
// ScrollArea's global style at import time.
|
||||
createGlobalStyle: () => () => null,
|
||||
createStaticStyles: () => ({
|
||||
dotContainer: 'dotContainer',
|
||||
neonDot: 'neonDot',
|
||||
neonDotWrapper: 'neonDotWrapper',
|
||||
}),
|
||||
cssVar: {
|
||||
colorInfo: '#00f',
|
||||
colorTextDescription: '#999',
|
||||
},
|
||||
keyframes: () => 'keyframes',
|
||||
useTheme: () => ({ isDarkMode: false }),
|
||||
}));
|
||||
|
||||
vi.mock('motion/react', () => ({
|
||||
@@ -68,12 +38,6 @@ vi.mock('motion/react', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/const/version', () => ({ isDesktop: false }));
|
||||
vi.mock('@/features/NavPanel/components/NavItem', () => ({
|
||||
default: ({
|
||||
|
||||
@@ -12,17 +12,8 @@ const permissionMock = vi.hoisted(() => ({
|
||||
}));
|
||||
const versionMock = vi.hoisted(() => ({ isDesktop: false }));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TopicList from './index';
|
||||
@@ -110,12 +109,6 @@ vi.mock('@/store/user/selectors', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../AllTopicsDrawer', () => ({
|
||||
default: ({ open }: { open: boolean }) => (
|
||||
<div data-open={String(open)} data-testid="all-topics-drawer" />
|
||||
@@ -138,16 +131,6 @@ vi.mock('./Item', () => ({
|
||||
default: () => <div data-testid="topic-item" />,
|
||||
}));
|
||||
|
||||
// Partial mock: keep every real export (e.g. `lobeStaticStylish`, which
|
||||
// `createStaticStyles` reads at import time in transitively-loaded modules like
|
||||
// ShareModal/useContainerStyles) and override only Flexbox. A full mock returning
|
||||
// just Flexbox drops those exports and crashes collection whenever the suite's
|
||||
// module graph evaluates one of them.
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<Record<string, unknown>>()),
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
describe('Agent topic list', () => {
|
||||
beforeEach(() => {
|
||||
pushMock.mockReset();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import GroupItem from './GroupItem';
|
||||
@@ -23,67 +22,6 @@ vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await import('~base-ui-stubs')).baseUiStubs,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
AccordionItem: ({
|
||||
action,
|
||||
children,
|
||||
title,
|
||||
}: {
|
||||
action?: ReactNode;
|
||||
children?: ReactNode;
|
||||
title?: ReactNode;
|
||||
}) => (
|
||||
<section>
|
||||
<div>
|
||||
{title}
|
||||
{action}
|
||||
</div>
|
||||
{children}
|
||||
</section>
|
||||
),
|
||||
ActionIcon: ({
|
||||
onClick,
|
||||
title,
|
||||
}: {
|
||||
onClick?: (event: { stopPropagation: () => void }) => void;
|
||||
title?: string;
|
||||
}) => (
|
||||
<button
|
||||
aria-label={title}
|
||||
type="button"
|
||||
onClick={() => onClick?.({ stopPropagation: vi.fn() })}
|
||||
/>
|
||||
),
|
||||
Center: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span />,
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
Tooltip: ({ children }: { children?: ReactNode }) => <>{children}</>,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
createStaticStyles: () => ({
|
||||
addTopicAction: 'addTopicAction',
|
||||
statusBadge: 'statusBadge',
|
||||
statusBadgeError: 'statusBadgeError',
|
||||
statusBadgeLoading: 'statusBadgeLoading',
|
||||
statusBadgeWaiting: 'statusBadgeWaiting',
|
||||
unreadDot: 'unreadDot',
|
||||
unreadRipple: 'unreadRipple',
|
||||
unreadWrapper: 'unreadWrapper',
|
||||
}),
|
||||
cssVar: {
|
||||
colorError: '#f00',
|
||||
colorInfo: '#00f',
|
||||
colorTextSecondary: '#666',
|
||||
colorTextTertiary: '#999',
|
||||
colorWarning: '#fa0',
|
||||
},
|
||||
cx: (...classes: Array<string | undefined>) => classes.filter(Boolean).join(' '),
|
||||
keyframes: () => 'keyframes',
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, options?: { directory?: string }) =>
|
||||
|
||||
+2
-11
@@ -6,17 +6,8 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useThreadItemDropdownMenu } from './useDropdownMenu';
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
modal: {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useTopicActionsDropdownMenu } from './useDropdownMenu';
|
||||
@@ -43,36 +42,25 @@ vi.mock('@/store/user', () => ({
|
||||
useUserStore: () => userMock.currentUserId,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
confirmModal: confirmModalMock,
|
||||
toast: messageMock,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: messageMock,
|
||||
modal: {
|
||||
confirm: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => {
|
||||
return {
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: messageMock,
|
||||
modal: {
|
||||
confirm: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
Upload: ({ children }: { children: ReactNode }) => <>{children}</>,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: (action: 'create_content' | 'edit_own_content') => ({
|
||||
allowed: permissionMock[action],
|
||||
|
||||
@@ -39,11 +39,10 @@ const mocks = vi.hoisted(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Center: ({ children }: { children: ReactNode }) => (
|
||||
<div data-testid="selector-trigger">{children}</div>
|
||||
),
|
||||
Flexbox: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
// The real Popover only mounts its content after an open interaction; the
|
||||
// assertions read the selector list synchronously.
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
Popover: ({
|
||||
children,
|
||||
content,
|
||||
@@ -62,19 +61,6 @@ vi.mock('@lobehub/ui', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({
|
||||
chevron: 'chevron',
|
||||
container: 'container',
|
||||
}),
|
||||
cx: (...classes: string[]) => classes.filter(Boolean).join(' '),
|
||||
}));
|
||||
|
||||
vi.mock('lucide-react', () => ({
|
||||
ChevronsUpDownIcon: () => <span data-testid="chevron" />,
|
||||
Circle: () => <span data-testid="circle" />,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => (key === 'taskManager.agent' ? 'Task Manager' : key),
|
||||
|
||||
@@ -39,38 +39,15 @@ const mocks = vi.hoisted(() => ({
|
||||
updateVerifyConfig: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
// Real base-ui ActionIcon only surfaces its title via a hover Tooltip; the
|
||||
// assertions click the title text directly.
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({ onClick, title }: { onClick?: () => void; title?: string }) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Block: ({ children, onClick }: { children: ReactNode; onClick?: () => void }) => (
|
||||
<div onClick={onClick}>{children}</div>
|
||||
),
|
||||
Drawer: ({ children, open }: { children: ReactNode; open?: boolean }) =>
|
||||
open ? <aside>{children}</aside> : null,
|
||||
Flexbox: ({ children, onClick }: { children: ReactNode; onClick?: () => void }) => (
|
||||
<div onClick={onClick}>{children}</div>
|
||||
),
|
||||
Icon: () => <span />,
|
||||
Tag: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ onClick, title }: { onClick?: () => void; title?: string }) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Button: ({ children, onClick }: { children: ReactNode; onClick?: () => void }) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
Tag: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
confirmModal: (opts: unknown) => mocks.confirmModal(opts),
|
||||
}));
|
||||
|
||||
@@ -78,33 +55,11 @@ vi.mock('@/features/Workspace/useWorkspaceAwareNavigate', () => ({
|
||||
useWorkspaceAwareNavigate: () => mocks.navigate,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: { useApp: () => ({ message: { error: vi.fn() } }) },
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
cx: (...classNames: unknown[]) => classNames.filter(Boolean).join(' '),
|
||||
createStaticStyles: () => ({
|
||||
body: 'body',
|
||||
drawerBody: 'drawerBody',
|
||||
error: 'error',
|
||||
group: 'group',
|
||||
groupHeader: 'groupHeader',
|
||||
list: 'list',
|
||||
row: 'row',
|
||||
seq: 'seq',
|
||||
}),
|
||||
cssVar: {
|
||||
colorTextDescription: '#999',
|
||||
colorTextQuaternary: '#aaa',
|
||||
colorTextSecondary: '#666',
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/NeuralNetworkLoading', () => ({ default: () => <div>loading</div> }));
|
||||
|
||||
vi.mock('@/features/Acceptance', async () => ({
|
||||
@@ -138,10 +93,6 @@ vi.mock('@/features/Acceptance', async () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/services/verify', () => ({
|
||||
verifyService: {
|
||||
deleteAcceptance: (id: string) => mocks.deleteAcceptance(id),
|
||||
|
||||
@@ -35,23 +35,22 @@ const mocks = vi.hoisted(() => ({
|
||||
updateTaskVisibility: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({ title }: { title?: string }) => <button type="button">{title}</button>,
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
DropdownMenu: ({ children, items }: { children?: ReactNode; items: MenuItem[] }) => {
|
||||
mocks.dropdownItems = items;
|
||||
return <>{children}</>;
|
||||
},
|
||||
Icon: () => <span />,
|
||||
copyToClipboard: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ title }: { title?: string }) => <button type="button">{title}</button>,
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
confirmModal: (opts: unknown) => mocks.confirmModal(opts),
|
||||
toast: { error: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: { success: mocks.messageSuccess },
|
||||
@@ -59,12 +58,6 @@ vi.mock('antd', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/business/client/hooks/useActiveWorkspaceId', () => ({
|
||||
useActiveWorkspaceId: () => mocks.activeWorkspaceId,
|
||||
}));
|
||||
@@ -103,10 +96,6 @@ vi.mock('@/hooks/useAppOrigin', () => ({
|
||||
useAppOrigin: () => 'https://example.com',
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/task', () => ({
|
||||
useTaskStore: (selector: (state: Record<string, unknown>) => unknown) =>
|
||||
selector({
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TaskParentBar from './TaskParentBar';
|
||||
@@ -25,29 +24,6 @@ const createState = (parent: any) => ({
|
||||
},
|
||||
});
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
icon,
|
||||
onClick,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
icon?: ReactNode;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
{icon}
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
Flexbox: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('react-router', () => ({
|
||||
useNavigate: () => mocks.navigate,
|
||||
}));
|
||||
|
||||
@@ -34,38 +34,12 @@ const mocks = vi.hoisted(() => ({
|
||||
} as any,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({ onClick }: { onClick?: () => void }) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
action
|
||||
</button>
|
||||
),
|
||||
Block: ({
|
||||
children,
|
||||
clickable,
|
||||
onClick,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
clickable?: boolean;
|
||||
onClick?: () => void;
|
||||
}) =>
|
||||
clickable ? (
|
||||
<button type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
) : (
|
||||
<div>{children}</div>
|
||||
),
|
||||
Flexbox: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span>icon</span>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@/libs/contextMenu', () => ({
|
||||
showContextMenu: mocks.showContextMenu,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: { error: vi.fn(), info: vi.fn(), success: vi.fn(), warning: vi.fn() },
|
||||
@@ -101,33 +75,14 @@ vi.mock('antd', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
vi.mock('antd-style', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
cssVar: {
|
||||
colorTextDescription: '#999',
|
||||
colorTextSecondary: '#666',
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ onClick }: { onClick?: () => void }) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
action
|
||||
</button>
|
||||
),
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
confirmModal: vi.fn(),
|
||||
toast: {
|
||||
error: vi.fn(),
|
||||
info: vi.fn(),
|
||||
success: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('react-router', () => ({
|
||||
useNavigate: () => mocks.navigate,
|
||||
}));
|
||||
|
||||
@@ -9,28 +9,6 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TopicCard from './TopicCard';
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ onClick }: { onClick?: () => void }) => (
|
||||
<button type="button" onClick={onClick}>
|
||||
action
|
||||
</button>
|
||||
),
|
||||
Avatar: () => <span>avatar</span>,
|
||||
Tag: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
confirmModal: vi.fn(),
|
||||
toast: {
|
||||
error: vi.fn(),
|
||||
info: vi.fn(),
|
||||
success: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/store/task', () => ({
|
||||
useTaskStore: (selector: (state: any) => unknown) =>
|
||||
selector({
|
||||
@@ -42,10 +20,6 @@ vi.mock('@/store/task', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/useActivityTime', () => ({
|
||||
useActivityTime: () => ({ text: '4m ago', title: '4m ago' }),
|
||||
}));
|
||||
|
||||
@@ -59,7 +59,8 @@ const mocks = vi.hoisted(() => ({
|
||||
const serializeSize = (size: unknown) =>
|
||||
size === undefined ? '' : typeof size === 'string' ? size : JSON.stringify(size);
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
copyToClipboard: vi.fn(),
|
||||
DropdownMenu: ({
|
||||
children,
|
||||
@@ -79,19 +80,10 @@ vi.mock('@lobehub/ui', () => ({
|
||||
)}
|
||||
</>
|
||||
),
|
||||
Flexbox: ({
|
||||
children,
|
||||
flex,
|
||||
style,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
flex?: CSSProperties['flex'];
|
||||
style?: CSSProperties;
|
||||
}) => <div style={{ flex, ...style }}>{children}</div>,
|
||||
Freeze: ({ children }: { children?: ReactNode; frozen?: boolean }) => <>{children}</>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({
|
||||
disabled,
|
||||
icon,
|
||||
@@ -116,19 +108,6 @@ vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Tag: ({ children, title }: { children?: ReactNode; title?: string }) => (
|
||||
<span title={title}>{children}</span>
|
||||
),
|
||||
Text: ({ children, style }: { children?: ReactNode; style?: CSSProperties }) => (
|
||||
<span style={style}>{children}</span>
|
||||
),
|
||||
confirmModal: vi.fn(),
|
||||
toast: {
|
||||
error: vi.fn(),
|
||||
info: vi.fn(),
|
||||
success: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
},
|
||||
FloatingPanel: ({
|
||||
actions,
|
||||
children,
|
||||
@@ -185,12 +164,6 @@ vi.mock('next/dynamic', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/Conversation/ChatList', () => ({
|
||||
default: () => <div data-testid="chat-list" />,
|
||||
}));
|
||||
|
||||
@@ -28,41 +28,8 @@ vi.mock('@lobehub/editor/react', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
// Stub the base-ui Button (submit) to a native button — it needs a
|
||||
// MotionProvider the app sets up globally but the unit env doesn't.
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
disabled,
|
||||
onClick,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button disabled={disabled} type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
ActionIcon: ({
|
||||
onClick,
|
||||
style,
|
||||
title,
|
||||
}: {
|
||||
onClick?: () => void;
|
||||
style?: CSSProperties;
|
||||
title?: string;
|
||||
}) => (
|
||||
<div
|
||||
aria-label={title}
|
||||
role="button"
|
||||
style={{ height: 24, width: 24, ...style }}
|
||||
onClick={onClick}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
),
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
@@ -135,10 +102,6 @@ vi.mock('../shared/useAgentVisibility', () => ({
|
||||
useAgentVisibility: (agentId?: string) => (agentId === 'agent-private' ? 'private' : undefined),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
describe('CreateTaskInlineEntry', () => {
|
||||
beforeEach(() => {
|
||||
permissionMock.allowed = true;
|
||||
@@ -182,7 +145,9 @@ describe('CreateTaskInlineEntry', () => {
|
||||
expect(assigneeControl?.style.getPropertyValue('--lobe-flex-height')).toBe('24px');
|
||||
expect(assigneeControl?.style.getPropertyValue('--lobe-flex-padding-block')).toBe('3px');
|
||||
|
||||
const attachmentAction = container.querySelector<HTMLElement>('[role="button"]');
|
||||
const attachmentAction = container
|
||||
.querySelector('svg.lucide-paperclip')
|
||||
?.closest<HTMLElement>('button');
|
||||
expect(attachmentAction).toHaveStyle({ height: '24px', width: '24px' });
|
||||
expect(attachmentAction?.parentElement?.style.getPropertyValue('--lobe-flex-align')).toBe(
|
||||
'center',
|
||||
|
||||
@@ -12,8 +12,8 @@ const taskStoreMock = vi.hoisted(() => ({
|
||||
visibility: 'workspace',
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: () => <span>Visibility</span>,
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
DropdownMenu: ({
|
||||
children,
|
||||
items,
|
||||
@@ -33,11 +33,6 @@ vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => <span data-testid="menu-extra-icon" />,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
cssVar: { colorTextSecondary: '#666' },
|
||||
}));
|
||||
|
||||
vi.mock('@/business/client/hooks/useActiveWorkspaceId', () => ({
|
||||
useActiveWorkspaceId: () => 'workspace-1',
|
||||
}));
|
||||
@@ -50,10 +45,6 @@ vi.mock('@/store/task', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
describe('TaskListVisibilityFilter', () => {
|
||||
it('shows a trailing checkmark only for the active visibility option', () => {
|
||||
render(<TaskListVisibilityFilter />);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TaskWorkspaceLayout from './TaskWorkspaceLayout';
|
||||
@@ -11,12 +10,6 @@ const mocks = vi.hoisted(() => ({
|
||||
isMobile: false,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<div {...props}>{children}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('react-router', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
const actual = (await vi.importActual('react-router')) as typeof import('react-router');
|
||||
|
||||
@@ -13,28 +13,6 @@ const mocks = vi.hoisted(() => ({
|
||||
useFetchTaskDetail: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Block: ({
|
||||
children,
|
||||
clickable,
|
||||
onClick,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
clickable?: boolean;
|
||||
onClick?: () => void;
|
||||
}) =>
|
||||
clickable ? (
|
||||
<button data-testid="task-card" type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
) : (
|
||||
<span>{children}</span>
|
||||
),
|
||||
ContextMenuTrigger: ({ children }: { children: ReactNode }) => <>{children}</>,
|
||||
Flexbox: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
i18n: { language: 'en-US' },
|
||||
@@ -132,7 +110,7 @@ describe('AgentTaskItem', () => {
|
||||
it('opens an assigned task inside its owning agent route', () => {
|
||||
render(<AgentTaskItem task={createTask('agt_owner')} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('task-card'));
|
||||
fireEvent.click(screen.getByText('Hourly trend update'));
|
||||
|
||||
expect(mocks.navigate).toHaveBeenCalledWith('/agent/agt_owner/task/T-22');
|
||||
});
|
||||
@@ -140,7 +118,7 @@ describe('AgentTaskItem', () => {
|
||||
it('opens an assigned task on the global detail route in global scope', () => {
|
||||
render(<AgentTaskItem routeScope="global" task={createTask('agt_owner')} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('task-card'));
|
||||
fireEvent.click(screen.getByText('Hourly trend update'));
|
||||
|
||||
expect(mocks.navigate).toHaveBeenCalledWith('/task/T-22');
|
||||
});
|
||||
@@ -148,7 +126,7 @@ describe('AgentTaskItem', () => {
|
||||
it('falls back to the global task detail route when the task has no assignee', () => {
|
||||
render(<AgentTaskItem task={createTask(null)} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId('task-card'));
|
||||
fireEvent.click(screen.getByText('Hourly trend update'));
|
||||
|
||||
expect(mocks.navigate).toHaveBeenCalledWith('/task/T-22');
|
||||
});
|
||||
|
||||
@@ -7,10 +7,8 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TaskSubtaskProgressTag from './TaskSubtaskProgressTag';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Block: ({ children, onClick }: { children: ReactNode; onClick?: () => void }) => (
|
||||
<div onClick={onClick}>{children}</div>
|
||||
),
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
DropdownMenu: ({
|
||||
children,
|
||||
items,
|
||||
@@ -32,23 +30,6 @@ vi.mock('@lobehub/ui', () => ({
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
Flexbox: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
Progress: () => <span>progress</span>,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
cssVar: { colorSuccess: 'green' },
|
||||
}));
|
||||
|
||||
vi.mock('./TaskStatusIcon', () => ({
|
||||
|
||||
@@ -2,25 +2,10 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TaskVisibilityChipLabel from './TaskVisibilityChipLabel';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Block: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span />,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
cssVar: {
|
||||
colorTextDescription: '#999',
|
||||
colorTextSecondary: '#666',
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, options?: { defaultValue?: string }) => {
|
||||
|
||||
@@ -7,7 +7,8 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import TaskVisibilityTag from './TaskVisibilityTag';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
DropdownMenu: ({
|
||||
children,
|
||||
items,
|
||||
@@ -25,15 +26,6 @@ vi.mock('@lobehub/ui', () => ({
|
||||
</>
|
||||
),
|
||||
Icon: () => <span data-testid="menu-extra-icon" />,
|
||||
Tooltip: ({ children }: { children: ReactNode }) => children,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({ trigger: 'trigger', triggerDisabled: 'trigger-disabled' }),
|
||||
cssVar: {
|
||||
colorTextDescription: '#999',
|
||||
colorTextSecondary: '#666',
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/business/client/hooks/useActiveWorkspaceId', () => ({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { canGoNative } from '@/libs/contextMenu/canGoNative';
|
||||
@@ -23,18 +22,17 @@ const mocks = vi.hoisted(() => ({
|
||||
updateTaskStatus: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
copyToClipboard: mocks.copyToClipboard,
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => React.createElement('div', {}, children),
|
||||
Icon: ({ icon: Icon }: { icon?: React.ComponentType }) =>
|
||||
Icon ? React.createElement(Icon) : React.createElement('span'),
|
||||
}));
|
||||
|
||||
vi.mock('@/libs/contextMenu', () => ({
|
||||
closeContextMenu: mocks.closeContextMenu,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: { success: mocks.messageSuccess },
|
||||
@@ -51,10 +49,6 @@ vi.mock('@/hooks/useAppOrigin', () => ({
|
||||
useAppOrigin: () => 'https://example.com',
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/agent', () => ({
|
||||
useAgentStore: (selector: (state: { inboxAgentId: string }) => unknown) =>
|
||||
selector({ inboxAgentId: 'inbox-agent' }),
|
||||
|
||||
@@ -15,27 +15,6 @@ const createState = (taskDetailMap: Record<string, any>) => ({
|
||||
taskDetailMap,
|
||||
});
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => <span>icon</span>,
|
||||
Text: ({ children }: { children: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
Breadcrumb: ({ items }: { items: Array<{ key?: string; title: ReactNode }> }) => (
|
||||
<nav>
|
||||
{items.map((item, index) => (
|
||||
<span data-testid="crumb" key={item.key ?? index}>
|
||||
{item.title}
|
||||
</span>
|
||||
))}
|
||||
</nav>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('react-router', () => ({
|
||||
Link: ({ children, to }: { children: ReactNode; to: string }) => <a href={to}>{children}</a>,
|
||||
useParams: () => ({}),
|
||||
|
||||
@@ -33,7 +33,8 @@ vi.mock('react-router', () => ({
|
||||
useSearchParams: () => [{ get: mockSearchParamsGet }],
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: mockMessageError, success: mockMessageSuccess },
|
||||
}));
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ vi.mock('react-router', () => ({
|
||||
useSearchParams: () => [{ get: mockSearchParamsGet }],
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: mockMessageError, success: vi.fn() },
|
||||
}));
|
||||
|
||||
|
||||
@@ -12,25 +12,11 @@ const tokenMocks = vi.hoisted(() => ({
|
||||
useTokenBreakdown: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => {
|
||||
const Primitive = ({ children }: { children?: ReactNode }) => createElement('div', {}, children);
|
||||
|
||||
return { Center: Primitive, Flexbox: Primitive, Tooltip: Primitive };
|
||||
});
|
||||
|
||||
vi.mock('@lobehub/ui/chat', () => ({
|
||||
TokenTag: ({ value }: { value: number }) =>
|
||||
createElement('div', { 'data-testid': 'token-tag' }, value),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
cssVar: new Proxy({}, { get: (_, key) => String(key) }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/user', () => ({
|
||||
useUserStore: (selector: (state: object) => unknown) => selector({}),
|
||||
}));
|
||||
|
||||
@@ -72,7 +72,10 @@ vi.mock('@lobechat/const', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({ toast: { error: toastError } }));
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: toastError },
|
||||
}));
|
||||
|
||||
vi.mock('@/features/ChatInput/hooks/useAgentId', () => ({
|
||||
useAgentId: () => 'agent-id',
|
||||
|
||||
@@ -84,26 +84,10 @@ vi.mock('@/components/AntdStaticMethods', () => ({
|
||||
message: { error: vi.fn(), info: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
toast: { error: vi.fn(), info: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock('@/components/RingLoading', () => ({
|
||||
default: () => <span data-testid="ring-loading" />,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => <span data-testid="icon" />,
|
||||
Tooltip: ({ children, title }: { children: ReactNode; title?: ReactNode }) => (
|
||||
<div data-title={typeof title === 'string' ? title : undefined}>{children}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({}),
|
||||
cssVar: new Proxy({}, { get: () => 'var(--mock)' }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, values?: Record<string, unknown>) =>
|
||||
|
||||
@@ -31,17 +31,16 @@ vi.mock('@/services/git', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
Icon: ({ icon }: any) => <span data-icon={icon?.displayName ?? icon?.name} data-testid="icon" />,
|
||||
Input: ({ value, onChange, placeholder }: any) => (
|
||||
<input placeholder={placeholder} value={value} onChange={onChange} />
|
||||
),
|
||||
Tooltip: ({ children }: { children: ReactNode }) => (
|
||||
<span data-testid="worktree-tooltip">{children}</span>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
confirmModal: confirmModalMock,
|
||||
DropdownMenuItem: ({ children, onClick }: { children: ReactNode; onClick?: () => void }) => (
|
||||
<button onClick={onClick}>{children}</button>
|
||||
@@ -63,12 +62,6 @@ vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({}),
|
||||
cssVar: new Proxy({}, { get: () => 'var(--mock)' }),
|
||||
cx: (...classes: string[]) => classes.filter(Boolean).join(' '),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, values?: Record<string, unknown>) =>
|
||||
|
||||
@@ -19,8 +19,6 @@ const testState = vi.hoisted(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({ confirmModal: vi.fn() }));
|
||||
|
||||
vi.mock('@/hooks/useEffectiveAgencyConfig', () => ({
|
||||
useEffectiveAgencyConfig: () => testState.effective,
|
||||
}));
|
||||
|
||||
@@ -14,7 +14,8 @@ const { manager, preference } = vi.hoisted(() => ({
|
||||
preference: { terminalFontFamily: '"JetBrains Mono"' },
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
vi.mock('antd-style', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
useTheme: () => ({ fontFamilyCode: 'Application Mono' }),
|
||||
}));
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ vi.mock('@lobechat/const', async (importOriginal) => ({
|
||||
isDesktop: true,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
DraggablePanel: ({ children, expand }: { children?: ReactNode; expand?: boolean }) => (
|
||||
<div data-expand={String(expand)} data-testid="terminal-panel">
|
||||
{children}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { ConnectorSourceType } from '@/database/schemas';
|
||||
@@ -57,33 +56,6 @@ vi.mock('@/hooks/useResourceManageable', () => ({
|
||||
useResourceManageable: () => true,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Tooltip: ({ children }: { children: ReactNode }) => children,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
App: { useApp: () => ({ message: { error: vi.fn() } }) },
|
||||
}));
|
||||
|
||||
// Stub the base-ui Button to a native button — it needs a MotionProvider the
|
||||
// app sets up globally but the unit env doesn't.
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
disabled,
|
||||
onClick,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button disabled={disabled} type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
confirmModal: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/tool', () => ({
|
||||
useToolStore<T>(selector: (state: typeof mocks.toolState) => T): T {
|
||||
return selector(mocks.toolState);
|
||||
|
||||
@@ -5,21 +5,9 @@ import { GoalContent } from './GoalModal';
|
||||
|
||||
const mocks = vi.hoisted(() => ({ close: vi.fn() }));
|
||||
|
||||
vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }) }));
|
||||
vi.mock('i18next', () => ({ t: (key: string) => key }));
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children }: any) => <div>{children}</div>,
|
||||
Text: ({ children }: any) => <span>{children}</span>,
|
||||
TextArea: (props: any) => <textarea {...props} />,
|
||||
}));
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({ children, onClick, disabled }: any) => (
|
||||
<button disabled={disabled} type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
Text: ({ children }: any) => <span>{children}</span>,
|
||||
createModal: vi.fn(),
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
useModalContext: () => ({ close: mocks.close }),
|
||||
}));
|
||||
|
||||
|
||||
@@ -14,11 +14,8 @@ let isRegenerating = false;
|
||||
|
||||
// Drive the Alert's `afterClose` directly via a click, so we exercise
|
||||
// ErrorContent's dismiss branching without the real close animation.
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Skeleton: { Button: () => <div>loading</div> },
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
Alert: ({ action, afterClose }: { action?: ReactNode; afterClose?: () => void }) => (
|
||||
<div>
|
||||
<button type="button" onClick={() => afterClose?.()}>
|
||||
@@ -27,23 +24,6 @@ vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
{action}
|
||||
</div>
|
||||
),
|
||||
Button: ({
|
||||
children,
|
||||
disabled,
|
||||
loading,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
}) => (
|
||||
<button aria-busy={loading || undefined} disabled={disabled} type="button">
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/Conversation/store', () => ({
|
||||
|
||||
@@ -15,8 +15,6 @@ import {
|
||||
useConversationScroll,
|
||||
} from './useConversationScroll';
|
||||
|
||||
vi.mock('zustand/traditional');
|
||||
|
||||
vi.mock('../../store', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof ConversationStoreModule>();
|
||||
return {
|
||||
|
||||
@@ -23,27 +23,6 @@ const chatListMocks = vi.hoisted(() => ({
|
||||
useFetchAgentConfig: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
disabled,
|
||||
onClick,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button disabled={disabled} onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/Conversation/ChatList/components/AgentSignalReceiptList', () => ({
|
||||
default: () => null,
|
||||
}));
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import type * as businessConstModule from '@lobechat/business-const';
|
||||
import { HeterogeneousAgentSessionErrorCode } from '@lobechat/electron-client-ipc';
|
||||
import type * as modelRuntimeModule from '@lobechat/model-runtime';
|
||||
import { AgentRuntimeErrorType } from '@lobechat/model-runtime';
|
||||
import type * as lobechatTypesModule from '@lobechat/types';
|
||||
import { ChatErrorType } from '@lobechat/types';
|
||||
import type * as lobehubUiModule from '@lobehub/ui';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
@@ -32,14 +30,6 @@ const businessErrorContentMock = vi.hoisted(() =>
|
||||
})),
|
||||
);
|
||||
|
||||
vi.mock('@lobechat/business-const', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as typeof businessConstModule;
|
||||
|
||||
return {
|
||||
...actual,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@lobechat/model-runtime', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as typeof modelRuntimeModule;
|
||||
|
||||
@@ -64,20 +54,6 @@ vi.mock('@lobechat/types', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as typeof lobehubUiModule;
|
||||
|
||||
return {
|
||||
...actual,
|
||||
Block: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Highlighter: ({ children }: { children?: ReactNode }) => <pre>{children}</pre>,
|
||||
Skeleton: {
|
||||
...actual.Skeleton,
|
||||
Button: () => <div>loading</div>,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, options?: Record<string, unknown>) =>
|
||||
|
||||
@@ -35,19 +35,6 @@ const mockOpenDocument = vi.fn();
|
||||
const mockOpenTaskDetail = vi.fn();
|
||||
const mockOpenVerifyReport = vi.fn();
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: (props: { onClick?: (e: unknown) => void; title?: string }) => (
|
||||
<button
|
||||
aria-label={props.title}
|
||||
data-side-browser={(props as Record<string, unknown>)['data-side-browser']}
|
||||
type="button"
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
),
|
||||
Avatar: ({ alt }: { alt?: string }) => <span>{alt}</span>,
|
||||
Text: ({ children }: { children?: unknown }) => <span>{children as never}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@/business/client/hooks/useWorkspaces', () => ({
|
||||
useWorkspaces: () => [{ id: 'ws-1', slug: 'lobe-team' }],
|
||||
}));
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { RENDERER_HANDLED_LINK_ATTR } from '@lobechat/desktop-bridge';
|
||||
import type { TooltipProps } from '@lobehub/ui';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ComponentType } from 'react';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useChatStore } from '@/store/chat';
|
||||
@@ -40,29 +41,19 @@ vi.mock('@/components/FileIcon', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...((await importOriginal()) as Record<string, unknown>),
|
||||
Tooltip: ({
|
||||
children,
|
||||
mouseEnterDelay,
|
||||
placement,
|
||||
title,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
mouseEnterDelay?: number;
|
||||
placement?: string;
|
||||
title?: ReactNode;
|
||||
}) => (
|
||||
<span
|
||||
data-mouse-enter-delay={String(mouseEnterDelay)}
|
||||
data-placement={placement}
|
||||
data-testid="local-file-tooltip"
|
||||
data-title={typeof title === 'string' ? title : undefined}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
),
|
||||
}));
|
||||
const tooltipPropsSpy = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => {
|
||||
const actual = await importOriginal<Record<string, unknown>>();
|
||||
const ActualTooltip = actual.Tooltip as ComponentType<TooltipProps>;
|
||||
return {
|
||||
...actual,
|
||||
Tooltip: (props: TooltipProps) => {
|
||||
tooltipPropsSpy(props);
|
||||
return <ActualTooltip {...props} />;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('LocalFileLink Render', () => {
|
||||
afterEach(() => {
|
||||
@@ -97,15 +88,13 @@ describe('LocalFileLink Render', () => {
|
||||
|
||||
const link = screen.getByRole('link', { name: 'Group.tsx' });
|
||||
|
||||
expect(screen.getByTestId('local-file-tooltip')).toHaveAttribute(
|
||||
'data-title',
|
||||
'/Users/me/project/src/Group.tsx (line 265)',
|
||||
expect(tooltipPropsSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
mouseEnterDelay: 0.1,
|
||||
placement: 'topLeft',
|
||||
title: '/Users/me/project/src/Group.tsx (line 265)',
|
||||
}),
|
||||
);
|
||||
expect(screen.getByTestId('local-file-tooltip')).toHaveAttribute(
|
||||
'data-mouse-enter-delay',
|
||||
'0.1',
|
||||
);
|
||||
expect(screen.getByTestId('local-file-tooltip')).toHaveAttribute('data-placement', 'topLeft');
|
||||
|
||||
fireEvent.click(link);
|
||||
|
||||
|
||||
+15
-35
@@ -2,48 +2,28 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ComponentType, ReactNode } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import Arguments from './index';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Highlighter: ({ children, wrap }: { children?: ReactNode; wrap?: boolean }) => (
|
||||
<pre data-testid="highlighter" data-wrap={String(Boolean(wrap))}>
|
||||
{children}
|
||||
</pre>
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({
|
||||
active,
|
||||
onClick,
|
||||
title,
|
||||
}: {
|
||||
active?: boolean;
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
}) => (
|
||||
<button aria-pressed={active} type="button" onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as Record<string, unknown>;
|
||||
return {
|
||||
...actual,
|
||||
ActionIcon: ({
|
||||
active,
|
||||
icon: IconComponent,
|
||||
onClick,
|
||||
title,
|
||||
}: {
|
||||
active?: boolean;
|
||||
icon?: ComponentType;
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
}) => (
|
||||
<button aria-pressed={active} type="button" onClick={onClick}>
|
||||
{title}
|
||||
{IconComponent ? <IconComponent /> : null}
|
||||
</button>
|
||||
),
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
Divider: () => <hr />,
|
||||
}));
|
||||
|
||||
vi.mock('@/components/Descriptions', () => ({
|
||||
default: ({
|
||||
items,
|
||||
|
||||
-14
@@ -2,7 +2,6 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import FallbackIntervention from './Fallback';
|
||||
@@ -13,19 +12,6 @@ const metaMap: Record<string, { avatar?: string; title?: string }> = {
|
||||
'search': { title: 'Web Search' },
|
||||
};
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<button {...props}>{children}</button>
|
||||
),
|
||||
Avatar: ({ avatar, title }: { avatar?: string; title?: string }) => (
|
||||
<img alt={title} src={avatar} />
|
||||
),
|
||||
Flexbox: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<div {...props}>{children}</div>
|
||||
),
|
||||
Icon: () => <span>icon</span>,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, options?: { count?: number; defaultValue?: string }) =>
|
||||
|
||||
+9
-18
@@ -1,23 +1,18 @@
|
||||
/**
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { WebOnboardingApiName } from '@lobechat/builtin-tool-web-onboarding';
|
||||
import { WebOnboardingInterventions } from '@lobechat/builtin-tool-web-onboarding/client';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Avatar: ({ avatar }: { avatar: string }) => <div>{avatar}</div>,
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
EmojiPicker: ({ onChange, value }: { onChange?: (next: string) => void; value?: string }) => (
|
||||
<button data-testid="emoji-picker" type="button" onClick={() => onChange?.('🪶')}>
|
||||
{value || ''}
|
||||
</button>
|
||||
),
|
||||
Flexbox: ({ children }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<div>{children}</div>
|
||||
),
|
||||
Text: ({ children, ...props }: { children?: ReactNode; [key: string]: unknown }) => (
|
||||
<span {...props}>{children}</span>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
@@ -38,13 +33,9 @@ vi.mock('react-i18next', () => ({
|
||||
}));
|
||||
|
||||
describe('web onboarding intervention registry', () => {
|
||||
let Component: ReturnType<typeof Object> | undefined;
|
||||
const Component = WebOnboardingInterventions[WebOnboardingApiName.saveUserQuestion];
|
||||
|
||||
beforeEach(async () => {
|
||||
const { WebOnboardingInterventions } =
|
||||
await import('@lobechat/builtin-tool-web-onboarding/client');
|
||||
const { WebOnboardingApiName } = await import('@lobechat/builtin-tool-web-onboarding');
|
||||
Component = WebOnboardingInterventions[WebOnboardingApiName.saveUserQuestion];
|
||||
it('registers the saveUserQuestion intervention', () => {
|
||||
expect(Component).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -90,8 +81,8 @@ describe('web onboarding intervention registry', () => {
|
||||
if (!Component) throw new TypeError('Expected web onboarding intervention to be registered');
|
||||
|
||||
const onArgsChange = vi.fn();
|
||||
let beforeApproveCallback: (() => Promise<void>) | undefined;
|
||||
const registerBeforeApprove = (_id: string, callback: () => Promise<void>) => {
|
||||
let beforeApproveCallback: (() => void | Promise<void>) | undefined;
|
||||
const registerBeforeApprove = (_id: string, callback: () => void | Promise<void>) => {
|
||||
beforeApproveCallback = callback;
|
||||
return () => {
|
||||
beforeApproveCallback = undefined;
|
||||
|
||||
-5
@@ -2,15 +2,10 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { act, cleanup, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import ExecutionTime from './ExecutionTime';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
describe('ExecutionTime', () => {
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
|
||||
@@ -15,15 +15,6 @@ const retryFailedAssistantStepMock = vi.fn();
|
||||
const navigateMock = vi.fn();
|
||||
let isInReasoningMock = false;
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Block: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Highlighter: ({ children }: { children?: ReactNode }) => <pre>{children}</pre>,
|
||||
Skeleton: {
|
||||
Button: () => <div>loading</div>,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
i18n: {
|
||||
@@ -69,10 +60,6 @@ vi.mock('@/features/Electron/HeterogeneousAgent/StatusGuide', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/useProviderName', () => ({
|
||||
useProviderName: () => 'Mock Provider',
|
||||
}));
|
||||
|
||||
+3
-17
@@ -2,26 +2,11 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import ContentBlocksScroll from './ContentBlocksScroll';
|
||||
import type { RenderableAssistantContentBlock } from './types';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children, gap }: { children?: ReactNode; gap?: number }) => (
|
||||
<div data-gap={gap}>{children}</div>
|
||||
),
|
||||
ScrollArea: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({
|
||||
scrollTask: 'scroll-task',
|
||||
scrollWorkflow: 'scroll-workflow',
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('./ContentBlock', () => ({
|
||||
default: ({ disableMarkdownStreaming, id }: RenderableAssistantContentBlock) => (
|
||||
<div
|
||||
@@ -66,7 +51,7 @@ describe('ContentBlocksScroll', () => {
|
||||
});
|
||||
|
||||
it('uses a consistent gap between workflow blocks', () => {
|
||||
const { container } = render(
|
||||
render(
|
||||
<ContentBlocksScroll
|
||||
assistantId="assistant-1"
|
||||
scroll={false}
|
||||
@@ -78,6 +63,7 @@ describe('ContentBlocksScroll', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container.querySelector('[data-gap="8"]')).toBeInTheDocument();
|
||||
const [firstBlock] = screen.getAllByTestId('content-block');
|
||||
expect(firstBlock.parentElement!.style.getPropertyValue('--lobe-flex-gap')).toBe('8px');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,16 +15,6 @@ let mockIsGenerating = false;
|
||||
let mockDbMessages: { createdAt?: Date | number | string | null; id: string }[] = [];
|
||||
let mockOperations: { metadata: Record<string, unknown>; status: string }[] = [];
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({
|
||||
container: 'group-container',
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/chat', () => ({
|
||||
useChatStore: (selector: (state: unknown) => unknown) => selector({}),
|
||||
}));
|
||||
|
||||
@@ -11,13 +11,6 @@ let mockStoreContent = 'original full content';
|
||||
let mockStoreHasTools = true;
|
||||
let mockStoreMessage: { createdAt?: number } | undefined = { createdAt: 1000 };
|
||||
|
||||
vi.mock('antd-style', () => ({
|
||||
createStaticStyles: () => ({
|
||||
pWithTool: 'tool-line',
|
||||
}),
|
||||
cx: (...values: unknown[]) => values.filter(Boolean).join(' '),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/Conversation/Markdown', () => ({
|
||||
default: ({ children, className }: { children?: ReactNode; className?: string }) => (
|
||||
<div className={className} data-testid="markdown">
|
||||
|
||||
+5
-20
@@ -11,7 +11,8 @@ import WorkflowCollapse from './WorkflowCollapse';
|
||||
|
||||
let mockIsGenerating = true;
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
Accordion: ({
|
||||
children,
|
||||
expandedKeys,
|
||||
@@ -64,8 +65,6 @@ vi.mock('@lobehub/ui', () => ({
|
||||
{IconComponent ? <IconComponent /> : null}
|
||||
</button>
|
||||
),
|
||||
Block: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Icon: ({ icon: IconComponent }: { icon?: ComponentType }) =>
|
||||
IconComponent ? (
|
||||
<div
|
||||
@@ -77,25 +76,11 @@ vi.mock('@lobehub/ui', () => ({
|
||||
) : (
|
||||
<div />
|
||||
),
|
||||
ShikiLobeTheme: {},
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({
|
||||
icon: IconComponent,
|
||||
onClick,
|
||||
title,
|
||||
}: {
|
||||
icon?: ComponentType;
|
||||
onClick?: (e: unknown) => void;
|
||||
title?: string;
|
||||
}) => (
|
||||
<button aria-label={title} type="button" onClick={onClick}>
|
||||
{IconComponent ? <IconComponent /> : null}
|
||||
</button>
|
||||
),
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
...(await import('~base-ui-stubs')).baseUiStubs,
|
||||
}));
|
||||
|
||||
vi.mock('motion/react', () => ({
|
||||
|
||||
-4
@@ -26,10 +26,6 @@ vi.mock('@/store/chat', () => ({
|
||||
selector({ activeTopicId: mocks.topicId, openTopicComments: mocks.openTopicComments }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
const build = () =>
|
||||
renderHook(() =>
|
||||
commentsAction.useBuild({
|
||||
|
||||
+4
-6
@@ -27,11 +27,13 @@ vi.mock('@lobehub/ui', () => ({
|
||||
copyToClipboard: mocks.copyToClipboard,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { success: mocks.messageSuccess },
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: { useApp: () => ({ message: { success: mocks.messageSuccess } }) },
|
||||
}));
|
||||
|
||||
@@ -68,10 +70,6 @@ vi.mock('@/store/user/selectors', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
const build = (
|
||||
data: Partial<UIChatMessage> = {},
|
||||
role: MessageActionContext['role'] = 'assistant',
|
||||
|
||||
@@ -16,10 +16,6 @@ vi.mock('../../../../store', () => ({
|
||||
selector({ deleteAssistantMessage, deleteMessage }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
// A group's id IS its head child's id — the assistantGroup bubble is a virtual
|
||||
// message built from the run's first assistant row. Fixtures mirror that.
|
||||
const build = (
|
||||
|
||||
-4
@@ -26,10 +26,6 @@ vi.mock('../../../../store', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
const build = (
|
||||
data: Partial<UIChatMessage>,
|
||||
role: MessageActionContext['role'] = 'assistant',
|
||||
|
||||
+4
-6
@@ -29,18 +29,16 @@ vi.mock('@/store/file', () => ({
|
||||
|
||||
const { messageSuccess } = vi.hoisted(() => ({ messageSuccess: vi.fn() }));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { success: messageSuccess },
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: { useApp: () => ({ message: { success: messageSuccess } }) },
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
const build = (data: Partial<UIChatMessage>, role: MessageActionContext['role'] = 'user') =>
|
||||
renderHook(() => restoreToInputAction.useBuild({ data: data as UIChatMessage, id: 'm1', role }))
|
||||
.result.current;
|
||||
|
||||
@@ -14,7 +14,8 @@ const actionMocks = vi.hoisted(() => ({
|
||||
commentsAvailable: true,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIconGroup: ({
|
||||
items,
|
||||
menu,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import type { ReactNode, Ref } from 'react';
|
||||
import type { Ref } from 'react';
|
||||
import { useImperativeHandle } from 'react';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -185,32 +185,11 @@ vi.mock('@/store/chat', () => ({
|
||||
|
||||
const messageSpy = vi.hoisted(() => ({ warning: vi.fn() }));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
message: messageSpy,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...((await importOriginal()) as Record<string, unknown>),
|
||||
ActionIcon: ({ onClick }: { onClick?: () => void }) => (
|
||||
<button type={'button'} onClick={onClick} />
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Center: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
copyToClipboard: vi.fn(),
|
||||
Empty: ({ description }: { description?: ReactNode }) => <div>{description}</div>,
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span />,
|
||||
stopPropagation: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as Record<string, unknown>;
|
||||
|
||||
|
||||
+3
-57
@@ -4,7 +4,6 @@ import {
|
||||
AGENT_DOCUMENT_SKILL_CATEGORY,
|
||||
AGENT_SIGNAL_SOURCE_TYPE,
|
||||
} from '@lobechat/const';
|
||||
import type { ErrorBoundary as LobeErrorBoundary } from '@lobehub/ui';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type * as ReactRouterDom from 'react-router';
|
||||
@@ -23,66 +22,13 @@ const removeDocumentMock = vi.hoisted(() => vi.fn());
|
||||
const useParamsMock = vi.hoisted(() => vi.fn());
|
||||
const documentExplorerShouldThrow = vi.hoisted(() => ({ current: false }));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ onClick, title }: { onClick?: (e: React.MouseEvent) => void; title?: string }) => (
|
||||
<button aria-label={title} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Alert: ({ message, title }: { message?: ReactNode; title?: ReactNode }) => (
|
||||
<div role="alert">
|
||||
<div>{title}</div>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
),
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
...(await import('~base-ui-stubs')).baseUiStubs,
|
||||
confirmModal: modalConfirm,
|
||||
createModal: vi.fn(),
|
||||
toast: { error: messageError, success: messageSuccess },
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => {
|
||||
const actual = await importOriginal<{ ErrorBoundary: typeof LobeErrorBoundary }>();
|
||||
return {
|
||||
Accordion: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
AccordionItem: ({ children, title }: { children?: ReactNode; title?: ReactNode }) => (
|
||||
<div>
|
||||
{title}
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
ActionIcon: ({
|
||||
onClick,
|
||||
title,
|
||||
}: {
|
||||
onClick?: (e: React.MouseEvent) => void;
|
||||
title?: string;
|
||||
}) => (
|
||||
<button aria-label={title} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Center: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Empty: ({ description }: { description?: ReactNode }) => <div>{description}</div>,
|
||||
ErrorBoundary: actual.ErrorBoundary,
|
||||
Flexbox: ({
|
||||
children,
|
||||
onClick,
|
||||
...props
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
onClick?: () => void;
|
||||
[key: string]: unknown;
|
||||
}) => (
|
||||
<div onClick={onClick} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
Highlighter: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Text: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@/components/NeuralNetworkLoading', () => ({
|
||||
default: () => <div data-testid="neural-network-loading" />,
|
||||
}));
|
||||
|
||||
@@ -5,27 +5,11 @@ import { FileItemHeader } from '../FileItem';
|
||||
|
||||
const mockRevealInFilesTab = vi.fn();
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as Record<string, unknown>;
|
||||
return {
|
||||
...actual,
|
||||
ActionIcon: ({ icon: _icon, title, onClick, ...rest }: any) => (
|
||||
<button aria-label={title} type="button" onClick={onClick} {...rest} />
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@/store/global', () => ({
|
||||
useGlobalStore: (selector: (s: any) => any) =>
|
||||
selector({ revealInFilesTab: mockRevealInFilesTab }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/AntdStaticMethods', () => ({
|
||||
message: { error: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
@@ -266,16 +266,11 @@ vi.mock('@/store/user/selectors', () => ({
|
||||
labPreferSelectors: { enableInAppBrowser: () => true },
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
vi.mock('@lobehub/ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({ onClick, title }: { onClick?: () => void; title?: string }) => (
|
||||
<button aria-label={title} type="button" onClick={onClick} />
|
||||
),
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span />,
|
||||
Skeleton: () => <div data-testid="params-loading" />,
|
||||
}));
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ import type * as ConversationStoreModule from '../store';
|
||||
import { useConversationStore } from '../store';
|
||||
import { useAgentMeta, useIsBuiltinAgent } from './useAgentMeta';
|
||||
|
||||
vi.mock('zustand/traditional');
|
||||
|
||||
// Mock the ConversationStore
|
||||
vi.mock('../store', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof ConversationStoreModule>();
|
||||
|
||||
@@ -27,10 +27,6 @@ vi.mock('@/features/ResourcePermission/useResourceAccess', () => ({
|
||||
useResourceAccess: (...args: unknown[]) => mocks.useResourceAccess(...(args as [])),
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/agent', () => ({
|
||||
useAgentStore: (selector: (state: typeof mocks.agentState) => unknown) =>
|
||||
selector(mocks.agentState),
|
||||
|
||||
@@ -9,7 +9,8 @@ import { confirmRemoveTopic } from './index';
|
||||
|
||||
const confirmModalMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
confirmModal: confirmModalMock,
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { DataSyncConfig } from '@lobechat/electron-client-ipc';
|
||||
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import LoginStep from './LoginStep';
|
||||
|
||||
const mockElectronState = vi.hoisted(() => ({
|
||||
clearRemoteServerSyncError: vi.fn(),
|
||||
connectRemoteServer: vi.fn(),
|
||||
@@ -19,56 +20,6 @@ vi.mock('@lobechat/electron-client-ipc', () => ({
|
||||
useWatchBroadcast: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => {
|
||||
const Button = ({
|
||||
children,
|
||||
disabled,
|
||||
onClick,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button disabled={disabled} type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
||||
return {
|
||||
Alert: ({ description, title }: { description?: ReactNode; title?: ReactNode }) => (
|
||||
<section>
|
||||
<h2>{title}</h2>
|
||||
<p>{description}</p>
|
||||
</section>
|
||||
),
|
||||
Button,
|
||||
Center: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
Flexbox: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span />,
|
||||
Input: (props: React.InputHTMLAttributes<HTMLInputElement>) => <input {...props} />,
|
||||
Text: ({ as, children }: { as?: 'p' | 'span'; children: ReactNode }) =>
|
||||
as === 'p' ? <p>{children}</p> : <span>{children}</span>,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
Divider: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', async (importOriginal) => {
|
||||
const actual = (await importOriginal()) as Record<string, unknown>;
|
||||
|
||||
return {
|
||||
...actual,
|
||||
createStaticStyles: () => ({}),
|
||||
cssVar: {
|
||||
colorFillSecondary: '#eee',
|
||||
colorTextDescription: '#888',
|
||||
colorTextSecondary: '#666',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string, options?: string | Record<string, string>) => {
|
||||
@@ -159,7 +110,6 @@ vi.mock('../components/LobeMessage', () => ({
|
||||
}));
|
||||
|
||||
const renderLoginStep = async (props: { mode?: 'onboarding' | 'status' } = {}) => {
|
||||
const { default: LoginStep } = await import('./LoginStep');
|
||||
const onBack = vi.fn();
|
||||
const onNext = vi.fn();
|
||||
|
||||
|
||||
@@ -32,12 +32,6 @@ const mockDocumentStore = {
|
||||
useFetchDocument,
|
||||
};
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('zustand-utils', () => ({
|
||||
createStoreUpdater: () => () => undefined,
|
||||
}));
|
||||
|
||||
@@ -39,14 +39,6 @@ vi.mock('@lobehub/editor', () => ({
|
||||
ReactToolbarPlugin: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ onClick, title }: { onClick?: (e: any) => void; title?: string }) => (
|
||||
<button aria-label={title} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/ChatInput/InputEditor/plugins', () => ({
|
||||
createChatInputRichPlugins: () => [],
|
||||
}));
|
||||
|
||||
@@ -11,17 +11,9 @@ const messageLoadingMock = vi.hoisted(() => vi.fn());
|
||||
const messageDestroyMock = vi.hoisted(() => vi.fn());
|
||||
const messageErrorMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
toast: {
|
||||
error: messageErrorMock,
|
||||
loading: messageLoadingMock,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: messageErrorMock, loading: messageLoadingMock },
|
||||
}));
|
||||
|
||||
vi.mock('react-router', async () => {
|
||||
|
||||
@@ -3,11 +3,9 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { openEditorModal } from '.';
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: () => null,
|
||||
createModal: vi.fn(() => ({ close: vi.fn(), destroy: vi.fn(), update: vi.fn() })),
|
||||
ModalFooter: () => null,
|
||||
useModalContext: () => ({ close: vi.fn() }),
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
...(await import('~base-ui-stubs')).baseUiStubs,
|
||||
}));
|
||||
|
||||
vi.mock('./EditorModalContent', () => ({ default: () => null }));
|
||||
|
||||
@@ -42,46 +42,13 @@ vi.mock('@lobechat/electron-client-ipc', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
disabled,
|
||||
onClick,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button disabled={disabled} type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
Icon: () => <span data-testid="modal-icon" />,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
Button: ({
|
||||
children,
|
||||
disabled,
|
||||
loading,
|
||||
onClick,
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
onClick?: () => void;
|
||||
}) => (
|
||||
<button disabled={disabled || loading} type="button" onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
createModal: (props: ModalProps) => {
|
||||
createModalMock(props);
|
||||
|
||||
return modalInstance;
|
||||
},
|
||||
ModalFooter: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
|
||||
@@ -13,10 +13,6 @@ vi.mock('@lobechat/electron-client-ipc', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('motion/react', async () => {
|
||||
const React = await import('react');
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import NavigationBar from './NavigationBar';
|
||||
@@ -14,32 +13,11 @@ vi.mock('@lobechat/electron-client-ipc', () => ({
|
||||
useWatchBroadcast: (event: string, handler: () => void) => mocks.handlers.set(event, handler),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({ icon: _icon, ...props }: Record<string, unknown>) => <button {...props} />,
|
||||
Flexbox: ({ children, ...props }: { children: ReactNode }) => <div {...props}>{children}</div>,
|
||||
Popover: ({
|
||||
children,
|
||||
content,
|
||||
open,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
content: ReactNode;
|
||||
open: boolean;
|
||||
}) => (
|
||||
<div>
|
||||
{children}
|
||||
{open && content}
|
||||
</div>
|
||||
),
|
||||
Tooltip: ({ children }: { children: ReactNode }) => children,
|
||||
}));
|
||||
|
||||
vi.mock('antd-style', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
createStaticStyles: () => ({ clock: 'clock' }),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }) }));
|
||||
vi.mock('@/features/NavPanel/ToggleLeftPanelButton', () => ({ default: () => null }));
|
||||
vi.mock('@/features/Workspace/useWorkspaceAwareNavigate', () => ({
|
||||
useWorkspaceAwareNavigate: () => mocks.navigate,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { AGENT_DOCUMENT_CATEGORY, CUSTOM_FOLDER_FILE_TYPE } from '@lobechat/const';
|
||||
import { act, fireEvent, render, waitFor } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
@@ -15,19 +14,6 @@ import ExplorerTree, { getItemPathFromEventPath } from './ExplorerTree';
|
||||
|
||||
const showContextMenu = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({ onClick, title }: { onClick?: () => void; title?: string }) => (
|
||||
<button aria-label={title} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Flexbox: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
|
||||
genCdnUrl: () => '',
|
||||
Icon: () => <span />,
|
||||
showContextMenu,
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('@/libs/contextMenu', () => ({
|
||||
showContextMenu,
|
||||
}));
|
||||
@@ -36,18 +22,8 @@ vi.mock('@lobehub/ui/icons', () => ({
|
||||
SkillsIcon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
ActionIcon: ({ onClick, title }: { onClick?: () => void; title?: string }) => (
|
||||
<button aria-label={title} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
confirmModal: vi.fn(),
|
||||
DropdownMenu: ({ children }: { children: ReactNode }) => children,
|
||||
Text: ({ children }: { children?: ReactNode }) => <span>{children}</span>,
|
||||
}));
|
||||
|
||||
vi.mock('antd', () => ({
|
||||
vi.mock('antd', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
App: {
|
||||
useApp: () => ({
|
||||
message: { error: vi.fn(), success: vi.fn(), warning: vi.fn() },
|
||||
@@ -66,12 +42,6 @@ vi.mock('@/features/Workspace/useWorkspaceAwareNavigate', () => ({
|
||||
useWorkspaceAwareNavigate: () => vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
const dispatchRealContextMenuEventRetargetedPastShadowRoot = (
|
||||
shadowRow: HTMLElement,
|
||||
shadowHost: Element,
|
||||
|
||||
@@ -2,39 +2,11 @@
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import ChatBody from './ChatBody';
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Flexbox: ({
|
||||
children,
|
||||
flex,
|
||||
height,
|
||||
style,
|
||||
width,
|
||||
...props
|
||||
}: {
|
||||
children?: ReactNode;
|
||||
flex?: number;
|
||||
height?: string;
|
||||
style?: CSSProperties;
|
||||
width?: string;
|
||||
[key: string]: unknown;
|
||||
}) => (
|
||||
<div
|
||||
data-flex={flex === undefined ? '' : String(flex)}
|
||||
data-height={height ?? ''}
|
||||
data-width={width ?? ''}
|
||||
style={style}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/Conversation', () => ({
|
||||
ChatList: ({ welcome }: { welcome?: ReactNode }) => (
|
||||
<div data-testid="floating-chat-list">
|
||||
@@ -54,8 +26,8 @@ describe('FloatingChatPanel ChatBody', () => {
|
||||
const body = screen.getByTestId('floating-chat-panel-body');
|
||||
const list = screen.getByTestId('floating-chat-list');
|
||||
|
||||
expect(body).toHaveAttribute('data-flex', '1');
|
||||
expect(body).toHaveAttribute('data-height', '100%');
|
||||
expect(body.style.getPropertyValue('--lobe-flex')).toBe('1');
|
||||
expect(body.style.getPropertyValue('--lobe-flex-height')).toBe('100%');
|
||||
expect(body).toContainElement(list);
|
||||
expect(list).toContainElement(screen.getByTestId('agent-welcome'));
|
||||
expect(body).toHaveStyle({ overflow: 'hidden' });
|
||||
|
||||
@@ -45,10 +45,6 @@ vi.mock('@/features/Conversation/store', () => ({
|
||||
selector(mockConversationState.current),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
Icon: ({ icon }: { icon: () => void }) => <span data-testid="icon">{icon.name}</span>,
|
||||
}));
|
||||
|
||||
describe('FloatingChatPanel InputRow', () => {
|
||||
it('does not render the expand affordance when disabled', () => {
|
||||
render(<InputRow isCollapsed={false} showExpandBar={false} onExpand={() => {}} />);
|
||||
|
||||
@@ -16,7 +16,8 @@ const sheetHandlers = vi.hoisted(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
ActionIcon: ({
|
||||
onClick,
|
||||
title,
|
||||
@@ -77,28 +78,6 @@ vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui', () => ({
|
||||
ActionIcon: ({
|
||||
onClick,
|
||||
title,
|
||||
...rest
|
||||
}: {
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
[key: string]: unknown;
|
||||
}) => (
|
||||
<button
|
||||
data-testid={(rest as any)['data-testid']}
|
||||
title={title}
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
>
|
||||
{title}
|
||||
</button>
|
||||
),
|
||||
Icon: ({ icon }: { icon: () => void }) => <span data-icon={icon.name} />,
|
||||
}));
|
||||
|
||||
const mergedHooksCaptured = vi.hoisted(() => ({
|
||||
current: undefined as
|
||||
| undefined
|
||||
|
||||
@@ -26,10 +26,6 @@ const mocks = vi.hoisted(() => ({
|
||||
sidebarVisibilityOverrides: {} as Record<string, boolean>,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/business/client/hooks/useActiveWorkspaceId', () => ({
|
||||
useActiveWorkspaceId: () => mocks.activeWorkspaceId,
|
||||
}));
|
||||
|
||||
@@ -91,11 +91,8 @@ const activeWorkspaceIdMock = vi.hoisted(() => ({
|
||||
value: null as string | null,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
toast: { error: messageErrorMock },
|
||||
}));
|
||||
|
||||
|
||||
@@ -41,11 +41,8 @@ vi.mock('antd', async (importOriginal) => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
|
||||
...(await importOriginal<object>()),
|
||||
confirmModal: mocks.confirmModal,
|
||||
toast: { error: mocks.toastError, success: vi.fn() },
|
||||
}));
|
||||
|
||||
@@ -12,23 +12,10 @@ vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@lobehub/ui/base-ui', () => ({
|
||||
confirmModal: vi.fn(),
|
||||
toast: { error: vi.fn(), success: vi.fn() },
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}));
|
||||
|
||||
vi.mock('@/business/client/hooks/useActiveWorkspaceId', () => ({
|
||||
useActiveWorkspaceId: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('@/hooks/usePermission', () => ({
|
||||
usePermission: () => ({ allowed: true }),
|
||||
}));
|
||||
|
||||
vi.mock('@/libs/trpc/client', () => ({
|
||||
lambdaClient: {},
|
||||
}));
|
||||
|
||||
@@ -12,12 +12,6 @@ vi.mock('@lobehub/ui', () => ({
|
||||
Icon: () => null,
|
||||
}));
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/HomeSidebar/Body/CustomizeSidebarModal', () => ({
|
||||
openCustomizeSidebarModal: vi.fn(),
|
||||
}));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user