Files
danyang-match/ui-tests/wxss-component-selector-contracts.mjs
T

71 lines
3.0 KiB
JavaScript
Raw Normal View History

// 契约:自定义组件的 WXSS 不得使用标签 / ID / 属性选择器
//
// 由来(2026-09-19)开发者工具警告:
// [pages/index/index] Some selectors are not allowed in component wxss,
// including tag name selectors, ID selectors, and attribute selectors.
// (./components/recommend-card/index.wxss:1:1092)
// 实测违规 1 处:`.compact-like image`。
//
// ⚠️ 作用域刻意限定 `miniapp/components/`:**page 的 wxss 允许标签选择器**,
// 把本规则套到 pages 上会立刻产生误报 —— 守卫一旦有假阳性就会被绕过。
//
// 自检:内置正向样例(合法类选择器 + 伪类 + `>` 子选择器)与反向样例
// (标签 / ID / 属性各一),确保判据既不全哑、也不误伤。
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { relative, resolve } from 'node:path'
import { checkWxss, walkWxss } from '../scripts/lib/wxss-selectors.mjs'
const root = resolve(import.meta.dirname, '..')
// WXSS_SCAN_ROOT 仅用于负向注入自证(指向临时目录),默认 miniapp/components
const scanRoot = resolve(root, process.env.WXSS_SCAN_ROOT ?? 'miniapp/components')
// ── 1. 判据自检 ──────────────────────────────────────────────────
const selfCheckCases = [
{
name: '正向:纯类选择器 / 伪类 / 子选择器 均合法',
src: [
'.a { color: red }',
'.a .b { color: red }',
'.a > .b { color: red }',
'.a:active, .b::after { color: red }',
'.a:nth-child(2) { color: red }',
'@media (min-width: 600px) { .a { color: red } }',
'/* .commented-out image { color: red } */',
].join('\n'),
expect: 0,
},
{ name: '反向:标签选择器', src: '.a image { width: 1px }', expect: 1 },
{ name: '反向:ID 选择器', src: '#main { width: 1px }', expect: 1 },
{ name: '反向:属性选择器', src: '.a[data-x="1"] { width: 1px }', expect: 1 },
]
for (const c of selfCheckCases) {
const got = checkWxss(c.src)
assert.equal(
got.length,
c.expect,
`判据自检失败 —— ${c.name}\n期望 ${c.expect} 条,实得 ${got.length} 条:\n${got.map((x) => x.message).join('\n')}`,
)
}
// ── 2. 全量扫描组件 WXSS ────────────────────────────────────────
const files = walkWxss(scanRoot)
assert.ok(files.length > 0, `未在 ${scanRoot} 下找到任何 .wxss —— 扫描清单可能失配,拒绝报绿`)
const broken = []
for (const file of files) {
for (const p of checkWxss(readFileSync(file, 'utf8'))) {
broken.push(`${relative(root, file).replace(/\\/g, '/')}:${p.line} ${p.message}`)
}
}
assert.deepEqual(
broken,
[],
`以下组件 WXSS 使用了不允许的选择器(开发者工具会警告,样式不生效):\n${broken.join('\n')}`,
)
console.log(`WXSS component selector contracts passed(${files.length} 个组件样式文件)`)