// @vitest-environment jsdom import { readFileSync } from 'node:fs'; import { describe, expect, test } from 'vitest'; import { repoPath } from './repoPath'; import { declaration, parseStyleSheet, resolveDeclarations, } from './styleCascade'; /** * 运行页顶栏动作区的声明级断言。 * * jsdom 不加载全局样式表,所以这里按仓库既有做法(`styleCascade`)解析真实生效的声明: * 「版本入口与「在浏览器打开」跟其他动作按钮同一套皮」只由样式决定,用例必须钉在声明上, * 否则下一次改动给版本入口单开一套 border / background / hover 时没有任何东西会红。 */ const GLOBAL_CSS_PATH = repoPath('apps/ai-game-creator-shell/src/styles.css'); const rules = parseStyleSheet(readFileSync(GLOBAL_CSS_PATH, 'utf8')); // 同一个求值器限制:全局表里也有 `prefers-reduced-motion` 档,求值时先排除掉。 const widthRules = rules.filter( (rule) => !(rule.media ?? '').includes('prefers-reduced-motion'), ); function resolved(selectors: readonly string[]): Map { return resolveDeclarations(widthRules, selectors, 1280); } function hasRule(selector: string): boolean { return widthRules.some((rule) => rule.selectors.includes(selector)); } describe('运行页顶栏动作区样式', () => { test('运行画面回到两行,页面里不再有预览地址状态行', () => { const surface = resolved(['.game-run-surface']); expect(declaration(surface, 'grid-template-rows')).toBe( 'minmax(300px, 1fr) auto', ); // 状态行与那行小字整体退役:地址不再以文字常驻在页面上。 expect(hasRule('.game-run-status-bar')).toBe(false); expect(hasRule('.game-run-status-hint')).toBe(false); }); test('版本入口住进顶栏动作区,皮由那一组的基础规则给', () => { // 动作区的按钮共用一套基础外观(这一组是「在浏览器打开」与版本入口的共同来源)。 const actionsButton = resolved(['.game-workbench-view-actions button']); expect(declaration(actionsButton, 'min-height')).toBe('30px'); expect(declaration(actionsButton, 'border-radius')).toBe('999px'); expect(declaration(actionsButton, 'font-size')).toBe('12px'); expect(declaration(actionsButton, 'font-weight')).toBe('700'); // 版本入口只补「版本名可能很长」这一件事,不再自带边框 / 底色 / 文字色 / hover。 const trigger = resolved(['.game-run-version-trigger']); expect(trigger.has('border')).toBe(false); expect(trigger.has('background')).toBe(false); expect(trigger.has('color')).toBe(false); expect(declaration(trigger, 'min-width')).toBe('0'); // 省略号要真的生效:按钮是 flex 容器,文本必须挂在自带 overflow 的 span 上。 const label = resolved(['.game-run-version-trigger-label']); expect(declaration(label, 'overflow')).toBe('hidden'); expect(declaration(label, 'text-overflow')).toBe('ellipsis'); expect(declaration(label, 'white-space')).toBe('nowrap'); expect(hasRule('.game-run-version-trigger:hover')).toBe(false); expect(hasRule('.game-run-version-trigger:focus-visible')).toBe(false); // 版本入口不再绝对定位压在游戏画面上。 const picker = resolved(['.game-run-version-picker']); expect(picker.has('position')).toBe(false); expect(picker.has('top')).toBe(false); expect(picker.has('right')).toBe(false); }); });