kin: KIN-021 Аудит-лог для --dangerously-skip-permissions в auto mode

This commit is contained in:
Gros Frumos 2026-03-16 07:13:32 +02:00
parent 67071c757d
commit a0b0976d8d
16 changed files with 1477 additions and 14 deletions

View file

@ -27,6 +27,7 @@ vi.mock('../api', () => ({
auditProject: vi.fn(),
createTask: vi.fn(),
patchTask: vi.fn(),
patchProject: vi.fn(),
},
}))
@ -509,3 +510,115 @@ describe('KIN-047: TaskDetail — Approve/Reject в статусе review', () =
}
})
})
// ─────────────────────────────────────────────────────────────
// KIN-065: Autocommit toggle в ProjectView
// ─────────────────────────────────────────────────────────────
describe('KIN-065: ProjectView — Autocommit toggle', () => {
it('Кнопка Autocommit присутствует в DOM', async () => {
const router = makeRouter()
await router.push('/project/KIN')
const wrapper = mount(ProjectView, {
props: { id: 'KIN' },
global: { plugins: [router] },
})
await flushPromises()
const btn = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
expect(btn?.exists()).toBe(true)
})
it('Кнопка имеет title "Autocommit: off" когда autocommit_enabled=0', async () => {
vi.mocked(api.project).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 0 } as any)
const router = makeRouter()
await router.push('/project/KIN')
const wrapper = mount(ProjectView, {
props: { id: 'KIN' },
global: { plugins: [router] },
})
await flushPromises()
const btn = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
expect(btn?.attributes('title')).toBe('Autocommit: off')
})
it('Кнопка имеет title "Autocommit: on..." когда autocommit_enabled=1', async () => {
vi.mocked(api.project).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 1 } as any)
const router = makeRouter()
await router.push('/project/KIN')
const wrapper = mount(ProjectView, {
props: { id: 'KIN' },
global: { plugins: [router] },
})
await flushPromises()
const btn = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
expect(btn?.attributes('title')).toContain('Autocommit: on')
})
it('Клик по кнопке вызывает patchProject с autocommit_enabled=true (включение)', async () => {
vi.mocked(api.project).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 0 } as any)
vi.mocked(api.patchProject).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 1 } as any)
const router = makeRouter()
await router.push('/project/KIN')
const wrapper = mount(ProjectView, {
props: { id: 'KIN' },
global: { plugins: [router] },
})
await flushPromises()
const btn = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
await btn!.trigger('click')
await flushPromises()
expect(api.patchProject).toHaveBeenCalledWith('KIN', { autocommit_enabled: true })
})
it('Клик по включённой кнопке вызывает patchProject с autocommit_enabled=false (выключение)', async () => {
vi.mocked(api.project).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 1 } as any)
vi.mocked(api.patchProject).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 0 } as any)
const router = makeRouter()
await router.push('/project/KIN')
const wrapper = mount(ProjectView, {
props: { id: 'KIN' },
global: { plugins: [router] },
})
await flushPromises()
const btn = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
await btn!.trigger('click')
await flushPromises()
expect(api.patchProject).toHaveBeenCalledWith('KIN', { autocommit_enabled: false })
})
it('При ошибке patchProject состояние кнопки откатывается (rollback)', async () => {
vi.mocked(api.project).mockResolvedValue({ ...MOCK_PROJECT, autocommit_enabled: 0 } as any)
vi.mocked(api.patchProject).mockRejectedValue(new Error('Network error'))
const router = makeRouter()
await router.push('/project/KIN')
const wrapper = mount(ProjectView, {
props: { id: 'KIN' },
global: { plugins: [router] },
})
await flushPromises()
const btn = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
await btn!.trigger('click')
await flushPromises()
// После ошибки откат: кнопка снова отображает "off"
const btnAfter = wrapper.findAll('button').find(b => b.text().includes('Autocommit'))
expect(btnAfter?.attributes('title')).toBe('Autocommit: off')
})
})