diff --git a/karma.conf.js b/karma.conf.js index f061e36b..c3d0cd06 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -26,7 +26,7 @@ module.exports = function (config) { logLevel: config.LOG_WARN, // config.LOG_DISABLE, config.LOG_ERROR, config.LOG_INFO, config.LOG_DEBUG frameworks: ['jasmine'], browsers: ['Chrome', 'Firefox', 'Safari'], - reporters: ['kjhtml', 'coverage', 'summary'], + reporters: ['kjhtml', 'summary'], retryLimit: 0, client: { captureConsole: false, @@ -46,16 +46,9 @@ module.exports = function (config) { stats: 'errors-only', logLevel: 'error' }, - coverageIstanbulReporter: { - combineBrowserReports: true, - fixWebpackSourcePaths: true, - reports: ['html', 'text-summary'], + coverageReporter: { dir: path.join(__dirname, 'coverage'), - 'report-config': { - html: { - subdir: 'html' - } - } + reporters: [{ type: 'html', subdir: 'html' }, { type: 'text-summary' }] }, summaryReporter: { show: 'failed', @@ -70,10 +63,11 @@ module.exports = function (config) { test: /\.js$/, loader: 'babel-loader', options: { - presets: ['@babel/preset-env'] + presets: ['@babel/preset-env'], + // instruments lib/ for the coverage reporter (npm run test:coverage) + plugins: [['istanbul', { include: ['lib/**'] }]] } }, - // istanbul-instrumenter-loader removed; use babel-plugin-istanbul for coverage { test: /\.css$/, use: { diff --git a/package.json b/package.json index 97f50c9e..1c0abfdc 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ ], "scripts": { "test": "karma start --single-run --browsers ChromeHeadless karma.conf.js", + "test:coverage": "karma start --single-run --browsers ChromeHeadless --reporters summary,coverage karma.conf.js", "test-local": "karma start --single-run", "generate:docs": "node_modules/.bin/jsdoc --configure .jsdoc.json --verbose", "build": "npx webpack", diff --git a/test/entrySpec.js b/test/entrySpec.js index 744d110c..2784b8f7 100755 --- a/test/entrySpec.js +++ b/test/entrySpec.js @@ -124,22 +124,19 @@ describe('Entry', function () { } }); - it('getField Invalid Uid Multiple', function () { + // 'group.group.group.0' is a valid path (the inner group is multiple), so it + // returns that instance; the old spec named it invalid and asserted nothing. + it('getField multiple group instance', function () { let uid = 'group.group.group.0'; - try { - entry.getField(uid); - } catch (e) { - expect(e.message).toEqual('Invalid uid, Field not found'); - } + let field = entry.getField(uid); + expect(field.uid).toEqual(uid); + expect(field.getData()).toEqual(testData.entry.group.group.group[0]); }); it('getField Invalid Uid', function () { - try { - entry.getField('invaliduid'); - } catch (e) { - expect(e.message).toEqual('Invalid uid, Field not found'); - } + // Current (undocumented) message prefix, as 2.2.3 throws it; b6d18c5 appends the cause. + expect(() => entry.getField('invaliduid')).toThrowError(/^Invalid uid, Field not found/); }); it('onSave Callback must be a function', function () { diff --git a/test/extensionSpec.js b/test/extensionSpec.js index 85d9dfe5..b5a46158 100755 --- a/test/extensionSpec.js +++ b/test/extensionSpec.js @@ -1,51 +1,46 @@ import originalTestData from './data/testData.json'; import Extension from '../lib/extension.js'; -import ExtensionModule from '../lib/extension.js'; +import helpers from './helpers'; -let testData = JSON.parse(JSON.stringify(originalTestData)) +// Extension.initialize posts 'init' to the host and karma has no host to answer, +// so these specs build Extension from init data, as the host would return it. describe('Extension', () => { - let newExtension; - let sendToParent = function (channel) { return Promise.resolve({ data: testData }); }; - let on = function (event, cbf) { - setTimeout(() => { - cbf({ data: { data: testData.entry, name: 'entrySave' } }); - cbf({ data: { data: {}, name: 'entryPublish' } }); - cbf({ data: { data: {}, name: 'entryUnPublish' } }); - cbf({ data: { data: testData.entry, name: 'entryChange' } }); - cbf({ data: { state: 'full_width', name: 'dashboardResize' } }); - cbf({ data: { data: 'sample', name: 'extensionFieldChange' } }); - }, 300); - }; + let testData; beforeEach(function () { - newExtension = ExtensionModule; + testData = helpers.clone(originalTestData); + helpers.resetExtensionEventListener(); }); - it('initialize', function (done) { - newExtension.initialize().then((data) => { - let extension = new newExtension(data); - expect(extension.config).toEqual(testData.config); - expect(extension.currentUser).toEqual(testData.user); - expect(extension.type).toEqual('FIELD'); + it('initialize', function () { + let extension = new Extension({ data: testData }); + expect(extension.config).toEqual(testData.config); + expect(extension.currentUser).toEqual(testData.user); + expect(extension.type).toEqual('FIELD'); + expect(extension.field).toBeDefined(); + expect(extension.entry).toBeDefined(); + expect(extension.window).toBeDefined(); - testData.type = 'SIDEBAR'; - extension = new newExtension(data); - expect(extension.type).toEqual(testData.type); - expect(extension.window).toBeUndefined(); - expect(extension.field).toBeUndefined(); + helpers.resetExtensionEventListener(); + testData.type = 'SIDEBAR'; + extension = new Extension({ data: testData }); + expect(extension.type).toEqual(testData.type); + expect(extension.window).toBeUndefined(); + expect(extension.field).toBeUndefined(); - testData.type = 'DASHBOARD'; - extension = new newExtension(data); - expect(extension.type).toEqual(testData.type); - expect(extension.entry).toBeUndefined(); - expect(extension.field).toBeUndefined(); - done(); - }); + helpers.resetExtensionEventListener(); + testData.type = 'DASHBOARD'; + extension = new Extension({ data: testData }); + expect(extension.type).toEqual(testData.type); + expect(extension.entry).toBeUndefined(); + expect(extension.field).toBeUndefined(); }); it('setReady', function (done) { - let extension = new newExtension({ data: testData }); + let extension = new Extension({ data: testData }); + extension.postRobot = { sendToParent: jasmine.createSpy('sendToParent').and.returnValue(Promise.resolve()) }; extension.setReady().then(() => { + expect(extension.postRobot.sendToParent).toHaveBeenCalledWith('ready'); done(); }); }); diff --git a/test/helpers/index.js b/test/helpers/index.js index 89cc5339..ef85e06a 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -1,2 +1,8 @@ const clone = (source) => JSON.parse(JSON.stringify(source)); -module.exports.clone = clone ; \ No newline at end of file +module.exports.clone = clone ; +// Each Extension registers one post-robot 'extensionEvent' listener and post-robot +// refuses a second one for the same window, so specs that build several reset it. +const resetExtensionEventListener = () => { + delete window.__postRobot__.requestListeners.extensionEvent; +}; +module.exports.resetExtensionEventListener = resetExtensionEventListener; diff --git a/test/sdkSpec.js b/test/sdkSpec.js index 25656885..3065e5dc 100755 --- a/test/sdkSpec.js +++ b/test/sdkSpec.js @@ -1,53 +1,43 @@ import testData from './data/testData.json'; import ContentstackUIExtension from '../lib/index.js'; -import MainModule from '../lib/index.js'; -import ExtensionModule from '../lib/extension.js'; +import Extension from '../lib/extension.js'; import pkg from '../package.json'; +import helpers from './helpers'; - +// karma has no host to answer 'init', so Extension.initialize is stubbed with +// what the host returns. describe('ContentstackUIExtension', () => { - let newContentstackUIExtension; - let sendToParent; - let on = function (event, cbf) { - setTimeout(() => { - cbf({ data: testData.entry }); - }, 300); - }; - + beforeEach(function () { + ContentstackUIExtension._extension = undefined; + helpers.resetExtensionEventListener(); + }); it('init', function (done) { - sendToParent = function (channel) { return Promise.resolve({ data: testData }); }; - - // Directly use the imported modules (mocking can be done with jest or sinon if needed) - let newExtensionModule = ExtensionModule; - newContentstackUIExtension = MainModule; + spyOn(Extension, 'initialize').and.returnValue(Promise.resolve({ data: helpers.clone(testData) })); - - newContentstackUIExtension.init().then((extension) => { + ContentstackUIExtension.init().then((extension) => { + expect(Extension.initialize).toHaveBeenCalledWith(pkg.version); expect(extension.config).toEqual(testData.config); expect(extension.currentUser).toEqual(testData.user); expect(extension.type).toEqual('FIELD'); - newContentstackUIExtension.init().then((newExtesnion) => { // must return same extension object once initialized - expect(extension).toEqual(newExtesnion); + ContentstackUIExtension.init().then((newExtension) => { // must return same extension object once initialized + expect(newExtension).toBe(extension); + expect(Extension.initialize.calls.count()).toEqual(1); done(); }); }); }); it('init failure', function (done) { - sendToParent = function (channel) { return Promise.reject('Sample Error'); }; - - let newExtensionModule = ExtensionModule; - newContentstackUIExtension = MainModule; - + spyOn(Extension, 'initialize').and.returnValue(Promise.reject('Sample Error')); - newContentstackUIExtension.init().catch((error) => { + ContentstackUIExtension.init().catch((error) => { expect(error).toEqual('Sample Error'); done(); }); }); it('SDK_VERSION', function () { - expect(newContentstackUIExtension.SDK_VERSION).toEqual(pkg.version); + expect(ContentstackUIExtension.SDK_VERSION).toEqual(pkg.version); }); });