diff --git a/web/frontend/src/__tests__/execution-mode-unification.test.ts b/web/frontend/src/__tests__/execution-mode-unification.test.ts index 3beec72..6b526cf 100644 --- a/web/frontend/src/__tests__/execution-mode-unification.test.ts +++ b/web/frontend/src/__tests__/execution-mode-unification.test.ts @@ -144,7 +144,7 @@ describe('KIN-FIX-002: execution_mode унификация на "auto_complete"' const router = makeRouter() await router.push('/task/KIN-001') - const wrapper = mount(TaskDetail, { + mount(TaskDetail, { props: { id: 'KIN-001' }, global: { plugins: [router] }, }) @@ -191,7 +191,7 @@ describe('KIN-FIX-002: execution_mode унификация на "auto_complete"' const router = makeRouter() await router.push('/project/KIN') - const wrapper = mount(ProjectView, { + mount(ProjectView, { props: { id: 'KIN' }, global: { plugins: [router] }, }) @@ -278,7 +278,7 @@ describe('KIN-FIX-002: execution_mode унификация на "auto_complete"' const router = makeRouter() await router.push('/task/KIN-001') - const wrapper = mount(TaskDetail, { + mount(TaskDetail, { props: { id: 'KIN-001' }, global: { plugins: [router] }, }) @@ -291,3 +291,159 @@ describe('KIN-FIX-002: execution_mode унификация на "auto_complete"' }) }) }) + +describe('KIN-077: кнопка Review/Auto — regression (400 Bad Request fix)', () => { + describe('ProjectView — patchProject вызывается с корректным enum-значением', () => { + it('при переключении review→auto отправляет "auto_complete", не "auto"', async () => { + const projectReview = { ...MOCK_PROJECT, execution_mode: 'review' } + vi.mocked(api.project).mockResolvedValue(projectReview as any) + vi.mocked(api.patchProject).mockResolvedValue({ execution_mode: 'auto_complete' } as any) + + const router = makeRouter() + await router.push('/project/KIN') + + const wrapper = mount(ProjectView, { + props: { id: 'KIN' }, + global: { plugins: [router] }, + }) + await flushPromises() + + const toggleBtn = wrapper.findAll('button').find(b => + b.text().includes('Review') || b.text().includes('Auto') + ) + expect(toggleBtn, 'кнопка тоггла должна быть найдена').toBeDefined() + + await toggleBtn!.trigger('click') + await flushPromises() + + // Главная проверка: patchProject вызван с 'auto_complete', не 'auto' (причина 400) + expect(vi.mocked(api.patchProject)).toHaveBeenCalledWith('KIN', { + execution_mode: 'auto_complete', + }) + const callArg = vi.mocked(api.patchProject).mock.calls[0][1] as { execution_mode: string } + expect(callArg.execution_mode).not.toBe('auto') + }) + + it('при переключении auto→review отправляет "review"', async () => { + const projectAuto = { ...MOCK_PROJECT, execution_mode: 'auto_complete' } + vi.mocked(api.project).mockResolvedValue(projectAuto as any) + vi.mocked(api.patchProject).mockResolvedValue({ execution_mode: 'review' } as any) + + const router = makeRouter() + await router.push('/project/KIN') + + const wrapper = mount(ProjectView, { + props: { id: 'KIN' }, + global: { plugins: [router] }, + }) + await flushPromises() + + const toggleBtn = wrapper.findAll('button').find(b => + b.text().includes('Auto') || b.text().includes('Review') + ) + expect(toggleBtn).toBeDefined() + + await toggleBtn!.trigger('click') + await flushPromises() + + expect(vi.mocked(api.patchProject)).toHaveBeenCalledWith('KIN', { + execution_mode: 'review', + }) + }) + }) + + describe('ProjectView — кнопка отображает актуальный режим', () => { + it('когда проект в режиме "review" — кнопка показывает "Review"', async () => { + const projectReview = { ...MOCK_PROJECT, execution_mode: 'review' } + vi.mocked(api.project).mockResolvedValue(projectReview as any) + + const router = makeRouter() + await router.push('/project/KIN') + + const wrapper = mount(ProjectView, { + props: { id: 'KIN' }, + global: { plugins: [router] }, + }) + await flushPromises() + + const toggleBtn = wrapper.findAll('button').find(b => + b.text().includes('Review') || b.text().includes('Auto') + ) + expect(toggleBtn).toBeDefined() + expect(toggleBtn!.text()).toContain('Review') + }) + + it('когда проект в режиме "auto_complete" — кнопка показывает "Auto"', async () => { + const projectAuto = { ...MOCK_PROJECT, execution_mode: 'auto_complete' } + vi.mocked(api.project).mockResolvedValue(projectAuto as any) + + const router = makeRouter() + await router.push('/project/KIN') + + const wrapper = mount(ProjectView, { + props: { id: 'KIN' }, + global: { plugins: [router] }, + }) + await flushPromises() + + const toggleBtn = wrapper.findAll('button').find(b => + b.text().includes('Auto') || b.text().includes('Review') + ) + expect(toggleBtn).toBeDefined() + expect(toggleBtn!.text()).toContain('Auto') + }) + + it('после клика review→auto кнопка меняет текст на "Auto"', async () => { + const projectReview = { ...MOCK_PROJECT, execution_mode: 'review' } + vi.mocked(api.project).mockResolvedValue(projectReview as any) + vi.mocked(api.patchProject).mockResolvedValue({ execution_mode: 'auto_complete' } as any) + + const router = makeRouter() + await router.push('/project/KIN') + + const wrapper = mount(ProjectView, { + props: { id: 'KIN' }, + global: { plugins: [router] }, + }) + await flushPromises() + + const findToggleBtn = () => + wrapper.findAll('button').find(b => b.text().includes('Auto') || b.text().includes('Review')) + + expect(findToggleBtn()!.text()).toContain('Review') + + await findToggleBtn()!.trigger('click') + await flushPromises() + + expect(findToggleBtn()!.text()).toContain('Auto') + }) + + it('двойной клик возвращает кнопку обратно в "Review"', async () => { + const projectReview = { ...MOCK_PROJECT, execution_mode: 'review' } + vi.mocked(api.project).mockResolvedValue(projectReview as any) + vi.mocked(api.patchProject) + .mockResolvedValueOnce({ execution_mode: 'auto_complete' } as any) + .mockResolvedValueOnce({ execution_mode: 'review' } as any) + + const router = makeRouter() + await router.push('/project/KIN') + + const wrapper = mount(ProjectView, { + props: { id: 'KIN' }, + global: { plugins: [router] }, + }) + await flushPromises() + + const findToggleBtn = () => + wrapper.findAll('button').find(b => b.text().includes('Auto') || b.text().includes('Review')) + + await findToggleBtn()!.trigger('click') + await flushPromises() + expect(findToggleBtn()!.text()).toContain('Auto') + + await findToggleBtn()!.trigger('click') + await flushPromises() + expect(findToggleBtn()!.text()).toContain('Review') + }) + }) +})