Skip to content
Permalink
Browse files

Jest (#2002)

* Eslint all JS files in the repo

There are other JS files around the repo so let's lint those
as well.

* Add unit testing via the Jest framework

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 authored and mekarpeles committed Mar 23, 2019
1 parent c444d50 commit 0818d6bc5ff1d4f87cac8e57a2c82c3be3b6cc33
@@ -0,0 +1,14 @@
/.*
conf/
config/
docker/
infogami/
node_modules/
scripts/
static/build/
static/openbook/
static/js/
static/build/vendor.js
provisioning/
vendor/
tests/screenshots/
@@ -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)
@@ -59,7 +59,6 @@ window.uggettext = ugettext;

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

@@ -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;
}
@@ -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})/;
@@ -9,7 +9,8 @@
"check-bundles": "npm run build-assets && bundlesize",
"svg-min": "svgo static/images/**/*.svg && svgo static/images/*.svg",
"lint:fix": "stylelint --syntax less --fix static/css/",
"lint:js": "eslint --config .eslintrc.json openlibrary/plugins/openlibrary/js/",
"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": [
@@ -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",
@@ -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
}
}
@@ -0,0 +1,10 @@
{
"env": {
"es6": true,
"jest": true
},
"globals": {
"test": true,
"expect": true
}
}
@@ -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('');
});
@@ -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 0818d6b

Please sign in to comment.
You can’t perform that action at this time.