Skip to content

Commit 79b03a7

Browse files
author
Kalle Ott
committed
add test cases
1 parent 22279f2 commit 79b03a7

File tree

11 files changed

+3562
-2830
lines changed

11 files changed

+3562
-2830
lines changed

example/package.json

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,20 @@
99
"start:prod": "NODE_ENV=production node build/server.js"
1010
},
1111
"dependencies": {
12-
"express": "^4.17.1",
13-
"fastify": "^2.11.0",
14-
"fastify-static": "^2.5.1",
15-
"razzle": "^3.0.0",
16-
"razzle-plugin-typescript": "^3.0.0",
12+
"fastify": "^2.14.1",
13+
"fastify-static": "^2.7.0",
14+
"razzle": "^3.1.3",
15+
"razzle-plugin-typescript": "^3.1.3",
1716
"react": "link:../node_modules/react",
1817
"react-dom": "link:../node_modules/react-dom",
19-
"react-lazy-svg": "link:../",
20-
"react-router-dom": "^5.1.2"
18+
"react-lazy-svg": "link:../"
2119
},
2220
"devDependencies": {
23-
"@types/node": "^13.1.8",
24-
"@types/react": "^16.9.17",
25-
"@types/react-dom": "^16.9.4",
26-
"@types/react-router-dom": "^5.1.3",
27-
"@types/webpack-env": "^1.15.0",
28-
"tslint": "^5.20.1",
29-
"typescript": "^3.7.5"
21+
"@types/node": "^14.0.9",
22+
"@types/react": "link:../node_modules/@types/react",
23+
"@types/react-dom": "link:../node_modules/@types/react-dom",
24+
"@types/webpack-env": "^1.15.2",
25+
"tslint": "^6.1.2",
26+
"typescript": "^3.9.3"
3027
}
3128
}

example/src/client.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import App from './App';
2-
import { BrowserRouter } from 'react-router-dom';
32
import React from 'react';
43
import { hydrate } from 'react-dom';
54
import {
@@ -15,11 +14,9 @@ const loadSVG = async (url: string) => {
1514
initOnClient(cache);
1615

1716
hydrate(
18-
<BrowserRouter>
19-
<SpriteContextProvider knownIcons={cache} loadSVG={loadSVG}>
20-
<App />
21-
</SpriteContextProvider>
22-
</BrowserRouter>,
17+
<SpriteContextProvider knownIcons={cache} loadSVG={loadSVG}>
18+
<App />
19+
</SpriteContextProvider>,
2320
document.getElementById('root')
2421
);
2522

example/src/server.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import App from './App';
22
import React from 'react';
3-
import { StaticRouter } from 'react-router-dom';
43
import fastify from 'fastify';
54
import { renderToString } from 'react-dom/server';
65
import fastifyStatic from 'fastify-static';
@@ -20,15 +19,13 @@ server.register(fastifyStatic, {
2019
prefix: '/static', // optional: default '/'
2120
});
2221

23-
server.get('/*', async (req, res) => {
22+
server.get('/*', async (_, res) => {
2423
const sessionIcons: IconsCache = new Map();
2524
const context: { url?: string } = {};
2625
const markup = renderToString(
27-
<StaticRouter context={context} location={req.raw.url}>
28-
<SpriteContextProvider loadSVG={readSvg} knownIcons={sessionIcons}>
29-
<App />
30-
</SpriteContextProvider>
31-
</StaticRouter>
26+
<SpriteContextProvider loadSVG={readSvg} knownIcons={sessionIcons}>
27+
<App />
28+
</SpriteContextProvider>
3229
);
3330

3431
if (context.url) {

example/src/serverLoadSvg.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const readSvg = async (url: string) => {
1515
if (url.startsWith(cdnBase)) {
1616
url = path.join(
1717
process.cwd(),
18-
url.replace(cdnBase, './build/static/media/')
18+
url.replace(cdnBase, './build/public/static/media/')
1919
);
2020
}
2121

example/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"noFallthroughCasesInSwitch": true,
2222
"downlevelIteration": true,
2323
"moduleResolution": "node",
24-
"baseUrl": "./",
24+
"baseUrl": "./src",
2525
"paths": {
2626
"*": ["src/*", "node_modules/*"]
2727
},

example/yarn.lock

Lines changed: 3069 additions & 2516 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,19 @@
3030
"trailingComma": "es5"
3131
},
3232
"devDependencies": {
33+
"@testing-library/jest-dom": "^5.9.0",
34+
"@testing-library/react": "^10.0.6",
3335
"@types/axios": "^0.14.0",
34-
"@types/jest": "^24.9.0",
35-
"@types/react": "^16.9.17",
36-
"@types/react-dom": "^16.9.4",
37-
"husky": "^4.0.10",
38-
"react": "^16.12.0",
39-
"react-dom": "^16.12.0",
40-
"rimraf": "^3.0.0",
41-
"tsdx": "^0.12.3",
42-
"tslib": "^1.10.0",
43-
"typescript": "^3.7.5"
36+
"@types/jest": "^25.2.3",
37+
"@types/react": "^16.9.35",
38+
"@types/react-dom": "^16.9.8",
39+
"husky": "^4.2.5",
40+
"react": "^16.13.1",
41+
"react-dom": "^16.13.1",
42+
"rimraf": "^3.0.2",
43+
"tsdx": "^0.13.2",
44+
"tslib": "^2.0.0",
45+
"typescript": "^3.9.3"
4446
},
4547
"dependencies": {}
4648
}

src/index.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import { renderToStaticMarkup } from 'react-dom/server';
1212
const spriteSheetId = '__SVG_SPRITE_SHEET__';
1313

1414
const ssrEmptySpriteSheet = `<svg id="${spriteSheetId}" style="display:none"></svg>`;
15-
const svgRegex = /<svg([\s\S]*?)>([\s\S]*?)<\/svg>/gim;
16-
const attributesRegex = /(.*?)=["'](.*?)["']/gim;
1715

1816
const globalIconsCache: IconsCache = new Map();
1917

@@ -50,6 +48,7 @@ const spriteContext = createContext<SpriteContextValue>({ registerSVG: noop });
5048
const mapAttributes = (rawAttributes: string) => {
5149
let match: null | RegExpExecArray = null;
5250
const attributes: IconData['attributes'] = {};
51+
const attributesRegex = /(.*?)=["'](.*?)["']/gim;
5352

5453
while ((match = attributesRegex.exec(rawAttributes))) {
5554
const [, name, value] = match;
@@ -82,14 +81,15 @@ const parseSVG = (
8281
svgString: string | undefined
8382
): IconData | undefined => {
8483
if (svgString) {
84+
const svgRegex = /<svg([\s\S]*?)>([\s\S]*?)<\/svg>/gim;
8585
const matches = svgRegex.exec(svgString);
8686

8787
if (matches) {
88-
const [, attributesString, __html] = matches;
88+
const [, attributesString, htmlString] = matches;
8989
const attributes = mapAttributes(attributesString);
9090

9191
const svgString = {
92-
__html,
92+
__html: htmlString.trim(),
9393
};
9494
const id = url;
9595

@@ -231,7 +231,11 @@ export const initOnClient = (knownIcons: IconsCache = globalIconsCache) => {
231231
sprites.forEach(node => {
232232
const { id, attributes: rawAttributes, innerHTML } = node;
233233
const attributes = mapNodeAttributes(rawAttributes);
234-
const iconData = { id, attributes, svgString: { __html: innerHTML } };
234+
const iconData = {
235+
id,
236+
attributes,
237+
svgString: { __html: innerHTML.trim() },
238+
};
235239
addIcon(iconData);
236240

237241
knownIcons.set(id, new Promise(resolve => resolve(iconData)));

test/blah.test.tsx

Lines changed: 0 additions & 2 deletions
This file was deleted.

test/index.test.tsx

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import React from 'react';
2+
import { render } from '@testing-library/react';
3+
import {
4+
Icon,
5+
SpriteContextProvider,
6+
IconsCache,
7+
initOnClient,
8+
renderSpriteSheetToString,
9+
} from '../src/index';
10+
import { act } from 'react-dom/test-utils';
11+
import { renderToString } from 'react-dom/server';
12+
13+
const svg1 = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
14+
<path d="M0 0h24v24H0z" fill="none"/>
15+
</svg>`;
16+
const svg2 = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
17+
<path d="M0 0h24v24H0z" fill="none"/>
18+
</svg>`;
19+
20+
const loadSVG = async (url: string) => {
21+
switch (url) {
22+
case '1': {
23+
return svg1;
24+
}
25+
case '2':
26+
default:
27+
return svg2;
28+
}
29+
};
30+
31+
test('should fill the cache when an icon is rendered', async () => {
32+
const cache: IconsCache = new Map();
33+
const { rerender } = render(
34+
<SpriteContextProvider knownIcons={cache} loadSVG={loadSVG}>
35+
<Icon url={'1'}></Icon>
36+
</SpriteContextProvider>
37+
);
38+
expect(cache.size).toBe(1);
39+
await act(async () => {
40+
const iconData = await cache.get('1');
41+
42+
expect(iconData?.attributes.viewBox).toBe('0 0 24 24');
43+
expect(iconData?.svgString.__html).toBe(
44+
'<path d="M0 0h24v24H0z" fill="none"/>'
45+
);
46+
});
47+
48+
rerender(
49+
<SpriteContextProvider knownIcons={cache} loadSVG={loadSVG}>
50+
<Icon url={'2'}></Icon>
51+
</SpriteContextProvider>
52+
);
53+
await act(async () => {
54+
expect(cache.size).toBe(2);
55+
const iconData = await cache.get('2');
56+
expect(iconData?.attributes.viewBox).toBe('0 0 24 24');
57+
expect(iconData?.svgString.__html).toBe(
58+
'<path d="M0 0h24v24H0z" fill="none"/>'
59+
);
60+
});
61+
});
62+
63+
test('render loaded svgs to a svg sprite sheet string', async () => {
64+
const cache: IconsCache = new Map();
65+
const renderedString = renderToString(
66+
<SpriteContextProvider knownIcons={cache} loadSVG={loadSVG}>
67+
<Icon url={'1'}></Icon>
68+
</SpriteContextProvider>
69+
);
70+
71+
const renderedSpriteSheet = await renderSpriteSheetToString(
72+
renderedString,
73+
cache
74+
);
75+
76+
expect(renderedSpriteSheet).toMatchInlineSnapshot(
77+
`"<svg><use xlink:href=\\"#1\\"></use></svg><svg id=\\"__SVG_SPRITE_SHEET__\\" style=\\"display:none\\"><symbol id=\\"1\\" xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\"><path d=\\"M0 0h24v24H0z\\" fill=\\"none\\"/></symbol></svg>"`
78+
);
79+
});
80+
81+
test('client should be able to initiate the cache from a rendered dom', async () => {
82+
const cache: IconsCache = new Map();
83+
document.body.innerHTML = `<svg id="__SVG_SPRITE_SHEET__" style="display:none">
84+
<symbol
85+
id="1"
86+
xmlns="http://www.w3.org/2000/svg"
87+
viewBox="0 0 24 24"
88+
>
89+
<path d="M0 0h24v24H0z" fill="none" />
90+
</symbol>
91+
</svg>`;
92+
93+
initOnClient(cache);
94+
95+
expect(cache.size).toBe(1);
96+
const iconData = await cache.get('1');
97+
98+
expect(iconData?.id).toBe('1');
99+
expect(iconData?.attributes.height).toBe(undefined);
100+
expect(iconData?.attributes.width).toBe(undefined);
101+
expect(iconData?.attributes.viewBox).toBe('0 0 24 24');
102+
expect(iconData?.svgString.__html).toBe(
103+
'<path d="M0 0h24v24H0z" fill="none"></path>'
104+
);
105+
});

0 commit comments

Comments
 (0)