fusion-js-test-common
v1.0.0
Published
Local reimplementation of the shared AMD/RequireJS + Karma + QUnit test harness
Readme
fusion-js-test-common
A local test harness package providing shared Karma, QUnit, and RequireJS tooling that the frontend test suite is written against.
What it provides
karma/commonConfiguration(require('fusion-js-test-common')) — the two thingsetc/frontend/karma.conf.jsandgulpfile.jsimport.commonConfiguration(config)takes theconfig.src.main/config.src.testdirs+file patterns karma.conf.js already builds and wires up everything else: a RequireJS bootstrap, thequnitkarma framework, aChromeHeadlessNoSandboxlauncher, andclient.qunit.testTimeout.- AMD modules, resolved via RequireJS in the browser (see
browser/):fusion/test/qunit,fusion/test/hamjest,fusion/test/jquery,fusion/test/backbone,fusion/test/mock-declaration,fusion/test/mock-view,fusion/test/mock-dialog2. ajs-stub.js/sinon-compat.js— plain (non-AMD) scripts loaded before RequireJS: a harmless stand-inAJSglobal + emptydvcs.connector.plugin.soynamespace (main/jsreaches for both directly, not through AMD), and a compatibility shim for the two sinon APIs this suite uses that modern sinon removed (see below).
How the test API works
QUnit.module('some/module/id', {
require: { main: 'some/module/id' }, // 'main' → 2nd arg of test()/beforeEach()
mocks: {
dep: QUnit.moduleMock('some/dep', () => value), // plain factory
other: QUnit.moduleMock('some/other', new MockDeclaration([ // sinon-stub-backed
'methodName', 'nested.methodName'
]).withConstructor()) // .withConstructor() if `new`'d
},
templates: { 'some.global.path': stubFn }, // set before main is required
beforeEach(assert, Main, mocks) { ... },
afterEach(assert, mocks) { ... },
someHelper() { ... } // mixed onto `this` for tests to call
});
QUnit.test('description', function (assert, Main, mocks) {
assert.assertThat('message', actual, matcher); // fusion/test/hamjest bridge
});Every entry in mocks is registered as a global RequireJS module
(requirejs.undef(id); define(id, [], () => value)) before require.main
is resolved, so anything main's dependency graph pulls in under that id
gets the mock instead of the real file. Mocks + main are resolved once per
QUnit.module() call (in a before hook) and reused for every test() in
that module — this suite adds/removes sinon spies on the same shared mock
objects across tests rather than re-creating them each time.
Between tests, fusion/test/qunit automatically:
- calls
.reset()on everysinon.stub()aMockDeclarationcreated (and on afusion/test/mock-view-based answer object, which also gets its event listeners cleared via.off()) — tests configure.returns(...)etc. fresh per test and rely on that not leaking into the next one; - restores a plain-object factory mock (e.g. a fake
window) to a snapshot taken when it was first created — some tests mutatemocks.window.locationdirectly.
After a module's last test, every app id it touched (via mocks or
require) is requirejs.undef()'d, so a module mocked as a dependency in
one file (e.g. dvcs-repos-table-view) doesn't leak into another file where
it's the main under test. jquery/underscore/backbone/sinon/
fusion/test/* are exempt from that cleanup — undefining those would force
RequireJS to re-fetch and re-evaluate the real UMD script, minting a new
jQuery/Backbone constructor with its own disconnected .fn/prototype.
Compatibility notes
- jQuery is pinned to 1.12.4, not a modern 3.x/4.x release: jQuery 3.0
removed the deprecated
jqXHR.error()/.success()/.complete()shortcuts this suite's REST client tests use. - sinon is modern (18.x), not vendored at an old version, so
sinon-compat.jsshims the two APIs this suite relies on that were removed:spy/stub.reset()(split intoresetHistory()/resetBehavior()) and the legacysinon.stub(obj, 'method', fn)3-arg form (nowsinon.stub(obj, 'method').callsFake(fn)). - Karma runs on
ChromeHeadlessNoSandbox, not PhantomJS: the karma.conf.jsbrowsersentry was updated for this. PhantomJS is unmaintained and, more concretely, the raw ES2015 intest/src/**/*-test.js(const, arrow functions, template literals) isn't valid PhantomJS-era JS — Karma serves those files directly (no transpile step), so a modern JS engine is required regardless of PhantomJS's maintenance status.
