Skip to content

Commit

Permalink
Add unit testing via the Jest framework
Browse files Browse the repository at this point in the history
From now on we'll write unit tests to strengthen our code.
I begin by writing tests for two simple files.
In the process, I discover a bug in htmlquote (which I fix!)
Code coverage is reported and lowest coverage possible is defined
in package.json. We will work towards increasing this with time
as we refactor. For now code coverage is 1%.. you have to start
somewhere!!

Fixes: #1999
  • Loading branch information
jdlrobson committed Mar 23, 2019
1 parent 0006ffb commit 398916d
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 7 deletions.
3 changes: 1 addition & 2 deletions openlibrary/plugins/openlibrary/js/index.js
Expand Up @@ -10,7 +10,7 @@ import loadStyle from './loadStyle';
import { ungettext, ugettext, sprintf } from './i18n';
import { addFadeInFunctionsTojQuery } from './jquery.others';
import jQueryRepeat from './jquery.repeat';
import { ForLoop, enumerate, htmlquote, websafe, foreach, join, len, range } from './jsdef';
import { enumerate, htmlquote, websafe, foreach, join, len, range } from './jsdef';
// Note this import will also load various jQuery plugins.
// (jQuery.ScrollTo, jquery.hoverIntent, jquery.dataTables, dataTableExt,
// highlight, removeHighlight, jTruncate, columnize)
Expand Down Expand Up @@ -59,7 +59,6 @@ window._uggettext = ugettext;

window.Browser = Browser;
window.Carousel = Carousel;
window.ForLoop = ForLoop;
window.Subject = Subject;
window.Template = Template;

Expand Down
10 changes: 5 additions & 5 deletions openlibrary/plugins/openlibrary/js/jsdef.js
Expand Up @@ -131,10 +131,10 @@ export function websafe(value) {
export function htmlquote(text) {
// This code exists for compatibility with template.js
text = String(text);
text = text.replace("&", "&"); // Must be done first!
text = text.replace("<", "&lt;");
text = text.replace(">", "&gt;");
text = text.replace("'", "&#39;");
text = text.replace('"', "&quot;");
text = text.replace(/&/g, "&amp;"); // Must be done first!
text = text.replace(/</g, "&lt;");
text = text.replace(/>/g, "&gt;");
text = text.replace(/'/g, "&#39;");
text = text.replace(/"/g, "&quot;");
return text;
}
8 changes: 8 additions & 0 deletions openlibrary/plugins/openlibrary/js/python.js
@@ -1,4 +1,12 @@
// used in templates/admin/index.html

/**
* Add commas to a number
* e.g. 1000 becomes 1,000
* 1 million becomes 1,000,000
* @param {mixed} n
* @return {string}
*/
export function commify(n) {
var text = n.toString();
var re = /(\d+)(\d{3})/;
Expand Down
16 changes: 16 additions & 0 deletions package.json
Expand Up @@ -10,6 +10,7 @@
"svg-min": "svgo static/images/**/*.svg && svgo static/images/*.svg",
"lint:fix": "stylelint --syntax less --fix static/css/",
"lint:js": "eslint --config .eslintrc.json .",
"test:unit": "jest --testRegex tests/unit/**/*.js",
"test": "npm run check-bundles && stylelint --syntax less static/css/ && npm run lint:js"
},
"bundlesize": [
Expand Down Expand Up @@ -62,6 +63,7 @@
"bundlesize": "^0.17.0",
"detect-libc": "^1.0.3",
"eslint": "^5.7.0",
"jest": "^24.5.0",
"less": "^3.8.1",
"node-gyp": "^3.8.0",
"prebuild-install": "^5.2.1",
Expand All @@ -70,5 +72,19 @@
"svgo": "1.1.1",
"webpack": "4.27.1",
"webpack-cli": "3.1.2"
},
"jest": {
"collectCoverageFrom": [
"openlibrary/plugins/openlibrary/js/**/*.js"
],
"coverageThreshold": {
"global": {
"branches": 0.6,
"functions": 1,
"lines": 1,
"statements": 1
}
},
"collectCoverage": true
}
}
10 changes: 10 additions & 0 deletions tests/unit/.eslintrc.json
@@ -0,0 +1,10 @@
{
"env": {
"es6": true,
"jest": true
},
"globals": {
"test": true,
"expect": true
}
}
57 changes: 57 additions & 0 deletions tests/unit/js/test.jsdef.js
@@ -0,0 +1,57 @@
import { foreach, range, join, len, htmlquote, enumerate,
websafe } from '../../../openlibrary/plugins/openlibrary/js/jsdef';

test('jsdef: python range function', () => {
expect(range(2, 5)).toEqual([2, 3, 4]);
expect(range(5)).toEqual([0, 1, 2, 3, 4]);
expect(range(0, 10, 2)).toEqual([0, 2, 4, 6, 8]);
});

test('jsdef: enumerate', () => {
expect(enumerate([1, 2, 3])).toEqual([
['0', 1],
['1', 2],
['2', 3]
]);
});

test('jsdef: foreach', () => {
let called = 0;
const loop = [];
const listToLoop = [1, 2, 3];
expect.assertions(1);
return new Promise((resolve) => {
foreach(listToLoop, loop, function () {
called += 1;
if (called === 3) {
expect(called).toBe(3);
resolve();
}
})
});
});

test('jsdef: join', () => {
const str = '-';
const joinFn = join.bind(str);
expect(joinFn(['1', '2'])).toBe('1-2');
});

test('jsdef: len', () => {
expect(len(['1', '2'])).toBe(2);
});

test('jsdef: htmlquote', () => {
expect(htmlquote(5)).toBe('5');
expect(htmlquote('<foo>')).toBe('&lt;foo&gt;');
expect(htmlquote('\'foo\': "bar"')).toBe('&#39;foo&#39;: &quot;bar&quot;');
expect(htmlquote('a&b')).toBe('a&amp;b');
});

test('jsdef: websafe', () => {
expect(websafe('<script>')).toBe('&lt;script&gt;');
// not sure if these are really necessary, but they document the current behaviour
expect(websafe(undefined)).toBe('');
expect(websafe(null)).toBe('');
expect(websafe({toString: undefined})).toBe('');
});
9 changes: 9 additions & 0 deletions tests/unit/js/test.python.js
@@ -0,0 +1,9 @@
import { commify } from '../../../openlibrary/plugins/openlibrary/js/python';

test('commify', () => {
expect(commify('5443232')).toBe('5,443,232');
expect(commify('50')).toBe('50');
expect(commify('5000')).toBe('5,000');
expect(commify(['1','2','3','45'])).toBe('1,2,3,45');
expect(commify([1, 20, 3])).toBe('1,20,3');
});

0 comments on commit 398916d

Please sign in to comment.