macos-web/tests/cases/16-assets.test.ts
2026-07-20 14:30:44 +08:00

127 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 16-assets: 资源完整性——静态扫描 + 运行时路径校验
* 原测试: Node fs 扫描 → 保留同样的扫描逻辑
*/
import { describe, it, expect } from 'vitest'
import { existsSync, readFileSync, readdirSync } from 'fs'
import { join, resolve } from 'path'
import { fileURLToPath } from 'url'
import { WALLPAPERS } from '../../src/composables/useSettings'
const __filename = fileURLToPath(import.meta.url)
const __dirname = join(__filename, '..')
const ROOT = resolve(__dirname, '../..')
const PUBLIC = join(ROOT, 'public')
describe('16-assets — 资源完整性', () => {
// ===== 静态扫描:收集所有 assets/ 引用 =====
function collectAssetRefs(): string[] {
const refs = new Set<string>()
const srcDir = join(ROOT, 'src')
const files = walkFiles(srcDir).concat([join(ROOT, 'index.html')])
for (const file of files) {
try {
const content = readFileSync(file, 'utf-8')
for (const m of content.matchAll(/(?:src|href|icon)=["']\/?(assets\/[^"']+?)["']/g)) {
refs.add(m[1])
}
} catch { /* ignore */ }
}
return [...refs].sort()
}
function walkFiles(dir: string): string[] {
const result: string[] = []
try {
for (const e of readdirSync(dir, { withFileTypes: true })) {
const full = join(dir, e.name)
if (e.isDirectory() && e.name !== 'node_modules') result.push(...walkFiles(full))
else if (/\.(ts|vue|css|html|js)$/.test(e.name)) result.push(full)
}
} catch { /* ignore */ }
return result
}
// ===== WALLPAPERS =====
it('所有 WALLPAPERS src 指向的文件存在', () => {
const missing: string[] = []
for (const w of WALLPAPERS) {
const p = join(PUBLIC, w.src)
if (!existsSync(p)) missing.push(w.src)
}
expect(missing).toEqual([])
})
it('bigsur 暗色变体文件存在', () => {
const bigsur = WALLPAPERS.find(w => w.id === 'bigsur')!
const p = join(PUBLIC, bigsur.dark!)
expect(existsSync(p)).toBe(true)
})
// ===== 关键图标 =====
const requiredIcons = [
'finder.png', 'folder.svg', 'txt.svg', 'trash.svg', 'trash-full.svg',
'settings.png', 'safari.png', 'calendar.png', 'calculator.png',
'terminal.png', 'music.png', 'photos.png', 'notes.png', 'appstore.png',
'launchpad.png', 'messages.png', 'facetime.png', 'maps.png', 'mail.png',
'preview.svg', 'quicktime.svg', 'activitymonitor.svg', 'textedit.svg',
]
it('关键应用图标存在', () => {
const missing: string[] = []
for (const icon of requiredIcons) {
const p = join(PUBLIC, 'assets/icons', icon)
if (!existsSync(p)) missing.push(icon)
}
expect(missing).toEqual([])
})
// ===== 音频和视频目录 =====
it('assets/audio 目录存在且含 mp3 文件', () => {
const audioDir = join(PUBLIC, 'assets/audio')
expect(existsSync(audioDir)).toBe(true)
const files = readdirSync(audioDir).filter((f: string) => f.endsWith('.mp3'))
expect(files.length).toBeGreaterThanOrEqual(6)
})
it('assets/video 目录存在且含 mp4/webm 文件', () => {
const videoDir = join(PUBLIC, 'assets/video')
expect(existsSync(videoDir)).toBe(true)
const files = readdirSync(videoDir)
expect(files.length).toBeGreaterThanOrEqual(6)
})
// ===== 静态引用完整性 =====
it('代码中引用的 assets 路径指向存在的文件', () => {
const refs = collectAssetRefs()
const missing: string[] = []
for (const ref of refs) {
// 跳过模板变量(如 ${src}
if (ref.includes('${') || ref.includes('{')) continue
const p = join(PUBLIC, ref)
if (!existsSync(p)) missing.push(ref)
}
expect(missing).toEqual([])
})
// ===== Store 图标 =====
const storeIcons = ['bear.png', 'typora.png', 'vscode.png', 'keynote.png', 'podcasts.png', 'news.png', 'github.png', 'tv.png']
it('Store 应用图标存在', () => {
const missing: string[] = []
for (const icon of storeIcons) {
if (!existsSync(join(PUBLIC, 'assets/icons', icon))) missing.push(icon)
}
expect(missing).toEqual([])
})
// ===== 其他资源 =====
it('avatar.svg 存在', () => {
expect(existsSync(join(PUBLIC, 'assets/icons/avatar.svg'))).toBe(true)
})
it('pdf.svg 存在', () => {
expect(existsSync(join(PUBLIC, 'assets/icons/pdf.svg'))).toBe(true)
})
})