Skip to content

Commit d30cc25

Browse files
committed
tests
1 parent 5677a81 commit d30cc25

File tree

2 files changed

+28
-16
lines changed

2 files changed

+28
-16
lines changed

web_src/js/svg.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,24 @@ export function svg(name, size = 16, className = '') {
113113
return serializer.serializeToString(svgNode);
114114
}
115115

116+
export function svgParseOuterInner(name) {
117+
const svgStr = svgs[name];
118+
if (!svgStr) throw new Error(`Unknown SVG icon: ${name}`);
119+
120+
// parse the SVG string to 2 parts
121+
// * svgInnerHtml: the inner part of the SVG, will be used as the content of the <svg> VNode
122+
// * svgOuter: the outer part of the SVG, including attributes
123+
// the builtin SVG contents are clean, so it's safe to use `indexOf` to split the content:
124+
// eg: <svg outer-attributes>${svgInnerHtml}</svg>
125+
const p1 = svgStr.indexOf('>'), p2 = svgStr.lastIndexOf('<');
126+
if (p1 === -1 || p2 === -1) throw new Error(`Invalid SVG icon: ${name}`);
127+
const svgInnerHtml = svgStr.slice(p1 + 1, p2);
128+
const svgOuterHtml = svgStr.slice(0, p1 + 1) + svgStr.slice(p2);
129+
const svgDoc = parser.parseFromString(svgOuterHtml, 'image/svg+xml');
130+
const svgOuter = svgDoc.firstChild;
131+
return {svgOuter, svgInnerHtml};
132+
}
133+
116134
export const SvgIcon = {
117135
name: 'SvgIcon',
118136
props: {
@@ -121,21 +139,7 @@ export const SvgIcon = {
121139
className: {type: String, default: ''},
122140
},
123141
render() {
124-
const svgStr = svgs[this.name];
125-
if (!svgStr) throw new Error(`Unknown SVG icon: ${this.name}`);
126-
127-
// parse the SVG string to 2 parts
128-
// * svgInnerHtml: the inner part of the SVG, will be used as the content of the <svg> VNode
129-
// * svgOuter: the outer part of the SVG, including attributes
130-
// the builtin SVG contents are clean, so it's safe to use `indexOf` to split the content:
131-
// eg: <svg outer-attributes>${svgInnerHtml}</svg>
132-
const p1 = svgStr.indexOf('>'), p2 = svgStr.lastIndexOf('<');
133-
if (p1 === -1 || p2 === -1) throw new Error(`Invalid SVG icon: ${this.name}`);
134-
const svgInnerHtml = svgStr.slice(p1 + 1, p2);
135-
const svgOuterHtml = svgStr.slice(0, p1 + 1) + svgStr.slice(p2);
136-
const svgDoc = parser.parseFromString(svgOuterHtml, 'image/svg+xml');
137-
const svgOuter = svgDoc.firstChild;
138-
142+
const {svgOuter, svgInnerHtml} = svgParseOuterInner(this.name);
139143
// https://vuejs.org/guide/extras/render-function.html#creating-vnodes
140144
// the `^` is used for attr, set SVG attributes like 'width', `aria-hidden`, `viewBox`, etc
141145
const attrs = {};
@@ -151,6 +155,7 @@ export const SvgIcon = {
151155
for (const cls of svgOuter.classList) {
152156
classes.push(cls);
153157
}
158+
// TODO: drop the `className/class-name` prop in the future, only use "class" prop
154159
if (this.className) {
155160
classes.push(...this.className.split(/\s+/).filter(Boolean));
156161
}

web_src/js/svg.test.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import {expect, test} from 'vitest';
2-
import {svg} from './svg.js';
2+
import {svg, svgParseOuterInner} from './svg.js';
33

44
test('svg', () => {
55
expect(svg('octicon-repo')).toMatch(/^<svg/);
66
expect(svg('octicon-repo', 16)).toContain('width="16"');
77
expect(svg('octicon-repo', 32)).toContain('width="32"');
88
});
9+
10+
test('svgParseOuterInner', () => {
11+
const {svgOuter, svgInnerHtml} = svgParseOuterInner('octicon-repo');
12+
expect(svgOuter.nodeName).toMatch('svg');
13+
expect(svgOuter.classList.contains('octicon-repo')).toBeTruthy();
14+
expect(svgInnerHtml).toContain('<path');
15+
})

0 commit comments

Comments
 (0)