Cut product flows over to Coding/Pi and retain only the migration-owned v1 boundary. Promote supported native optional packages because electron-builder omitted pnpm transitive optional closure from the packaged ASAR.
125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import { MemoryRouter } from 'react-router-dom';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import Setup from '@/pages/Setup';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import { useSettingsStore } from '@/stores/settings';
|
|
|
|
const { hostApiFetchMock, translateMock } = vi.hoisted(() => ({
|
|
hostApiFetchMock: vi.fn(),
|
|
translateMock: vi.fn((key: string, options?: { returnObjects?: boolean }) => (
|
|
options?.returnObjects ? [`${key}.0`, `${key}.1`, `${key}.2`] : key
|
|
)),
|
|
}));
|
|
|
|
vi.mock('@/lib/host-api', () => ({
|
|
hostApiFetch: (...args: unknown[]) => hostApiFetchMock(...args),
|
|
}));
|
|
|
|
vi.mock('@/lib/api-client', () => ({
|
|
invokeIpc: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('react-i18next', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('react-i18next')>();
|
|
return {
|
|
...actual,
|
|
useTranslation: () => ({
|
|
t: translateMock,
|
|
}),
|
|
};
|
|
});
|
|
|
|
vi.mock('sonner', () => ({
|
|
toast: {
|
|
success: vi.fn(),
|
|
error: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
function renderSetup() {
|
|
return render(
|
|
<MemoryRouter initialEntries={['/setup']}>
|
|
<Setup />
|
|
</MemoryRouter>,
|
|
);
|
|
}
|
|
|
|
function resetStores() {
|
|
useAuthStore.setState({ user: null });
|
|
useSettingsStore.setState({
|
|
setupComplete: false,
|
|
theme: 'system',
|
|
language: 'en',
|
|
launchAtStartup: false,
|
|
telemetryEnabled: false,
|
|
proxyEnabled: false,
|
|
proxyServer: '',
|
|
proxyHttpServer: '',
|
|
proxyHttpsServer: '',
|
|
proxyAllServer: '',
|
|
proxyBypassRules: '',
|
|
sidebarCollapsed: false,
|
|
devModeUnlocked: false,
|
|
});
|
|
}
|
|
|
|
describe('Setup first-run progress flow', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
resetStores();
|
|
});
|
|
|
|
it('greets the authenticated user by the normalized account name', () => {
|
|
useAuthStore.setState({
|
|
user: { username: 'zhangsan@example.com', userId: 'user-1', tenantId: null, deptId: null, authorities: [] },
|
|
});
|
|
|
|
renderSetup();
|
|
|
|
expect(screen.getByRole('heading', { name: 'zhangsan,欢迎回来!' })).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders runtime checks as a quiet progress flow without dependency details', async () => {
|
|
hostApiFetchMock.mockResolvedValue({ runtime: 'pi' });
|
|
|
|
renderSetup();
|
|
|
|
fireEvent.click(screen.getByTestId('setup-next-button'));
|
|
|
|
expect(await screen.findByTestId('setup-runtime-progress')).toBeInTheDocument();
|
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
|
expect(screen.queryByText('runtime.nodejs')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('runtime.codingRuntime')).not.toBeInTheDocument();
|
|
expect(screen.queryByRole('button', { name: 'runtime.viewLogs' })).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('shows only a retry action when runtime checks fail', async () => {
|
|
hostApiFetchMock.mockResolvedValue({ runtime: 'unavailable' });
|
|
|
|
renderSetup();
|
|
|
|
fireEvent.click(screen.getByTestId('setup-next-button'));
|
|
|
|
expect(await screen.findByTestId('setup-runtime-retry')).toBeInTheDocument();
|
|
expect(screen.queryByText(/missing bundled runtime package/)).not.toBeInTheDocument();
|
|
expect(screen.queryByRole('button', { name: 'runtime.viewLogs' })).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('keeps dependency installation focused on overall progress', async () => {
|
|
hostApiFetchMock.mockResolvedValue({ runtime: 'pi' });
|
|
|
|
renderSetup();
|
|
|
|
fireEvent.click(screen.getByTestId('setup-next-button'));
|
|
|
|
await waitFor(() => expect(screen.getByTestId('setup-next-button')).toBeEnabled());
|
|
fireEvent.click(screen.getByTestId('setup-next-button'));
|
|
|
|
expect(await screen.findByTestId('setup-installing-progress')).toBeInTheDocument();
|
|
expect(screen.queryByText('defaultSkills.python-env.name')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('defaultSkills.file-tools.name')).not.toBeInTheDocument();
|
|
expect(screen.queryByRole('button', { name: 'installing.skip' })).not.toBeInTheDocument();
|
|
});
|
|
});
|