You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vitepress/__tests__/unit/node/icons.test.ts

160 lines
5.0 KiB

import { resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { generateIconsCSS, resolveIconSVG } from 'node/icons'
import { parseIconName } from 'shared/shared'
// the e2e workspace has @iconify-json/lucide installed — use it as the
// resolution root for collection-loading tests
const e2eRoot = resolve(fileURLToPath(import.meta.url), '../../../e2e')
describe('node/icons', () => {
describe('parseIconName', () => {
test('parses qualified names', () => {
expect(parseIconName('lucide:heart')).toEqual({
collection: 'lucide',
icon: 'heart'
})
expect(parseIconName('simple-icons:github')).toEqual({
collection: 'simple-icons',
icon: 'github'
})
})
test('rejects bare names and anything outside iconify grammar', () => {
for (const name of [
'github',
'GitHub',
'foo bar',
'foo:',
':bar',
'a<b',
'foo:bar:baz',
'-leading',
''
]) {
expect(parseIconName(name), name).toBeNull()
}
})
})
describe('generateIconsCSS', () => {
test('emits base rules and per-icon rules, no legacy common rule', async () => {
// simple-icons is not in the e2e workspace's package.json — this also
// covers the fallback to vitepress's own dependency
const { css, warnings } = await generateIconsCSS(
e2eRoot,
new Set(['simple-icons:github']),
'compressed'
)
expect(warnings).toEqual([])
expect(css).toContain(
'.vpi-simple-icons-github{--icon:url("data:image/svg+xml'
)
expect(css).toContain(":where([class^='vpi-']")
expect(css).toContain('display:inline-block')
expect(css).not.toContain('.vpi-social')
})
test('suggests qualification for bare names', async () => {
const { css, warnings } = await generateIconsCSS(
e2eRoot,
new Set(['github']),
'compressed'
)
expect(css).toBe('')
expect(warnings).toEqual([
expect.stringContaining('"github" has no collection prefix')
])
expect(warnings[0]).toContain('simple-icons:github')
})
test('groups collections and stays deterministic across insertion order', async () => {
const a = await generateIconsCSS(
e2eRoot,
new Set(['lucide:heart', 'simple-icons:github', 'lucide:egg']),
'compressed'
)
const b = await generateIconsCSS(
e2eRoot,
new Set(['simple-icons:github', 'lucide:egg', 'lucide:heart']),
'compressed'
)
expect(a.css).toBe(b.css)
expect(a.css).toContain('.vpi-lucide-heart')
expect(a.css).toContain('.vpi-lucide-egg')
expect(a.css).toContain('.vpi-simple-icons-github')
})
test('warns on icons missing from an installed collection', async () => {
const { css, warnings } = await generateIconsCSS(
e2eRoot,
new Set(['simple-icons:github', 'simple-icons:thisiconisnotreal']),
'compressed'
)
expect(css).toContain('.vpi-simple-icons-github')
expect(css).not.toContain('thisiconisnotreal')
expect(warnings).toEqual([
expect.stringContaining(
'"thisiconisnotreal" was not found in the "simple-icons"'
)
])
})
test('warns on uninstalled collections with an install hint', async () => {
const { css, warnings } = await generateIconsCSS(
e2eRoot,
new Set(['notinstalled:foo']),
'compressed'
)
expect(css).toBe('')
expect(warnings).toEqual([
expect.stringContaining('@iconify-json/notinstalled')
])
})
test('warns on invalid names', async () => {
const { warnings } = await generateIconsCSS(
e2eRoot,
new Set(['Not A Name']),
'compressed'
)
expect(warnings).toEqual([
expect.stringContaining('"Not A Name" is not a valid icon name')
])
})
test('returns empty css for an empty set', async () => {
const { css, warnings } = await generateIconsCSS(
e2eRoot,
new Set(),
'compressed'
)
expect(css).toBe('')
expect(warnings).toEqual([])
})
})
describe('resolveIconSVG', () => {
test('resolves an svg offline', async () => {
const resolved = await resolveIconSVG(e2eRoot, 'lucide', 'heart')
expect(resolved).toHaveProperty('svg')
const svg = (resolved as { svg: string }).svg
expect(svg).toContain('<svg')
expect(svg).toContain('viewBox')
})
test('reports missing icons and collections distinctly', async () => {
expect(await resolveIconSVG(e2eRoot, 'lucide', 'noicon')).toEqual({
error: expect.stringContaining('was not found in the "lucide"')
})
expect(await resolveIconSVG(e2eRoot, 'nocollection', 'x')).toEqual({
error: expect.stringContaining('@iconify-json/nocollection')
})
expect(await resolveIconSVG(e2eRoot, 'Bad Name', 'x')).toEqual({
error: expect.stringContaining('not a valid icon name')
})
})
})
})