UNPKG

@qrac/svgstore

Version:

Combines mulitple svg files into one.

233 lines (197 loc) 7.54 kB
'use strict'; const svgstore = require('../src/svgstore.js'); const test = require('./utils/test.js'); const doctype = '<?xml version="1.0" encoding="UTF-8"?>' + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ' + '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; const svgNs = '<svg xmlns="http://www.w3.org/2000/svg" ' + 'xmlns:xlink="http://www.w3.org/1999/xlink">'; const FIXTURE_SVGS = { foo: '<svg viewBox="0 0 100 100"><defs><linear-gradient style="fill: red;"/></defs><path style="fill: red;"/></svg>', bar: '<svg viewBox="0 0 200 200"><defs><radial-gradient style="stroke: red;"/></defs><rect style="stroke: red;"/></svg>', baz: '<svg viewBox="0 0 200 200"><defs><linear-gradient style="fill: red;"/></defs><path style="fill: red;"/></svg>', qux: '<svg viewBox="0 0 200 200"><defs><radial-gradient style="stroke: red;" fill="blue"/></defs><rect style="stroke: red;" fill="blue"/></svg>', quux: '<svg viewBox="0 0 200 200" aria-labelledby="titleId" role="img"><title id="titleId">A boxy shape</title><rect/></svg>', corge: '<svg viewBox="0 0 200 200" aria-labelledby="titleId" role="img" preserveAspectRatio="xMinYMax" take-me-too="foo" count-me-out="bar">' + '<title id="titleId">A boxy shape</title><rect/></svg>', defsWithId: '<svg><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="a"><stop stop-color="#FFF" offset="0%"/><stop stop-color="#F0F0F0" offset="100%"/></linearGradient><path id="b" d=""/></defs><path fill="url(#a)" fill-rule="nonzero" d=""/><use xlink:href="#b"></use><use fill-rule="nonzero" xlink:href="#b"></use><path fill="url(#a)" fill-rule="nonzero" d=""/></svg>', }; test('should create an svg document', async (t) => { const store = svgstore(); const svg = store.toString(); t.strictEqual(svg.slice(0, 5), '<?xml'); }); test('should create an svg element', async (t) => { const store = svgstore(); const svg = store.toString({ inline: true }); t.strictEqual(svg.slice(0, 4), '<svg'); }); test('should combine svgs', async (t) => { const store = svgstore() .add('foo', doctype + FIXTURE_SVGS.foo) .add('bar', doctype + FIXTURE_SVGS.bar); const expected = doctype + svgNs + '<defs>' + '<linear-gradient style="fill: red;"/>' + '<radial-gradient style="stroke: red;"/>' + '</defs>' + '<symbol id="foo" viewBox="0 0 100 100"><path style="fill: red;"/></symbol>' + '<symbol id="bar" viewBox="0 0 200 200"><rect style="stroke: red;"/></symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should clean defs', async (t) => { const store = svgstore({ cleanDefs: true }) .add('foo', doctype + FIXTURE_SVGS.foo) .add('bar', doctype + FIXTURE_SVGS.bar) .add('baz', doctype + FIXTURE_SVGS.baz, { cleanDefs: [], }) .add('qux', doctype + FIXTURE_SVGS.qux, { cleanDefs: ['fill'], }); const expected = doctype + svgNs + '<defs>' + '<linear-gradient/><radial-gradient/>' + '<linear-gradient style="fill: red;"/>' + '<radial-gradient style="stroke: red;"/>' + '</defs>' + '<symbol id="foo" viewBox="0 0 100 100"><path style="fill: red;"/></symbol>' + '<symbol id="bar" viewBox="0 0 200 200"><rect style="stroke: red;"/></symbol>' + '<symbol id="baz" viewBox="0 0 200 200"><path style="fill: red;"/></symbol>' + '<symbol id="qux" viewBox="0 0 200 200"><rect style="stroke: red;" fill="blue"/></symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should clean symbols', async (t) => { const store = svgstore({ cleanSymbols: true }) .add('foo', doctype + FIXTURE_SVGS.foo) .add('bar', doctype + FIXTURE_SVGS.bar) .add('baz', doctype + FIXTURE_SVGS.baz, { cleanSymbols: [], }) .add('qux', doctype + FIXTURE_SVGS.qux, { cleanSymbols: ['fill'], }); const expected = doctype + svgNs + '<defs>' + '<linear-gradient style="fill: red;"/>' + '<radial-gradient style="stroke: red;"/>' + '<linear-gradient style="fill: red;"/>' + '<radial-gradient style="stroke: red;" fill="blue"/>' + '</defs>' + '<symbol id="foo" viewBox="0 0 100 100"><path/></symbol>' + '<symbol id="bar" viewBox="0 0 200 200"><rect/></symbol>' + '<symbol id="baz" viewBox="0 0 200 200"><path style="fill: red;"/></symbol>' + '<symbol id="qux" viewBox="0 0 200 200"><rect style="stroke: red;"/></symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should attempt to preserve the `viewBox`, `aria-labelledby`, and `role` attributes of the root SVG by default', async (t) => { const store = svgstore().add('quux', FIXTURE_SVGS.quux); const expected = doctype + svgNs + '<defs/>' + '<symbol id="quux" viewBox="0 0 200 200" aria-labelledby="titleId" role="img">' + '<title id="titleId">A boxy shape</title><rect/>' + '</symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should support custom attribute preservation, on top of the defaults', async (t) => { const copyAttrs = ['preserveAspectRatio', 'take-me-too', 'role']; const store = svgstore({ copyAttrs }).add('corge', FIXTURE_SVGS.corge); const expected = doctype + svgNs + '<defs/>' + '<symbol id="corge" viewBox="0 0 200 200" aria-labelledby="titleId" role="img" preserveAspectRatio="xMinYMax" take-me-too="foo">' + '<title id="titleId">A boxy shape</title><rect/>' + '</symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should set symbol attributes', async (t) => { const options = { inline: true, symbolAttrs: { viewBox: null, id: function (id) { return 'icon-' + id; }, }, }; const store = svgstore(options) .add('foo', doctype + FIXTURE_SVGS.foo) .add('bar', doctype + FIXTURE_SVGS.bar); const expected = '<svg>' + '<defs>' + '<linear-gradient style="fill: red;"/>' + '<radial-gradient style="stroke: red;"/>' + '</defs>' + '<symbol id="icon-foo"><path style="fill: red;"/></symbol>' + '<symbol id="icon-bar"><rect style="stroke: red;"/></symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should set svg attributes', async (t) => { const options = { inline: true, svgAttrs: { id: 'spritesheet', style: 'display: none', }, }; const store = svgstore(options) .add('foo', doctype + FIXTURE_SVGS.foo) .add('bar', doctype + FIXTURE_SVGS.bar); const expected = '<svg id="spritesheet" style="display: none">' + '<defs>' + '<linear-gradient style="fill: red;"/>' + '<radial-gradient style="stroke: red;"/>' + '</defs>' + '<symbol id="foo" viewBox="0 0 100 100"><path style="fill: red;"/></symbol>' + '<symbol id="bar" viewBox="0 0 200 200"><rect style="stroke: red;"/></symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); }); test('should rename defs id', async (t) => { const options = { inline: true, renameDefs: true, }; const store = svgstore(options).add( 'defs_with_id', doctype + FIXTURE_SVGS.defsWithId ); const expected = '<svg>' + '<defs>' + '<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="defs_with_id_a">' + '<stop stop-color="#FFF" offset="0%"/>' + '<stop stop-color="#F0F0F0" offset="100%"/>' + '</linearGradient>' + '<path id="defs_with_id_b" d=""/>' + '</defs>' + '<symbol id="defs_with_id">' + '<path fill="url(#defs_with_id_a)" fill-rule="nonzero" d=""/>' + '<use xlink:href="#defs_with_id_b"/>' + '<use fill-rule="nonzero" xlink:href="#defs_with_id_b"/>' + '<path fill="url(#defs_with_id_a)" fill-rule="nonzero" d=""/>' + '</symbol>' + '</svg>'; t.strictEqual(store.toString(), expected); });