Files
superwork/vscode/src/codeReader/features/features.test.ts
T
cruldra 880bf7fc57 ✨ feat(vscode): 新增「了解一块代码」:AI 找功能代码占一栏,对话里接着改
主栏标题栏的放大镜问要了解哪一块,占一个栏位建一栏(和收藏共用 30 个栏位,视图改名 slot1..30,按 slotKindN 分收藏 / 功能挂标题栏按钮),同时开对话页让 Claude 只读地在全部工作区文件夹里找,按 --json-schema 交回环节 → 文件 + 符号 + 一句话。
对话复用预览顶部的聊天(CodeQa.askTop:会话续接、进行中的一轮、记录存 workspaceState);结构不合格算这一轮没答成、留着能再画出来。
条目每次画、点时按眼下的代码找:有语言插件的解析成代码块按「类名.方法名」找,没有的问 VS Code 文档符号;找不到画成灰的。
2026-10-12 15:48:54 +11:00

81 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { FeatureResult } from './featureResult'
import type { Feature } from './features'
import { describe, expect, it } from 'vitest'
import { featureCommand, featureMessage, itemRow, parseFeatures, placeFeature, removeFeature, renameFeature, withResult } from './features'
const RESULT: FeatureResult = { groups: [{ name: '登录页面', items: [{ folder: 'web', path: 'src/Login.tsx', symbol: 'LoginPage', role: '登录表单' }] }] }
const feature = (slot: number, overrides: Partial<Feature> = {}): Feature => ({ id: `f${slot}`, question: `问题${slot}`, name: `问题${slot}`, slot, ...overrides })
describe('存着的功能', () => {
it('认得出的留下,坏的丢掉;结果读不懂的当还没有结果', () => {
const stored = [
feature(1, { result: RESULT }),
{ id: 'x', question: 'q', name: 'q' },
'bad',
feature(2, { result: { groups: 'bad' } as unknown as FeatureResult }),
]
expect(parseFeatures(stored)).toEqual([feature(1, { result: RESULT }), feature(2)])
expect(parseFeatures(undefined)).toEqual([])
})
it('同一个栏位存了两个时只认第一个', () => {
expect(parseFeatures([feature(1), { ...feature(1), id: 'other' }])).toEqual([feature(1)])
})
})
describe('新功能占栏位、重命名、换结果、删除', () => {
it('和收藏共用栏位:占没被占的里面最小的,满了没有', () => {
expect(placeFeature([1, 2, 4])).toBe(3)
expect(placeFeature(Array.from({ length: 30 }, (_, index) => index + 1))).toBeUndefined()
})
it('重命名只改那一栏的名字,换结果只换那一个,删除只去掉那一个', () => {
const features = [feature(1), feature(4)]
expect(renameFeature(features, 4, '续费')).toEqual([feature(1), feature(4, { name: '续费' })])
expect(withResult(features, 'f1', RESULT)).toEqual([feature(1, { result: RESULT }), feature(4)])
expect(removeFeature(features, 1)).toEqual([feature(4)])
})
})
describe('功能栏标题栏上的命令', () => {
it('每个栏位各有打开对话、重命名、删除', () => {
expect(featureCommand('openChat', 3)).toBe('superpowers.codeReader.openFeatureChat3')
expect(featureCommand('rename', 3)).toBe('superpowers.codeReader.renameFeature3')
expect(featureCommand('remove', 30)).toBe('superpowers.codeReader.removeFeature30')
})
})
describe('栏里的一行条目', () => {
const item = RESULT.groups[0].items[0]
it('名字后面淡色的是那一句话,悬停看文件、符号和那句话', () => {
expect(itemRow(item, true)).toEqual({ label: 'LoginPage', description: '登录表单', tooltip: '**src\\/Login\\.tsx** \nLoginPage \n登录表单' })
expect(itemRow({ folder: 'web', path: '.env', role: '接口地址' }, true)).toEqual({ label: '.env', description: '接口地址', tooltip: '**\\.env** \n接口地址' })
})
it('找不到的悬停先说找不到了', () => {
expect(itemRow(item, false).tooltip).toBe('找不到了 \n**src\\/Login\\.tsx** \nLoginPage \n登录表单')
})
})
describe('栏上方的一句话', () => {
it('正在找:第一次是「正在找…」,有结果后再找是按你说的改;带上正在做的事', () => {
expect(featureMessage(undefined, { status: 'running' })).toBe('正在找…')
expect(featureMessage(undefined, { status: 'running', activity: '读取 a.ts' })).toBe('正在找…(读取 a.ts)')
expect(featureMessage(RESULT, { status: 'running' })).toBe('正在按你说的改…')
})
it('找失败了:说原因、可以在对话里接着说重试;有旧结果时旧的留着', () => {
expect(featureMessage(undefined, { status: 'failed', error: '没找到 Claude Code' })).toBe('没找成:没找到 Claude Code。可以在对话里接着说,让它再找一次。')
expect(featureMessage(RESULT, { status: 'failed', error: '等太久,已经停掉。' })).toBe('这次没改成:等太久,已经停掉。下面还是上一次的结果,可以在对话里接着说,让它再改一次。')
})
it('没在找:有结果不说话;一个环节都没有说没找到;还没有结果(停下了、重开了窗口)说可以接着说', () => {
expect(featureMessage(RESULT, undefined)).toBeUndefined()
expect(featureMessage(RESULT, { status: 'stopped' })).toBeUndefined()
expect(featureMessage({ groups: [] }, undefined)).toBe('没找到和这个功能直接相关的代码,可以在对话里换个说法接着说。')
expect(featureMessage(undefined, { status: 'stopped' })).toBe('还没有结果,可以在对话里接着说,让它再找一次。')
expect(featureMessage(undefined, undefined)).toBe('还没有结果,可以在对话里接着说,让它再找一次。')
})
})