import type { Issue } from '../../gitea/types' import { describe, expect, it } from 'vitest' import { boardIssues } from '../../panel/kanbanSnapshot' import { countingFiles, pickEntries, pickItemText, withFileCount } from './pickList' import { inReviewColumn } from './reviewRules' function issue(number: number, title: string, pr?: string): Issue { return { id: `o/r#${number}`, number, title, column: 'review', ...(pr ? { pr } : {}), assignees: [], htmlUrl: `https://x/${number}` } } const avatar = issue(446, '用户资料:上传头像,收紧非管理员改资料的权限', '447') const settings = issue(452, '桌面端:照 Figma 原型重做设置页', '455') const noPr = issue(451, '会话消息区 UI 优化') describe('选工单弹框的一项', () => { it('本机有工作副本:工单号 + 标题,淡色 PR 号,第二行改了几个文件', () => { expect(pickItemText({ issue: avatar, pr: { number: 447, files: { count: 6 }, hasWorktree: true } })).toEqual({ label: '#446 用户资料:上传头像,收紧非管理员改资料的权限', description: 'PR #447', detail: '改了 6 个文件 · 本机有工作副本', }) }) it('本机没有工作副本:说选中后拉取 PR 分支', () => { expect(pickItemText({ issue: settings, pr: { number: 455, files: { count: 12 }, hasWorktree: false } }).detail) .toBe('改了 12 个文件 · 本机没有工作副本,选中后拉取 PR 分支') }) it('文件数还在读、没读到:照实写,不编数', () => { expect(pickItemText({ issue: avatar, pr: { number: 447, files: 'loading', hasWorktree: true } }).detail) .toBe('正在读改动文件数… · 本机有工作副本') expect(pickItemText({ issue: avatar, pr: { number: 447, files: 'failed', hasWorktree: true } }).detail) .toBe('读不到改动文件数 · 本机有工作副本') }) it('没有关联 PR:没有 PR 号,第二行只写「没有关联 PR」', () => { expect(pickItemText({ issue: noPr })).toEqual({ label: '#451 会话消息区 UI 优化', detail: '没有关联 PR' }) }) }) describe('弹框的各项:先摆出来,文件数读到一个换一个', () => { const opened = pickEntries([avatar, settings, noPr], item => item.number === 446) it('一打开:有 PR 的写「正在读」,本机有没有工作副本当场判断,没 PR 的没有文件数;在转圈', () => { expect(opened).toEqual([ { issue: avatar, pr: { number: 447, files: 'loading', hasWorktree: true } }, { issue: settings, pr: { number: 455, files: 'loading', hasWorktree: false } }, { issue: noPr }, ]) expect(countingFiles(opened)).toBe(true) }) it('读到一个只换那一项,别的项是同一个对象、次序不变;还有没读完的接着转圈', () => { const next = withFileCount(opened, 452, { count: 12 }) expect(next.map(entry => entry.issue.number)).toEqual([446, 452, 451]) expect(next[1].pr?.files).toEqual({ count: 12 }) expect(next[0]).toBe(opened[0]) expect(next[2]).toBe(opened[2]) expect(opened[1].pr?.files).toBe('loading') expect(countingFiles(next)).toBe(true) }) it('都读完(没读到的也算完)就停止转圈', () => { const done = withFileCount(withFileCount(opened, 452, { count: 12 }), 446, 'failed') expect(done.map(entry => pickItemText(entry).detail)).toEqual([ '读不到改动文件数 · 本机有工作副本', '改了 12 个文件 · 本机没有工作副本,选中后拉取 PR 分支', '没有关联 PR', ]) expect(countingFiles(done)).toBe(false) }) it('没有 PR 的工单、没有工单:一开始就不转圈', () => { expect(countingFiles(pickEntries([noPr], () => false))).toBe(false) expect(countingFiles(pickEntries([], () => false))).toBe(false) }) }) describe('弹框列的工单从哪来', () => { // 存下的看板快照是 JSON,PR 号是字符串 const saved = JSON.parse(JSON.stringify({ issues: [ { ...issue(460, '已经合并', '461'), column: 'done' }, { ...issue(454, '看板快照里的审查工单', '454'), worktreePath: '~/Sources/worktree/p/x' }, { ...issue(12, 'YouTrack 的审查工单'), source: 'youtrack' }, { ...issue(300, '进行中'), column: 'in-progress' }, ], scope: 'all', globalAutoReview: false, youtrackConfigured: true, })) as unknown it('看板这次加载过就用它最近一次加载的,不看存下的快照', () => { expect(boardIssues([avatar], saved)).toEqual({ issues: [avatar], from: 'loaded' }) }) it('这次还没加载过:用存下的快照;「审查」列的 Gitea 工单照常列出,字符串的 PR 号认得', () => { const board = boardIssues(undefined, saved) expect(board?.from).toBe('saved') const entries = pickEntries(inReviewColumn(board!.issues), () => false) expect(entries.map(entry => [entry.issue.number, entry.pr?.number])).toEqual([[454, 454]]) }) it('都没有、快照是坏的:undefined(看板还没加载过)', () => { expect(boardIssues(undefined, undefined)).toBeUndefined() expect(boardIssues(undefined, { issues: 'x' })).toBeUndefined() }) })