模型选择保存期间禁用选项,避免并发选择竞态
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m25s
Project CI / Backend tests (pull_request) Failing after 9s
Project CI / Native shell tests (pull_request) Successful in 18m11s

针对 review 提出的 P2:保存 select_game_creator_model 期间重新打开菜单再选一次会挂起两条 invoke,完成第一条即解锁发送导致显示/配置错乱

保存期间禁用下拉选项(可查看菜单,不可再选),保存完成后恢复;补充并发回归测试
This commit is contained in:
2026-09-07 17:28:16 +08:00
parent 2703acda84
commit 2e5dc57e9d
2 changed files with 40 additions and 0 deletions
@@ -160,6 +160,7 @@ export function ConversationModelSelect({
type="button"
role="option"
aria-selected={model.id === selected}
disabled={disabled || busy}
onClick={() => {
setOpen(false);
void select(model.id);
@@ -137,3 +137,42 @@ test('marks the default model in the menu', async () => {
const fastOption = screen.getByRole('option', { name: '快速' });
expect(within(fastOption).queryByText('默认')).toBeNull();
});
test('keeps model options disabled while a selection save is in flight', async () => {
let resolveSave: ((value: unknown) => void) | undefined;
invoke.mockImplementation(async (command, input) => {
if (command === 'select_game_creator_model') {
return new Promise((resolve) => {
resolveSave = resolve;
});
}
return { config: { selectedModelId: 'quality' } };
});
const onReady = vi.fn();
render(<ConversationModelSelect disabled={false} onReady={onReady} />);
await screen.findByRole('button', { name: '对话模型' });
await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true));
fireEvent.click(screen.getByRole('button', { name: '对话模型' }));
await screen.findByRole('option', { name: '快速' });
fireEvent.click(screen.getByRole('option', { name: '快速' }));
// 保存期间重新打开菜单:可以查看,但选项应禁用,避免并发选择。
fireEvent.click(screen.getByRole('button', { name: '对话模型' }));
expect(screen.getByRole('option', { name: '快速' })).toHaveProperty(
'disabled',
true,
);
expect(screen.getByRole('option', { name: /高质量/ })).toHaveProperty(
'disabled',
true,
);
expect(onReady).toHaveBeenLastCalledWith(false);
resolveSave?.({ config: { selectedModelId: 'fast' } });
await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true));
expect(screen.getByRole('option', { name: '快速' })).toHaveProperty(
'disabled',
false,
);
});