Makelore 2.0 initial clean snapshot
This commit is contained in:
161
tests/unit/setup-page.test.tsx
Normal file
161
tests/unit/setup-page.test.tsx
Normal file
@@ -0,0 +1,161 @@
|
||||
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 { useOpencodeStore } from '@/stores/opencode';
|
||||
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,
|
||||
});
|
||||
useOpencodeStore.setState({
|
||||
status: { state: 'stopped', port: 4096 },
|
||||
health: null,
|
||||
healthCheckedAt: null,
|
||||
runtimeConfigSummary: null,
|
||||
projects: [],
|
||||
activeProject: null,
|
||||
sessions: [],
|
||||
sessionsByProjectId: {},
|
||||
selectedSessionId: null,
|
||||
sessionStatuses: {},
|
||||
sessionMessages: [],
|
||||
sessionMessagesBySessionId: {},
|
||||
streamingMessage: null,
|
||||
streamingMessagesBySessionId: {},
|
||||
streamingTools: [],
|
||||
streamingToolsBySessionId: {},
|
||||
sendingSessionId: null,
|
||||
sendingSessionIds: {},
|
||||
queuedSessionPrompts: {},
|
||||
sessionDiffs: [],
|
||||
sessionDiffLoading: false,
|
||||
sessionDiffError: null,
|
||||
fileStatuses: [],
|
||||
fileSearchResults: [],
|
||||
contentSearchResults: [],
|
||||
selectedContextFile: null,
|
||||
fileContextLoading: false,
|
||||
fileContextError: null,
|
||||
runtimeAutoStartAttempted: false,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
|
||||
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({ state: 'stopped', port: 4096 });
|
||||
|
||||
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.opencode')).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: 'runtime.viewLogs' })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows only a retry action when runtime checks fail', async () => {
|
||||
hostApiFetchMock.mockResolvedValue({
|
||||
state: 'error',
|
||||
error: 'missing bundled runtime package at /very/noisy/path',
|
||||
});
|
||||
|
||||
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({ state: 'stopped', port: 4096 });
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user