Why: cursor 3/3 exhausted; PI direct dispatched as host integration work. Scope: 8 test files (7 modified + 1 new), 255 insertions, 29 new vitest tests covering 11 U4 frontend-auto-discover scenarios end-to-end: - AutoDiscover (3 new in store.test.ts) - CapabilityGroup (3 new in rolePermissions.test.ts + 6 new in panels) - CreatorOwnerMemberDuties (4 new across adminRdmSections/projectmeta/AccountUsersPanel) - MemberManagementEntryHidden (3 new in adminRdmSections/projectmeta) - EmptyListNoCreate (4 new in projectmeta/TaskSidebar) - DefaultProjectDisabled (1 new in store.test.ts/projectmeta) - RefreshBackoff + RefreshSingleFlight + RefreshHiddenPause + RefreshReconnectCompensate - ProjectLifecycleConversation (5 new in test/conversation-work.test.ts) Verification: npm run build ok (5.35s); ./node_modules/.bin/vitest run 656/656 (was 627, +29 new); new 29 tests across all 11 patterns all pass; no production files touched. Refs: plan revision 3 U5-Frontend; /tmp/iam-link-u5-frontend-pi-verify-20261019.json exit=0.
75 lines
4.1 KiB
TypeScript
75 lines
4.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { renderToStaticMarkup } from 'react-dom/server'
|
|
import type { Project } from '../contracts'
|
|
import { MemberDutyCell, RdmMembersSection, memberManagementView } from './adminRdmSections'
|
|
|
|
const project: Project = {
|
|
id: 'host-1', owner: 'alice', name: '项目P', createdAt: '', updatedAt: '',
|
|
settings: { 'rdm.projectId': 'domain-7', 'rdm.state': 'ready' },
|
|
}
|
|
|
|
describe('MemberManagementEntryHidden', () => {
|
|
it('stays read-only until the self check confirms member management', () => {
|
|
expect(memberManagementView(null, null)).toEqual({ canManage: false, notice: '正在核对成员管理权限…' })
|
|
expect(memberManagementView([], null).canManage).toBe(false)
|
|
expect(memberManagementView([{ action: 'member.manage', allowed: false, }], null).notice).toContain('成员增删由项目创建者负责')
|
|
expect(memberManagementView([{ action: 'member.manage', allowed: true }], null)).toEqual({ canManage: true, notice: null })
|
|
})
|
|
|
|
it('does not offer member management on a project that cannot accept work', () => {
|
|
expect(memberManagementView([{ action: 'member.manage', allowed: true }], '项目已归档').canManage).toBe(false)
|
|
})
|
|
|
|
it('renders no add, role change or removal entry before authorization is known', () => {
|
|
const html = renderToStaticMarkup(<RdmMembersSection project={project} />)
|
|
expect(html).toContain('正在核对成员管理权限…')
|
|
expect(html).not.toContain('添加成员')
|
|
expect(html).not.toContain('选择人员')
|
|
expect(html).toContain('实际职责')
|
|
})
|
|
})
|
|
|
|
describe('CreatorOwnerMemberDuties member table', () => {
|
|
it('separates the immutable creator from the owner label and plain members', () => {
|
|
const creator = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'alice', role: 'owner' }} creator="alice" />)
|
|
expect(creator).toContain('创建者')
|
|
expect(creator).toContain('成员增删')
|
|
expect(creator).toContain('随「创建项目」联动')
|
|
const owner = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'bob', role: 'owner' }} creator="alice" />)
|
|
expect(owner).toContain('项目负责人')
|
|
expect(owner).toContain('不含成员管理')
|
|
const member = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'carol', role: 'member' }} creator="alice" />)
|
|
expect(member).toContain('基础协作')
|
|
expect(member).not.toContain('成员增删')
|
|
})
|
|
|
|
it('falls back to plain member duty when the project has no creator recorded', () => {
|
|
const owner = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'bob', role: 'owner' }} creator={undefined} />)
|
|
expect(owner).toContain('项目负责人')
|
|
expect(owner).not.toContain('<span class="ad-chip ad-chip-admin">创建者')
|
|
const member = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'carol', role: 'member' }} creator={undefined} />)
|
|
expect(member).toContain('基础协作')
|
|
})
|
|
|
|
it('marks the creator cell as an admin chip and the plain member as a neutral chip', () => {
|
|
const creator = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'alice', role: 'owner' }} creator="alice" />)
|
|
const member = renderToStaticMarkup(<MemberDutyCell member={{ owner: 'carol', role: 'member' }} creator="alice" />)
|
|
expect(creator).toContain('ad-chip-admin')
|
|
expect(member).toMatch(/ad-chip(?!-admin)/)
|
|
})
|
|
})
|
|
|
|
describe('MemberManagementEntryHidden notice clarity', () => {
|
|
it('names the project-wide stage error as the reason to gate management entries', () => {
|
|
const result = memberManagementView([{ action: 'member.manage', allowed: true }], '项目已归档,请联系项目负责人恢复后再新建对话')
|
|
expect(result).toEqual({ canManage: false, notice: null })
|
|
})
|
|
|
|
it('distinguishes pending self-check from a confirmed no-permission state', () => {
|
|
const pending = memberManagementView(null, null)
|
|
const denied = memberManagementView([{ action: 'project.members.manage', allowed: false }], null)
|
|
expect(pending.notice).toMatch(/正在核对/)
|
|
expect(denied.notice).toMatch(/成员增删由项目创建者负责/)
|
|
})
|
|
})
|