minify-font
Version:
A lightweight font subsetting and conversion tool | 轻量级字体裁剪和转换工具
389 lines (317 loc) • 12.6 kB
JavaScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { minifyFont } from '../src/minify-font.mjs'
import { mkdir } from 'node:fs/promises'
// Mock dependencies
vi.mock('../src/minify-font.mjs')
vi.mock('node:fs/promises')
describe('minify-font CLI', () => {
let originalArgv
let originalExit
let consoleLogSpy
let consoleErrorSpy
let runCLI
beforeEach(async () => {
// Save original values
originalArgv = process.argv
originalExit = process.exit
// Mock process.exit
process.exit = vi.fn()
// Mock console methods
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
// Mock mkdir
vi.mocked(mkdir).mockResolvedValue(undefined)
// Mock minifyFont
vi.mocked(minifyFont).mockResolvedValue(undefined)
// Clear module cache and re-import to get fresh instance
vi.resetModules()
const module = await import('./minify-font.mjs')
runCLI = module.runCLI
})
afterEach(() => {
// Restore original values
process.argv = originalArgv
process.exit = originalExit
vi.restoreAllMocks()
vi.clearAllMocks()
})
describe('Help and Version', () => {
it('should show help when no arguments provided', async () => {
process.argv = ['node', 'minify-font.mjs']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: minify-font'))
expect(process.exit).toHaveBeenCalledWith(0)
})
it('should show help with -h flag', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-h']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: minify-font'))
expect(process.exit).toHaveBeenCalledWith(0)
})
it('should show help with --help flag', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--help']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: minify-font'))
expect(process.exit).toHaveBeenCalledWith(0)
})
it('should show version with -v flag', async () => {
process.argv = ['node', 'minify-font.mjs', '-v']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('version'))
expect(process.exit).toHaveBeenCalledWith(0)
})
it('should show version with --version flag', async () => {
process.argv = ['node', 'minify-font.mjs', '--version']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('version'))
expect(process.exit).toHaveBeenCalledWith(0)
})
})
describe('Collection Selection', () => {
it('should use default top2500 collection', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('Using character collection: top2500')
)
expect(minifyFont).toHaveBeenCalled()
})
it('should use top500 collection with -c flag', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-c', 'top500']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('Using character collection: top500')
)
})
it('should use commonlyUsed collection with --collection flag', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--collection', 'commonlyUsed']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('Using character collection: commonlyUsed')
)
})
it('should use commonlyUsed collection', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-c', 'commonlyUsed']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('Using character collection: commonlyUsed')
)
})
it('should error on invalid collection name', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-c', 'invalid']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid collection "invalid"'))
expect(process.exit).toHaveBeenCalledWith(1)
})
})
describe('Custom Words', () => {
it('should use custom words with -w flag', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-w', 'Hello World']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Added custom words'))
})
it('should combine collection with custom words', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-c', 'top500', '-w', '额外字符']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('Using character collection: top500')
)
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Added custom words'))
})
})
describe('Output Options', () => {
it('should generate default formats (ttf, woff, woff2)', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf']
await runCLI()
expect(minifyFont).toHaveBeenCalledTimes(3)
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
input: 'font.ttf',
output: expect.stringContaining('.min.ttf'),
})
)
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
input: 'font.ttf',
output: expect.stringContaining('.min.woff'),
})
)
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
input: 'font.ttf',
output: expect.stringContaining('.min.woff2'),
})
)
})
it('should use specified output directory', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-o', 'output/']
await runCLI()
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
output: expect.stringContaining('output/'),
})
)
})
it('should use specific output file', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-o', 'custom.woff2']
await runCLI()
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
output: 'custom.woff2',
})
)
})
it('should generate only specified formats', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-f', 'woff2']
await runCLI()
expect(minifyFont).toHaveBeenCalledTimes(1)
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
output: expect.stringContaining('.woff2'),
})
)
})
it('should generate multiple specified formats', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-f', 'ttf,woff']
await runCLI()
expect(minifyFont).toHaveBeenCalledTimes(2)
})
it('should create output directories', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-o', 'dist/fonts/']
await runCLI()
expect(mkdir).toHaveBeenCalledWith(expect.stringContaining('dist/fonts'), {
recursive: true,
})
})
})
describe('Font Options', () => {
it('should accept input options as JSON', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--input-options', '{"type":"ttf"}']
await runCLI()
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
inputOptions: { type: 'ttf' },
})
)
})
it('should accept output options as JSON', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--output-options', '{"hinting":true}']
await runCLI()
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
outputOptions: { hinting: true },
})
)
})
it('should error on invalid input options JSON', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--input-options', 'invalid-json']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('Invalid JSON for --input-options'),
expect.any(String)
)
expect(process.exit).toHaveBeenCalledWith(1)
})
it('should error on invalid output options JSON', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--output-options', 'invalid-json']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('Invalid JSON for --output-options'),
expect.any(String)
)
expect(process.exit).toHaveBeenCalledWith(1)
})
})
describe('Error Handling', () => {
it('should error when input file is missing', async () => {
process.argv = ['node', 'minify-font.mjs', '-o', 'output.woff2']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Input font path is required'))
expect(process.exit).toHaveBeenCalledWith(1)
})
it('should error on unknown option', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '--unknown']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Unknown option'))
expect(process.exit).toHaveBeenCalledWith(1)
})
it('should error on multiple input files', async () => {
process.argv = ['node', 'minify-font.mjs', 'font1.ttf', 'font2.ttf']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('Multiple input files not supported')
)
expect(process.exit).toHaveBeenCalledWith(1)
})
it('should handle minifyFont errors', async () => {
vi.mocked(minifyFont).mockRejectedValue(new Error('Font processing failed'))
process.argv = ['node', 'minify-font.mjs', 'font.ttf']
await runCLI()
expect(consoleErrorSpy).toHaveBeenCalledWith(
expect.stringContaining('Error minifying font'),
expect.stringContaining('Font processing failed')
)
expect(process.exit).toHaveBeenCalledWith(1)
})
})
describe('@font-face CSS Generation', () => {
it('should output @font-face CSS', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('@font-face'))
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('font-family'))
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('src:'))
})
it('should use correct format names in CSS', async () => {
process.argv = ['node', 'minify-font.mjs', 'font.ttf', '-f', 'ttf']
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("format('truetype')"))
})
})
describe('Complex Scenarios', () => {
it('should handle all options together', async () => {
process.argv = [
'node',
'minify-font.mjs',
'input.ttf',
'-c',
'commonlyUsed',
'-w',
'ABC',
'-o',
'dist/',
'-f',
'woff2,woff',
'--input-options',
'{}',
'--output-options',
'{}',
]
await runCLI()
expect(consoleLogSpy).toHaveBeenCalledWith(
expect.stringContaining('Using character collection: commonlyUsed')
)
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Added custom words'))
expect(minifyFont).toHaveBeenCalledTimes(2)
})
it('should preserve input filename in output', async () => {
process.argv = ['node', 'minify-font.mjs', 'my-custom-font.ttf', '-o', 'output/']
await runCLI()
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
output: expect.stringContaining('my-custom-font.min'),
})
)
})
it('should handle paths with directories in input', async () => {
process.argv = ['node', 'minify-font.mjs', 'fonts/source/font.ttf']
await runCLI()
expect(minifyFont).toHaveBeenCalledWith(
expect.objectContaining({
input: 'fonts/source/font.ttf',
output: expect.stringMatching(/fonts\/source\/font\.min\./),
})
)
})
})
})