Skip to content

Commit d2bb9d0

Browse files
committed
test(#141): add unit tests for invalid icon configs
Focus: making sure vivify-server doesn't crash when an icon option has a mistake, but instead falls back to fallbackIcon with a console warning.
1 parent 6c707c2 commit d2bb9d0

3 files changed

Lines changed: 68 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"viv": "VIV_PORT=3000 node --loader ts-node/esm src/app.ts",
88
"lint": "eslint src static",
99
"lint-markdown": "markdownlint-cli2 --config .github/.markdownlint-cli2.yaml",
10-
"test": "node --loader ts-node/esm tests/unit/cli.ts",
10+
"test": "node --loader ts-node/esm --test tests/unit/cli.ts tests/unit/alerts.ts",
1111
"deduplicate": "yarn-deduplicate"
1212
},
1313
"type": "module",

src/parser/alerts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,4 @@ const capitalize = (str: string) => {
125125
};
126126

127127
export default MarkdownItAlerts;
128+
export { resolveIcon }; // Exported for unit test

tests/unit/alerts.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import assert from 'node:assert';
2+
import test, { describe } from 'node:test';
3+
4+
import { resolveIcon } from '../../src/parser/alerts.js';
5+
6+
const assertFallback = (result: string) => {
7+
// We know a fallback icon is returned when result starts with this
8+
assert.match(result, /^<script>console\.warn\(/);
9+
// Contains the actual fallback icon
10+
assert.match(result, /<svg/);
11+
};
12+
13+
// Tests to make sure vivify-server isn't crashing on invalid options in
14+
// config.alertsOptions
15+
describe('resolveIcon returns fallback icon', () => {
16+
test('empty string', () => {
17+
assertFallback(resolveIcon('')); // empty string is considered (invalid) octicon name
18+
});
19+
20+
test('invalid octicon name', () => {
21+
assertFallback(resolveIcon('foo-bar')); // nonexistent
22+
assertFallback(resolveIcon('04trweäöcaöe')); // garbage
23+
assertFallback(resolveIcon('CircleSlashIcon')); // real icon but should be kebab-case
24+
});
25+
26+
test('valid paths but icon not found', () => {
27+
assertFallback(resolveIcon('/home/john/icons/flower.svg'));
28+
assertFallback(resolveIcon('~/icons/flower.svg'));
29+
assertFallback(resolveIcon('./alert-icons/gear.svg'));
30+
assertFallback(resolveIcon('../../svgs/dog.svg'));
31+
});
32+
33+
test('invalid paths', () => {
34+
assertFallback(resolveIcon('//home/john/icons/flower.svg')); // double slash
35+
assertFallback(resolveIcon('/home/john//icons/flower.svg')); // double slash alt
36+
assertFallback(resolveIcon('./alert icons/gear.svg')); // unescaped space
37+
});
38+
39+
test('misclassified invalid paths', () => {
40+
// Considered to be (invalid) octicon names
41+
assertFallback(resolveIcon('home/john/icons/flower.svg')); // missing beginning slash
42+
assertFallback(resolveIcon('~icons/flower.svg'));
43+
});
44+
45+
test('missing .svg extension', () => {
46+
// Considered to be (invalid) octicon names
47+
assertFallback(resolveIcon('/home/john/icons/flower'));
48+
assertFallback(resolveIcon('~/icons/flower'));
49+
assertFallback(resolveIcon('./alert-icons/gear'));
50+
assertFallback(resolveIcon('../../svgs/dog'));
51+
});
52+
53+
test('wrong file extension', () => {
54+
// Considered to be (invalid) octicon names
55+
assertFallback(resolveIcon('/home/john/icons/flower.png'));
56+
assertFallback(resolveIcon('~/icons/flower.jpg'));
57+
assertFallback(resolveIcon('./alert-icons/gear.txt'));
58+
assertFallback(resolveIcon('../../svgs/dog.ico'));
59+
});
60+
61+
test('wrong tag', () => {
62+
// Considered to be (invalid) octicon names
63+
assertFallback(resolveIcon("<img src='flower.png' alt='Alert icon hehe'>"));
64+
assertFallback(resolveIcon('<script>document.createElement("svg");</script>'));
65+
});
66+
});

0 commit comments

Comments
 (0)