Files
makelore/tests/unit/setup-page.test.tsx
brother7 5a275b93a7 feat: remove legacy OpenCode runtime
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.
2026-08-24 12:17:43 +08:00

125 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
});
});