完善客户端模块与工作区能力
This commit is contained in:
@@ -50,6 +50,14 @@ function renderSettings() {
|
||||
);
|
||||
}
|
||||
|
||||
async function unlockAdditionalSettings(): Promise<void> {
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
const passwordInput = await screen.findByTestId('settings-admin-password-input');
|
||||
fireEvent.change(passwordInput, { target: { value: 'zhiniankeji666' } });
|
||||
fireEvent.click(screen.getByTestId('settings-admin-unlock-button'));
|
||||
await screen.findByTestId('settings-opencode-workspace');
|
||||
}
|
||||
|
||||
function mockValidatedWorkspaceHostApi(activeProject: {
|
||||
id: string;
|
||||
path: string;
|
||||
@@ -98,7 +106,12 @@ function mockValidatedWorkspaceHostApi(activeProject: {
|
||||
describe('Settings runtime workspace', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
invokeIpcMock.mockResolvedValue(undefined);
|
||||
invokeIpcMock.mockImplementation(async (channel: string, payload?: unknown) => {
|
||||
if (channel === 'admin:isUnlocked') return false;
|
||||
if (channel === 'admin:verifyPassword') return { success: payload === 'zhiniankeji666' };
|
||||
if (channel === 'admin:lock') return { success: true };
|
||||
return undefined;
|
||||
});
|
||||
useSettingsStore.setState({
|
||||
theme: 'system',
|
||||
language: 'en',
|
||||
@@ -148,7 +161,7 @@ describe('Settings runtime workspace', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('hides non-general settings until the general header reveal button is clicked', async () => {
|
||||
it('keeps runtime status and updates public while protecting developer settings', async () => {
|
||||
const activeProject = {
|
||||
id: 'prj_1',
|
||||
path: 'D:/repo/packages/ui',
|
||||
@@ -162,20 +175,35 @@ describe('Settings runtime workspace', () => {
|
||||
renderSettings();
|
||||
|
||||
expect(await screen.findByRole('heading', { name: 'appearance.title' })).toBeInTheDocument();
|
||||
expect(screen.getByTestId('settings-opencode-workspace').closest('[data-state]')).toHaveAttribute('data-state', 'closed');
|
||||
expect(screen.getByText('Network').closest('[data-state]')).toHaveAttribute('data-state', 'closed');
|
||||
expect(screen.getByText('updates.title').closest('[data-state]')).toHaveAttribute('data-state', 'closed');
|
||||
expect(screen.getByText('advanced.title').closest('[data-state]')).toHaveAttribute('data-state', 'closed');
|
||||
expect(screen.getByTestId('settings-runtime-summary')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Restart runtime' })).toBeInTheDocument();
|
||||
expect(screen.getByText('updates.title')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('settings-opencode-workspace')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Network')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('advanced.title')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
|
||||
expect(await screen.findByTestId('settings-opencode-workspace')).toBeInTheDocument();
|
||||
expect(screen.getByText('Network')).toBeInTheDocument();
|
||||
expect(screen.getByText('updates.title')).toBeInTheDocument();
|
||||
expect(screen.getByText('advanced.title')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('settings-admin-password-dialog')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('settings-opencode-workspace')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders runtime, model, and workspace controls in settings without exposing the runtime brand', async () => {
|
||||
it('rejects an incorrect administrator password and unlocks the protected settings with the fixed password', async () => {
|
||||
renderSettings();
|
||||
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
fireEvent.change(screen.getByTestId('settings-admin-password-input'), { target: { value: 'wrong' } });
|
||||
fireEvent.click(screen.getByTestId('settings-admin-unlock-button'));
|
||||
|
||||
expect(await screen.findByRole('alert')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('settings-opencode-workspace')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.change(screen.getByTestId('settings-admin-password-input'), { target: { value: 'zhiniankeji666' } });
|
||||
fireEvent.click(screen.getByTestId('settings-admin-unlock-button'));
|
||||
expect(await screen.findByTestId('settings-opencode-workspace')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders runtime, model, and workspace controls after administrator unlock without exposing the runtime brand', async () => {
|
||||
const activeProject = {
|
||||
id: 'prj_1',
|
||||
path: 'D:/repo/packages/ui',
|
||||
@@ -188,30 +216,21 @@ describe('Settings runtime workspace', () => {
|
||||
mockValidatedWorkspaceHostApi(activeProject);
|
||||
|
||||
renderSettings();
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
await unlockAdditionalSettings();
|
||||
|
||||
const workspace = await screen.findByTestId('settings-opencode-workspace');
|
||||
expect(within(workspace).getByText('Workspace')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('settings-opencode-runtime')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('settings-runtime-summary')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('settings-opencode-models')).toBeInTheDocument();
|
||||
expect(screen.getByText('openai/gpt-5.4')).toBeInTheDocument();
|
||||
expect(screen.getByText('openai/gpt-5.4-mini')).toBeInTheDocument();
|
||||
expect(screen.getByText('2 providers')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('D:/repo/packages/ui').length).toBeGreaterThan(0);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(hostApiFetchMock).toHaveBeenCalledWith('/api/opencode/start', {
|
||||
method: 'POST',
|
||||
})
|
||||
);
|
||||
expect(screen.getByRole('button', { name: 'Restart runtime' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Stop runtime' })).toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: 'Stop runtime' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: 'Check health' })).not.toBeInTheDocument();
|
||||
expect(document.body.textContent).not.toMatch(/opencode/i);
|
||||
expect(screen.queryByLabelText(/opencode/i)).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Check health' }));
|
||||
|
||||
await waitFor(() => expect(hostApiFetchMock).toHaveBeenCalledWith('/api/opencode/health'));
|
||||
});
|
||||
|
||||
it('opens the model configuration page from the workspace models card', async () => {
|
||||
@@ -226,7 +245,7 @@ describe('Settings runtime workspace', () => {
|
||||
mockValidatedWorkspaceHostApi(activeProject);
|
||||
|
||||
renderSettings();
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
await unlockAdditionalSettings();
|
||||
|
||||
const modelsCard = await screen.findByTestId('settings-opencode-models');
|
||||
fireEvent.click(within(modelsCard).getByRole('button', { name: 'Configure models' }));
|
||||
@@ -261,7 +280,7 @@ describe('Settings runtime workspace', () => {
|
||||
});
|
||||
|
||||
renderSettings();
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
await unlockAdditionalSettings();
|
||||
fireEvent.click(await screen.findByRole('button', { name: `Use project ${activeProject.name}` }));
|
||||
|
||||
expect(await screen.findByText(/configuration is missing/i)).toBeInTheDocument();
|
||||
@@ -304,7 +323,7 @@ describe('Settings runtime workspace', () => {
|
||||
});
|
||||
|
||||
renderSettings();
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'appearance.showMoreSettings' }));
|
||||
await unlockAdditionalSettings();
|
||||
fireEvent.click(await screen.findByRole('button', { name: `Use project ${activeProject.name}` }));
|
||||
|
||||
await waitFor(() => {
|
||||
|
||||
Reference in New Issue
Block a user