svg-symbol-sprite
Version:
A script to generate a symbol sprite from SVG files
149 lines (109 loc) • 4.79 kB
text/typescript
import { resolve } from 'node:path';
import { readdir, readFile } from 'node:fs/promises';
import { exec, ExecException } from 'node:child_process';
import test, { Test } from 'tape';
import { parse, ElementNode } from 'svg-parser';
const command = async (args: string): Promise<ElementNode | ExecException> =>
new Promise((onSuccess, onError) => {
exec(`yarn build && node dist/index.js -o example/sprite.svg ${args}`, async error => {
if (error) {
return onError(error);
}
const svg = await readFile(resolve('example', 'sprite.svg'), 'utf-8');
const parsed = parse(svg);
return onSuccess(parsed.children[0] as ElementNode);
});
});
test('Create SVG sprite with default settings', async (t: Test) => {
const symbols = await readdir(resolve('assets'));
const result = await command('-i assets').catch(e => e);
if ('code' in result) {
t.fail(`An error occurred: ${result.message}`);
return;
} else {
const { children, properties } = result as ElementNode;
t.equal(properties?.xmlns, 'http://www.w3.org/2000/svg', 'Should have the default SVG namespace');
t.equal(properties?.['aria-hidden'], 'true', 'Should have the "aria-hidden" attribute set to true');
t.equal(
properties?.style,
'width: 0; height: 0; position: absolute;',
'Should have the default style attribute'
);
t.equal(symbols.length, children.length, `Should have ${symbols.length} symbols`);
}
});
test('Create SVG sprite with no attributes and no style', async (t: Test) => {
const symbols = await readdir(resolve('assets'));
const result = await command('-i assets -p svg- -a "" -s ""');
if ('code' in result) {
t.fail(`An error occurred: ${result.message}`);
return;
} else {
const { children, properties } = result as ElementNode;
t.equal(properties?.xmlns, undefined, 'Should have no default namespace SVG');
t.equal(properties?.['aria-hidden'], undefined, 'Should have no "aria-hidden" attribute');
t.equal(properties?.style, undefined, 'Should have an empty "style" attribute');
for (let i = 0; i < children.length; i++) {
const child = children[i] as ElementNode;
const id = child.properties?.id as string | undefined;
const name = symbols[i].split('.')[0];
t.equal(id, `svg-${name}`, `The ID of the ${name} icon is set correctly`);
}
}
});
test('Create SVG sprite with custom attributes and custom style', async (t: Test) => {
const attrs = 'aria-label="SVGSymbolSprite" data-svg-sprite="true"';
const symbols = await readdir(resolve('assets'));
const result = await command(`-i assets -p svg- -a ${attrs} -s "display: none;"`);
if ('code' in result) {
t.fail(`An error occurred: ${result.message}`);
return;
} else {
const { children, properties } = result as ElementNode;
t.equal(properties?.xmlns, undefined, 'Should have no default namespace SVG');
t.equal(properties?.['aria-label'], 'SVGSymbolSprite', 'Should have an "aria-label" attribute');
t.equal(properties?.style, 'display: none;', 'Should have a custom "style" attribute');
for (let i = 0; i < children.length; i++) {
const child = children[i] as ElementNode;
const id = child.properties?.id as string | undefined;
const name = symbols[i].split('.')[0];
t.equal(id, `svg-${name}`, `The ID of the ${name} icon is set correctly`);
}
}
});
test('Create SVG sprite with no attributes and no style', async (t: Test) => {
const symbols = await readdir(resolve('assets'));
const result = await command('-i assets -p svg- -a "" -s ""');
if ('code' in result) {
t.fail(`An error occurred: ${result.message}`);
return;
} else {
const { children, properties } = result as ElementNode;
t.equal(properties?.xmlns, undefined, 'Should have no default namespace SVG');
t.equal(properties?.['aria-hidden'], undefined, 'Should have no "aria-hidden" attribute');
t.equal(properties?.style, undefined, 'Should have an empty "style" attribute');
for (let i = 0; i < children.length; i++) {
const child = children[i] as ElementNode;
const id = child.properties?.id as string | undefined;
const name = symbols[i].split('.')[0];
t.equal(id, `svg-${name}`, `The ID of the ${name} icon is set correctly`);
}
}
});
test('Create SVG sprite with no SVGO files optimization', async (t: Test) => {
const result = await command('-i assets2 -c false');
if ('code' in result) {
t.fail(`An error occurred: ${result.message}`);
return;
} else {
const { children } = result as ElementNode;
for (const child of children) {
['title', 'desc', 'metadata', 'defs', 'path', 'g', 'use'].forEach((el: string) => {
t.assert(
(child as ElementNode).children.find(item => (item as ElementNode).tagName === el),
`${el} exists as a child of the sprite`
);
});
}
}
});