From c4fa90a747151f8c63254362b39890fbf0455a44 Mon Sep 17 00:00:00 2001 From: Lars Jung Date: Wed, 1 Jun 2016 02:15:04 +0200 Subject: [PATCH] Add scar tests. --- ghu.js | 39 ++++++++++++++++++++++++++++++-- package.json | 4 +++- test-scar/.eslintrc | 3 +++ test-scar/tests.html | 10 ++++++++ test-scar/tests.js | 16 +++++++++++++ test-scar/tests/premisses.js | 21 +++++++++++++++++ test-scar/tests/unit/boot.js | 33 +++++++++++++++++++++++++++ test-scar/tests/unit/config.js | 32 ++++++++++++++++++++++++++ test-scar/tests/unit/libs.js | 25 ++++++++++++++++++++ test-scar/tests/unit/modulejs.js | 33 +++++++++++++++++++++++++++ test-scar/util/modjs.js | 17 ++++++++++++++ test-scar/util/pin.js | 33 +++++++++++++++++++++++++++ 12 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 test-scar/.eslintrc create mode 100644 test-scar/tests.html create mode 100644 test-scar/tests.js create mode 100644 test-scar/tests/premisses.js create mode 100644 test-scar/tests/unit/boot.js create mode 100644 test-scar/tests/unit/config.js create mode 100644 test-scar/tests/unit/libs.js create mode 100644 test-scar/tests/unit/modulejs.js create mode 100644 test-scar/util/modjs.js create mode 100644 test-scar/util/pin.js diff --git a/ghu.js b/ghu.js index a2419650..5c45de1a 100644 --- a/ghu.js +++ b/ghu.js @@ -7,6 +7,7 @@ const { const ROOT = resolve(__dirname); const SRC = join(ROOT, 'src'); const TEST = join(ROOT, 'test'); +const TEST_SCAR = join(ROOT, 'test-scar'); const BUILD = join(ROOT, 'build'); const mapper = mapfn.p(SRC, BUILD).s('.less', '.css').s('.jade', ''); @@ -150,7 +151,41 @@ ghu.task('build:tests', ['build:scripts', 'build:styles'], 'build the test suite }); }); -ghu.task('build', ['build:scripts', 'build:styles', 'build:pages', 'build:copy', 'build:tests'], +ghu.task('build:tests-scar', ['build:scripts', 'build:styles'], 'build the test suite', () => { + const webpackConfig = { + module: { + loaders: [ + { + include: [TEST_SCAR], + loader: 'babel', + query: {cacheDirectory: true} + } + ] + } + }; + + return Promise.all([ + read(`${BUILD}/_h5ai/public/js/scripts.js`) + .then(newerThan(`${BUILD}/test-scar/h5ai-scripts.js`)) + .then(write(`${BUILD}/test-scar/h5ai-scripts.js`, {overwrite: true})), + + read(`${BUILD}/_h5ai/public/css/styles.css`) + .then(newerThan(`${BUILD}/test-scar/h5ai-styles.css`)) + .then(write(`${BUILD}/test-scar/h5ai-styles.css`, {overwrite: true})), + + read(`${TEST_SCAR}/tests.html`) + .then(newerThan(`${BUILD}/test-scar/tests.html`)) + .then(write(`${BUILD}/test-scar/tests.html`, {overwrite: true})), + + read(`${TEST_SCAR}: tests.js`) + .then(webpack(webpackConfig, {showStats: false})) + .then(write(mapfn.p(TEST_SCAR, `${BUILD}/test-scar`), {overwrite: true})) + ]).then(() => { + console.log(`browse to file://${BUILD}/test-scar/tests.html to run the test suite`); + }); +}); + +ghu.task('build', ['build:scripts', 'build:styles', 'build:pages', 'build:copy', 'build:tests', 'build:tests-scar'], 'build all updated files, optionally use :production'); ghu.task('deploy', ['build'], 'deploy to a specified path with :dest=/some/path', runtime => { @@ -167,7 +202,7 @@ ghu.task('deploy', ['build'], 'deploy to a specified path with :dest=/some/path' }); ghu.task('watch', runtime => { - return watch([SRC, TEST], () => ghu.run(runtime.sequence.filter(x => x !== 'watch'), runtime.args, true)); + return watch([SRC, TEST, TEST_SCAR], () => ghu.run(runtime.sequence.filter(x => x !== 'watch'), runtime.args, true)); }); ghu.task('release', ['force-production', 'clean', 'build'], 'create a zipball', runtime => { diff --git a/package.json b/package.json index f1e02782..f62c6608 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "babel-loader": "6.2.4", "babel-preset-es2015": "6.9.0", "eslint": "2.11.0", - "ghu": "0.6.0" + "ghu": "0.6.0", + "scar": "0.10.1", + "sinon": "2.0.0-pre" }, "engines": { "node": ">=6.0.0" diff --git a/test-scar/.eslintrc b/test-scar/.eslintrc new file mode 100644 index 00000000..34d009c4 --- /dev/null +++ b/test-scar/.eslintrc @@ -0,0 +1,3 @@ +--- + env: + browser: true diff --git a/test-scar/tests.html b/test-scar/tests.html new file mode 100644 index 00000000..26434ba4 --- /dev/null +++ b/test-scar/tests.html @@ -0,0 +1,10 @@ + + + + + h5ai test suite - scar + + + + + diff --git a/test-scar/tests.js b/test-scar/tests.js new file mode 100644 index 00000000..2d3319f9 --- /dev/null +++ b/test-scar/tests.js @@ -0,0 +1,16 @@ +const {test} = require('scar'); +const {clearModulejs, mockConfigModule} = require('./util/modjs'); +const {pinHtml} = require('./util/pin'); + +mockConfigModule(); +clearModulejs(); + +require('./tests/premisses'); +require('./tests/unit/boot'); +require('./tests/unit/config'); +require('./tests/unit/libs'); +require('./tests/unit/modulejs'); + +pinHtml(); + +test.cli({sync: true}); diff --git a/test-scar/tests/premisses.js b/test-scar/tests/premisses.js new file mode 100644 index 00000000..e5e25cf5 --- /dev/null +++ b/test-scar/tests/premisses.js @@ -0,0 +1,21 @@ +const {test, assert} = require('scar'); + +test('window is global object', () => { + assert.equal(typeof window, 'object'); + assert.equal(window, window.window); +}); + +test('document is global object', () => { + assert.equal(typeof window.document, 'object'); +}); + +test('jQuery and $ are global functions', () => { + assert.equal(typeof window.jQuery, 'function'); + assert.equal(window.jQuery.fn.jquery, '2.2.4'); + assert.equal(window.jQuery, window.$); +}); + +test('_ is global function', () => { + assert.equal(typeof window._, 'function'); + assert.equal(window._.VERSION, '4.13.1'); +}); diff --git a/test-scar/tests/unit/boot.js b/test-scar/tests/unit/boot.js new file mode 100644 index 00000000..c49ed768 --- /dev/null +++ b/test-scar/tests/unit/boot.js @@ -0,0 +1,33 @@ +const {test, assert} = require('scar'); +const sinon = require('sinon'); + +const ID = 'boot'; +const DEPS = ['$', 'core/server']; + +const getDef = () => window.modulejs._private.definitions[ID]; +const createInst = () => getDef().fn.call(null, window.jQuery, {}); + +test(`module '${ID}' is defined`, () => { + assert.ok(getDef()); +}); + +test(`module '${ID}' has correct id`, () => { + assert.equal(getDef().id, ID); +}); + +test(`module '${ID}' has correct deps`, () => { + assert.deepEqual(getDef().deps, DEPS); +}); + +test(`module '${ID}' has args for each dependency`, () => { + const def = getDef(); + assert.deepEqual(def.deps.length, def.fn.length); +}); + +test(`module '${ID}' inits without errors`, () => { + createInst(); +}); + +test(`module '${ID}' instance is undefined`, () => { + assert.equal(createInst(), undefined); +}); diff --git a/test-scar/tests/unit/config.js b/test-scar/tests/unit/config.js new file mode 100644 index 00000000..6ac18eee --- /dev/null +++ b/test-scar/tests/unit/config.js @@ -0,0 +1,32 @@ +const {test, assert} = require('scar'); + +const ID = 'config'; +const DEPS = []; + +const getDef = () => window.modulejs._private.definitions[ID]; +const createInst = () => getDef().fn(); + +test(`module '${ID}' is defined`, () => { + assert.ok(getDef()); +}); + +test(`module '${ID}' has correct id`, () => { + assert.equal(getDef().id, ID); +}); + +test(`module '${ID}' has correct deps`, () => { + assert.deepEqual(getDef().deps, DEPS); +}); + +test(`module '${ID}' has args for each dependency`, () => { + const def = getDef(); + assert.deepEqual(def.deps.length, def.fn.length); +}); + +test(`module '${ID}' inits without errors`, () => { + createInst(); +}); + +test(`module '${ID}' is only dummy definiton`, () => { + assert.deepEqual(createInst(), {_dummyConfig: true}); +}); diff --git a/test-scar/tests/unit/libs.js b/test-scar/tests/unit/libs.js new file mode 100644 index 00000000..0140d2e5 --- /dev/null +++ b/test-scar/tests/unit/libs.js @@ -0,0 +1,25 @@ +const {test, assert} = require('scar'); + +const libs = { + _: window._, + $: window.jQuery, + marked: window.marked, + prism: window.Prism +}; + +Object.keys(libs).forEach(id => { + test(`module '${id}' is defined`, () => { + assert.ok(window.modulejs._private.definitions[id]); + }); + + test(`module '${id}' has no instance`, () => { + assert.equal(window.modulejs._private.instances[id], undefined); + }); + + test(`module '${id}' returns global lib`, () => { + const definition = window.modulejs._private.definitions[id]; + const instance = definition.fn(); + assert.ok(instance); + assert.equal(instance, libs[id]); + }); +}); diff --git a/test-scar/tests/unit/modulejs.js b/test-scar/tests/unit/modulejs.js new file mode 100644 index 00000000..7fc11fba --- /dev/null +++ b/test-scar/tests/unit/modulejs.js @@ -0,0 +1,33 @@ +const {test, assert} = require('scar'); + +test('modulejs is global object', () => { + assert.equal(typeof window.modulejs, 'object'); +}); + +test('modulejs.define() is function', () => { + assert.equal(typeof window.modulejs.define, 'function'); +}); + +test('modulejs.require() is function', () => { + assert.equal(typeof window.modulejs.require, 'function'); +}); + +test('modulejs.state() is function', () => { + assert.equal(typeof window.modulejs.state, 'function'); +}); + +test('modulejs.log() is function', () => { + assert.equal(typeof window.modulejs.log, 'function'); +}); + +test('modulejs._private is object', () => { + assert.equal(typeof window.modulejs._private, 'object'); +}); + +test('modulejs has definitions', () => { + assert.ok(Object.keys(window.modulejs._private.definitions).length >= 0); +}); + +test('modulejs has no instances', () => { + assert.equal(Object.keys(window.modulejs._private.instances).length, 0); +}); diff --git a/test-scar/util/modjs.js b/test-scar/util/modjs.js new file mode 100644 index 00000000..49de5244 --- /dev/null +++ b/test-scar/util/modjs.js @@ -0,0 +1,17 @@ +const lodash = window._; +const modjs = window.modulejs; + +function clearModulejs() { + lodash.each(modjs._private.instances, (val, key) => { + delete modjs._private.instances[key]; // eslint-disable-line prefer-reflect + }); +} + +function mockConfigModule() { + modjs.define('config', {_dummyConfig: true}); +} + +module.exports = { + clearModulejs, + mockConfigModule +}; diff --git a/test-scar/util/pin.js b/test-scar/util/pin.js new file mode 100644 index 00000000..1419ffca --- /dev/null +++ b/test-scar/util/pin.js @@ -0,0 +1,33 @@ +const jq = window.jQuery; +let title; +let htmlId; +let htmlClasses; +let bodyId; +let bodyClasses; +let $pinnedElements; + +function pinHtml() { + title = document.title; + htmlId = jq('html').attr('id'); + htmlClasses = jq('html').attr('class'); + bodyId = jq('body').attr('id'); + bodyClasses = jq('body').attr('class'); + $pinnedElements = jq('head,body').children(); +} + +function restoreHtml() { + document.title = title; + jq('html').attr('id', htmlId); + jq('html').attr('class', htmlClasses); + jq('body').attr('id', bodyId); + jq('body').attr('class', bodyClasses); + jq('head,body').children().not($pinnedElements).remove(); + if (window.localStorage && window.localStorage.clear) { + window.localStorage.clear(); + } +} + +module.exports = { + pinHtml, + restoreHtml +};