Files
Agent-System-Frontend/test/duty-draft.test.ts
T

85 lines
4.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
absorbServerDocs, applyCell, cellDuty, completeness, editCell, replacementNote, saveIssues, savePayload,
type DutyDocDraft,
} from '../src/duties/draft'
function doc(over: Partial<DutyDocDraft> = {}): DutyDocDraft {
return {
docId: 'd1', title: '需求', code: 'UR-1', typeKey: 'design', stage: 'BD',
dutyVersion: 3, activeRound: 0, legacySectionOverrides: 0, dirty: false,
author: 'alice', reviewers: ['bob'], approver: 'carol',
...over,
}
}
describe('文档职责草稿', () => {
it('单元格由三权反推,三人视图读到同一份角色', () => {
const roles = { author: 'alice', reviewers: ['bob', 'dave'], approver: 'carol' }
expect(cellDuty(roles, 'alice')).toBe('author')
expect(cellDuty(roles, 'bob')).toBe('reviewer')
expect(cellDuty(roles, 'dave')).toBe('reviewer')
expect(cellDuty(roles, 'carol')).toBe('approver')
expect(cellDuty(roles, 'erin')).toBe('none')
expect(completeness(roles)).toEqual({ authors: 1, reviewers: 2, approvers: 1, conflicts: 0 })
})
it('替换编制前先记住原编制,并保证一人一责', () => {
const next = applyCell({ author: 'alice', reviewers: ['bob'], approver: 'carol' }, 'bob', 'author')
expect(next.replacedAuthor).toBe('alice')
expect(next.roles).toEqual({ author: 'bob', reviewers: [], approver: 'carol' })
expect(replacementNote({ author: 'alice', reviewers: ['bob'], approver: 'carol' }, 'bob', 'author')).toBe('将替换alice')
})
it('清掉唯一编制后允许留在草稿,但禁止保存', () => {
const cleared = editCell([doc()], 'd1', 'alice', 'none')
expect(cleared[0].author).toBe('')
expect(cleared[0].dirty).toBe(true)
expect(saveIssues(cleared[0])).toContain('需指定编制人')
expect(savePayload(cleared, false).issues.join(' ')).toContain('需指定编制人')
})
it('过期服务端页不覆盖未保存草稿', () => {
const dirty = doc({ author: 'erin', dirty: true, dutyVersion: 3 })
const absorbed = absorbServerDocs([dirty], [{
docId: 'd1', title: '需求', typeKey: 'design', dutyVersion: 4,
}], [{ docId: 'd1', owner: 'alice', duty: 'author' }, { docId: 'd1', owner: 'bob', duty: 'reviewer' }, { docId: 'd1', owner: 'carol', duty: 'approver' }])
expect(absorbed[0].author).toBe('erin')
expect(absorbed[0].dutyVersion).toBe(3)
})
it('写入结果未知时采用服务端版本,不再留着旧草稿重放', () => {
const dirty = doc({ author: 'erin', dirty: true, dutyVersion: 3 })
const absorbed = absorbServerDocs([dirty], [{
docId: 'd1', title: '需求', typeKey: 'design', dutyVersion: 4,
}], [
{ docId: 'd1', owner: 'alice', duty: 'author' },
{ docId: 'd1', owner: 'bob', duty: 'reviewer' },
{ docId: 'd1', owner: 'carol', duty: 'approver' },
], true)
expect(absorbed[0]).toMatchObject({ author: 'alice', dutyVersion: 4, dirty: false })
})
it('保存载荷是每份脏文档的完整目标,超过 20 份被拒绝', () => {
const many = Array.from({ length: 21 }, (_, index) => doc({ docId: `d${index}`, dirty: true }))
const blocked = savePayload(many, true)
expect(blocked.issues).toContain('一次保存最多 20 份文档')
const one = savePayload([doc({ dirty: true, activeRound: 2 })], true)
expect(one.docs[0]).toMatchObject({
docId: 'd1', author: 'alice', reviewers: ['bob'], approver: 'carol',
expectedDutyVersion: 3, confirmInvalidation: true,
})
expect(one.docs[0]).not.toHaveProperty('accountIds')
})
it('候选检索选中的 userId 随预览/批量保存以 accountIds{owner:userId} 携带,只含本文档职责人', () => {
const known = { bob: 'u-bob', erin: 'u-erin' }
const out = savePayload([
doc({ dirty: true }),
doc({ docId: 'd2', dirty: true, author: 'dave', reviewers: ['frank'], approver: 'gina' }),
], false, known)
expect(out.docs[0].accountIds).toEqual({ bob: 'u-bob' })
expect(out.docs[1]).not.toHaveProperty('accountIds')
})
})