import type { BlockConcept, KindIconName } from './types' import { renderToStaticMarkup } from 'react-dom/server' import { describe, expect, it } from 'vitest' import { KIND_ICONS } from '../../../src/codeReader/contract' import { KIND_ICON_COMPONENTS, KindIcon } from './kindIcons' function render(concepts: readonly BlockConcept[]): string { return renderToStaticMarkup() } function concept(id: string, label: string, icon: KindIconName, color?: BlockConcept['color']): BlockConcept { return { id, label, icon, ...(color && { color }) } } /** 标签之间的字:图标(svg)没有字 */ const visibleText = (html: string): string => html.replace(/<[^>]*>/g, '').trim() describe('块的种类图标', () => { it('内置种类各有一个图标,和原型的一一对应', () => { expect(KIND_ICONS).toEqual({ import: 'import', function: 'square-function', class: 'box', trait: 'network', impl: 'square-function', module: 'layers', attribute: 'sliders-horizontal', type: 'braces', interface: 'braces', enum: 'list-ordered', exception: 'triangle-alert', field: 'tag', const: 'lock', variable: 'variable', if: 'split', else: 'corner-down-right', loop: 'repeat', try: 'shield', catch: 'shield-alert', finally: 'shield-check', return: 'corner-down-left', statement: 'code', comment: 'message-square-text', interpreter: 'terminal', options: 'sliders-horizontal', case: 'signpost', command: 'square-terminal', pipeline: 'square-terminal', directive: 'terminal', stage: 'layers', run: 'square-terminal', copy: 'copy', setting: 'sliders-horizontal', label: 'tag', health: 'activity', start: 'play', }) }) it('这组图标里每个名字画的就是 lucide 里同名的图标', () => { // 名字里带数字的图标 lucide 另加一个按组件名起的类(share-2 的 lucide-share2),同名的那个类排在最后 for (const name of Object.keys(KIND_ICON_COMPONENTS) as KindIconName[]) { const html = render([concept(name, name, name)]) expect(html, name).toMatch(new RegExp(`class="lucide (?:[\\w-]+ )?lucide-${name}"`)) } }) it('只画图标不带字,名字在悬停提示(data-tooltip,不用原生 title)里;读屏念这个名字;20px 的框、16px 的图形', () => { const html = render([concept('function', '函数', 'square-function')]) expect(visibleText(html)).toBe('') expect(html).toContain('role="img" aria-label="函数"') expect(html).toContain('data-tooltip="函数"') expect(html).toContain('data-kind="function"') expect(html).not.toContain(' title=') expect(html).toContain('lucide-square-function') expect(html).toContain('width="16" height="16"') expect(html).toContain('size-5') }) it('认到几个就横排几个:悬停各自的名字,读屏把名字连起来念;规则的图标用规则给的颜色', () => { const html = render([ concept('class', '类', 'box'), concept('dataclasses.dataclass', '数据类', 'package', { dark: '#ef7fb0', light: '#b3306c' }), concept('dataclasses.frozen', '不可修改', 'lock', { dark: '#9cdcfe', light: '#001080' }), ]) expect(visibleText(html)).toBe('') expect(html).toContain('aria-label="类,数据类,不可修改"') expect(html).toContain('data-tooltip="类"') expect(html).toContain('data-tooltip="数据类"') expect(html).toContain('data-tooltip="不可修改"') expect(html).toContain('data-kind="class"') expect(html).toContain('lucide-box') expect(html).toContain('lucide-package') expect(html).toContain('lucide-lock') expect(html).toContain('--kind-dark:#ef7fb0') expect(html).toContain('--kind-light:#b3306c') expect(html).toContain('--kind-dark:#9cdcfe') expect(html).toContain('--kind-light:#001080') expect(html).not.toContain(' title=') expect(html.match(/size-5/g)).toHaveLength(3) expect(html).toContain('gap-0.5') }) })