Files
hermes-desktop/tests/client/dropdown-label-activation.test.ts
toor 01d9e301fc
Build / build (push) Canceled after 0s
Playwright / browser (push) Canceled after 0s
initialize Electron desktop app and remove unused files
2026-10-25 01:09:01 +08:00

44 lines
2.0 KiB
TypeScript

import { readdirSync, readFileSync } from 'node:fs'
import { join } from 'node:path'
import { parse as parseSfc } from '@vue/compiler-sfc'
import { parse as parseTemplate, type ElementNode, type RootNode, type TemplateChildNode } from '@vue/compiler-dom'
import { describe, expect, it } from 'vitest'
function vueFiles(directory: string): string[] {
return readdirSync(directory, { withFileTypes: true }).flatMap(entry => {
const path = join(directory, entry.name)
return entry.isDirectory() ? vueFiles(path) : path.endsWith('.vue') ? [path] : []
})
}
// A native label forwards clicks on custom control chrome to the first input.
// For popup controls this can immediately toggle the menu closed again.
const popupControls = new Set([
'a-select', 'a-tree-select', 'a-cascader', 'a-auto-complete', 'a-dropdown',
'a-trigger', 'a-date-picker', 'a-range-picker', 'a-time-picker', 'a-color-picker',
'ModelSelector', 'ProfileSelector', 'LanguageSwitch', 'WorkflowModelSelector',
])
describe('dropdown label activation', () => {
it('keeps custom popup controls outside native labels throughout the client', () => {
const violations: string[] = []
for (const path of vueFiles('packages/client/src')) {
const { descriptor } = parseSfc(readFileSync(path, 'utf8'))
if (!descriptor.template) continue
const offset = descriptor.template.loc.start.line - 1
function visit(node: RootNode | TemplateChildNode, insideLabel = false) {
if (node.type !== 0 && node.type !== 1) return
if (node.type === 1) {
if (insideLabel && popupControls.has(node.tag)) {
violations.push(`${path}:${offset + node.loc.start.line} <${node.tag}> inside <label>`)
}
insideLabel ||= node.tag === 'label'
}
for (const child of (node as RootNode | ElementNode).children) visit(child, insideLabel)
}
visit(parseTemplate(descriptor.template.content))
}
expect(violations).toEqual([])
})
})