233 lines
8.0 KiB
TypeScript
233 lines
8.0 KiB
TypeScript
// @vitest-environment happy-dom
|
||
import { beforeEach, describe, expect, it } from 'vitest'
|
||
import {
|
||
inspectThemePackage,
|
||
installTheme,
|
||
listInstalledThemes,
|
||
parseThemePackage,
|
||
uninstallTheme,
|
||
setActiveCustomTheme,
|
||
} from './themePackageService'
|
||
import type { ThemeManifest } from '@/contracts'
|
||
|
||
const manifestYaml = `theme_id: ocean-blue
|
||
name: 海洋蓝
|
||
version: 1.2.0
|
||
author: 测试作者
|
||
min_app_version: 0.1.0
|
||
css_entry: theme.css
|
||
is_dark: false`
|
||
|
||
const themeCss = `[data-theme="ocean-blue"] {
|
||
--color-accent-primary: #0077b6;
|
||
--color-background-primary: #f5fbff;
|
||
}`
|
||
|
||
/** 主题包 = YAML 清单 + 一行 `---` + CSS。 */
|
||
function pkg(manifestText = manifestYaml, css = themeCss): string {
|
||
return `${manifestText}\n---\n${css}`
|
||
}
|
||
|
||
function manifest(overrides: Partial<ThemeManifest> = {}): ThemeManifest {
|
||
return {
|
||
theme_id: 'test-theme',
|
||
name: '测试主题',
|
||
version: '1.0.0',
|
||
author: '作者',
|
||
min_app_version: '0.1.0',
|
||
is_dark: false,
|
||
css_entry: 'theme.css',
|
||
...overrides,
|
||
}
|
||
}
|
||
|
||
beforeEach(() => {
|
||
localStorage.clear()
|
||
document.head.querySelectorAll('style[id^="theme-style-"]').forEach((el) => el.remove())
|
||
})
|
||
|
||
describe('parseThemePackage', () => {
|
||
it('用 `---` 切分清单与 CSS,两部分都完整取出', () => {
|
||
const { manifestText, css } = parseThemePackage(pkg())
|
||
|
||
expect(manifestText).toContain('theme_id: ocean-blue')
|
||
expect(manifestText).not.toContain('data-theme')
|
||
expect(css).toBe(themeCss)
|
||
})
|
||
|
||
it('CSS 里自己带 `---` 也不会被截断(只按第一行分隔符切)', () => {
|
||
const cssWithDashes = '[data-theme="ocean-blue"] { content: "---"; }\n/* --- */'
|
||
const { css } = parseThemePackage(pkg(manifestYaml, cssWithDashes))
|
||
|
||
expect(css).toBe(cssWithDashes)
|
||
})
|
||
|
||
it('兼容 CRLF 换行的文件', () => {
|
||
const { css } = parseThemePackage(pkg().replace(/\n/g, '\r\n'))
|
||
|
||
expect(css).toContain('--color-accent-primary: #0077b6;')
|
||
})
|
||
|
||
it('缺少分隔行时报 THEME_PACKAGE_INVALID', () => {
|
||
expect(() => parseThemePackage(manifestYaml)).toThrow(/THEME_PACKAGE_INVALID/)
|
||
})
|
||
|
||
it('分隔行之后没有 CSS 时报 THEME_CSS_INVALID', () => {
|
||
expect(() => parseThemePackage(`${manifestYaml}\n---\n \n`)).toThrow(/THEME_CSS_INVALID/)
|
||
})
|
||
|
||
it('识别 ZIP 二进制并明确提示不支持,而不是当文本解析出乱码', () => {
|
||
// ZIP 魔数 PK\x03\x04
|
||
expect(() => parseThemePackage('PK\x03\x04 |