timeout values and low hanging lint for hooks.js

mochawesome
John McLear 2021-01-27 20:09:05 +00:00
parent 0c9a19bd1b
commit 96d9a40b04
1 changed files with 51 additions and 4 deletions

View File

@ -1,15 +1,12 @@
/* global __dirname, __filename, afterEach, beforeEach, describe, it, process, require */
'use strict';
function m(mod) { return `${__dirname}/../../../src/${mod}`; }
const assert = require('assert').strict;
const common = require('../common');
const hooks = require(m('static/js/pluginfw/hooks'));
const plugins = require(m('static/js/pluginfw/plugin_defs'));
const sinon = require(m('node_modules/sinon'));
const logger = common.logger;
describe(__filename, function () {
const hookName = 'testHook';
const hookFnName = 'testPluginFileName:testHookFunctionName';
@ -98,11 +95,13 @@ describe(__filename, function () {
describe('basic behavior', function () {
it('passes hook name', async function () {
this.timeout(10);
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
callHookFnSync(hook);
});
it('passes context', async function () {
this.timeout(10);
for (const val of ['value', null, undefined]) {
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, val); };
callHookFnSync(hook, val);
@ -110,6 +109,7 @@ describe(__filename, function () {
});
it('returns the value provided to the callback', async function () {
this.timeout(10);
for (const val of ['value', null, undefined]) {
hook.hook_fn = (hn, ctx, cb) => { cb(ctx); };
assert.equal(callHookFnSync(hook, val), val);
@ -117,6 +117,7 @@ describe(__filename, function () {
});
it('returns the value returned by the hook function', async function () {
this.timeout(10);
for (const val of ['value', null, undefined]) {
// Must not have the cb parameter otherwise returning undefined will error.
hook.hook_fn = (hn, ctx) => ctx;
@ -125,16 +126,19 @@ describe(__filename, function () {
});
it('does not catch exceptions', async function () {
this.timeout(10);
hook.hook_fn = () => { throw new Error('test exception'); };
assert.throws(() => callHookFnSync(hook), {message: 'test exception'});
});
it('callback returns undefined', async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx, cb) => { assert.equal(cb('foo'), undefined); };
callHookFnSync(hook);
});
it('checks for deprecation', async function () {
this.timeout(10);
sinon.stub(console, 'warn');
hooks.deprecationNotices[hookName] = 'test deprecation';
callHookFnSync(hook);
@ -145,6 +149,7 @@ describe(__filename, function () {
});
describe('supported hook function styles', function () {
this.timeout(10);
for (const tc of supportedSyncHookFunctions) {
it(tc.name, async function () {
sinon.stub(console, 'warn');
@ -163,6 +168,7 @@ describe(__filename, function () {
});
describe('bad hook function behavior (other than double settle)', function () {
this.timeout(10);
const promise1 = Promise.resolve('val1');
const promise2 = Promise.resolve('val2');
@ -242,6 +248,7 @@ describe(__filename, function () {
if (step1.async && step2.async) continue;
it(`${step1.name} then ${step2.name} (diff. outcomes) -> log+throw`, async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx, cb) => {
step1.fn(cb, new Error(ctx.ret1), ctx.ret1);
return step2.fn(cb, new Error(ctx.ret2), ctx.ret2);
@ -305,6 +312,7 @@ describe(__filename, function () {
if (step1.rejects !== step2.rejects) continue;
it(`${step1.name} then ${step2.name} (same outcome) -> only log`, async function () {
this.timeout(10);
const err = new Error('val');
hook.hook_fn = (hn, ctx, cb) => {
step1.fn(cb, err, 'val');
@ -330,27 +338,32 @@ describe(__filename, function () {
describe('hooks.callAll', function () {
describe('basic behavior', function () {
it('calls all in order', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(1), makeHook(2), makeHook(3));
assert.deepEqual(hooks.callAll(hookName), [1, 2, 3]);
});
it('passes hook name', async function () {
this.timeout(10);
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
hooks.callAll(hookName);
});
it('undefined context -> {}', async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); };
hooks.callAll(hookName);
});
it('null context -> {}', async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); };
hooks.callAll(hookName, null);
});
it('context unmodified', async function () {
this.timeout(10);
const wantContext = {};
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, wantContext); };
hooks.callAll(hookName, wantContext);
@ -359,34 +372,40 @@ describe(__filename, function () {
describe('result processing', function () {
it('no registered hooks (undefined) -> []', async function () {
this.timeout(10);
delete plugins.hooks.testHook;
assert.deepEqual(hooks.callAll(hookName), []);
});
it('no registered hooks (empty list) -> []', async function () {
this.timeout(10);
testHooks.length = 0;
assert.deepEqual(hooks.callAll(hookName), []);
});
it('flattens one level', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]]));
assert.deepEqual(hooks.callAll(hookName), [1, 2, [3]]);
});
it('filters out undefined', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]));
assert.deepEqual(hooks.callAll(hookName), [2, [3]]);
});
it('preserves null', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(null), makeHook([2]), makeHook([[3]]));
assert.deepEqual(hooks.callAll(hookName), [null, 2, [3]]);
});
it('all undefined -> []', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(), makeHook());
assert.deepEqual(hooks.callAll(hookName), []);
@ -399,11 +418,13 @@ describe(__filename, function () {
describe('basic behavior', function () {
it('passes hook name', async function () {
this.timeout(10);
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
await callHookFnAsync(hook);
});
it('passes context', async function () {
this.timeout(10);
for (const val of ['value', null, undefined]) {
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, val); };
await callHookFnAsync(hook, val);
@ -411,6 +432,7 @@ describe(__filename, function () {
});
it('returns the value provided to the callback', async function () {
this.timeout(10);
for (const val of ['value', null, undefined]) {
hook.hook_fn = (hn, ctx, cb) => { cb(ctx); };
assert.equal(await callHookFnAsync(hook, val), val);
@ -419,6 +441,7 @@ describe(__filename, function () {
});
it('returns the value returned by the hook function', async function () {
this.timeout(10);
for (const val of ['value', null, undefined]) {
// Must not have the cb parameter otherwise returning undefined will never resolve.
hook.hook_fn = (hn, ctx) => ctx;
@ -428,26 +451,31 @@ describe(__filename, function () {
});
it('rejects if it throws an exception', async function () {
this.timeout(10);
hook.hook_fn = () => { throw new Error('test exception'); };
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
});
it('rejects if rejected Promise passed to callback', async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx, cb) => cb(Promise.reject(new Error('test exception')));
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
});
it('rejects if rejected Promise returned', async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx, cb) => Promise.reject(new Error('test exception'));
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
});
it('callback returns undefined', async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx, cb) => { assert.equal(cb('foo'), undefined); };
await callHookFnAsync(hook);
});
it('checks for deprecation', async function () {
this.timeout(10);
sinon.stub(console, 'warn');
hooks.deprecationNotices[hookName] = 'test deprecation';
await callHookFnAsync(hook);
@ -540,6 +568,7 @@ describe(__filename, function () {
for (const tc of supportedSyncHookFunctions.concat(supportedHookFunctions)) {
it(tc.name, async function () {
this.timeout(10);
sinon.stub(console, 'warn');
sinon.stub(console, 'error');
hook.hook_fn = tc.fn;
@ -687,6 +716,7 @@ describe(__filename, function () {
if (step1.name.startsWith('return ') || step1.name === 'throw') continue;
for (const step2 of behaviors) {
it(`${step1.name} then ${step2.name} (diff. outcomes) -> log+throw`, async function () {
this.timeout(10);
hook.hook_fn = (hn, ctx, cb) => {
step1.fn(cb, new Error(ctx.ret1), ctx.ret1);
return step2.fn(cb, new Error(ctx.ret2), ctx.ret2);
@ -740,6 +770,7 @@ describe(__filename, function () {
if (step1.rejects !== step2.rejects) continue;
it(`${step1.name} then ${step2.name} (same outcome) -> only log`, async function () {
this.timeout(10);
const err = new Error('val');
hook.hook_fn = (hn, ctx, cb) => {
step1.fn(cb, err, 'val');
@ -765,6 +796,7 @@ describe(__filename, function () {
describe('hooks.aCallAll', function () {
describe('basic behavior', function () {
it('calls all asynchronously, returns values in order', async function () {
this.timeout(10);
testHooks.length = 0; // Delete the boilerplate hook -- this test doesn't use it.
let nextIndex = 0;
const hookPromises = [];
@ -799,21 +831,25 @@ describe(__filename, function () {
});
it('passes hook name', async function () {
this.timeout(10);
hook.hook_fn = async (hn) => { assert.equal(hn, hookName); };
await hooks.aCallAll(hookName);
});
it('undefined context -> {}', async function () {
this.timeout(10);
hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); };
await hooks.aCallAll(hookName);
});
it('null context -> {}', async function () {
this.timeout(10);
hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); };
await hooks.aCallAll(hookName, null);
});
it('context unmodified', async function () {
this.timeout(10);
const wantContext = {};
hook.hook_fn = async (hn, ctx) => { assert.equal(ctx, wantContext); };
await hooks.aCallAll(hookName, wantContext);
@ -822,11 +858,13 @@ describe(__filename, function () {
describe('aCallAll callback', function () {
it('exception in callback rejects', async function () {
this.timeout(10);
const p = hooks.aCallAll(hookName, {}, () => { throw new Error('test exception'); });
await assert.rejects(p, {message: 'test exception'});
});
it('propagates error on exception', async function () {
this.timeout(10);
hook.hook_fn = () => { throw new Error('test exception'); };
await hooks.aCallAll(hookName, {}, (err) => {
assert(err instanceof Error);
@ -835,12 +873,14 @@ describe(__filename, function () {
});
it('propagages null error on success', async function () {
this.timeout(10);
await hooks.aCallAll(hookName, {}, (err) => {
assert(err == null, `got non-null error: ${err}`);
});
});
it('propagages results on success', async function () {
this.timeout(10);
hook.hook_fn = () => 'val';
await hooks.aCallAll(hookName, {}, (err, results) => {
assert.deepEqual(results, ['val']);
@ -848,40 +888,47 @@ describe(__filename, function () {
});
it('returns callback return value', async function () {
this.timeout(10);
assert.equal(await hooks.aCallAll(hookName, {}, () => 'val'), 'val');
});
});
describe('result processing', function () {
it('no registered hooks (undefined) -> []', async function () {
this.timeout(10);
delete plugins.hooks[hookName];
assert.deepEqual(await hooks.aCallAll(hookName), []);
});
it('no registered hooks (empty list) -> []', async function () {
this.timeout(10);
testHooks.length = 0;
assert.deepEqual(await hooks.aCallAll(hookName), []);
});
it('flattens one level', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]]));
assert.deepEqual(await hooks.aCallAll(hookName), [1, 2, [3]]);
});
it('filters out undefined', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]), makeHook(Promise.resolve()));
assert.deepEqual(await hooks.aCallAll(hookName), [2, [3]]);
});
it('preserves null', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(null), makeHook([2]), makeHook(Promise.resolve(null)));
assert.deepEqual(await hooks.aCallAll(hookName), [null, 2, null]);
});
it('all undefined -> []', async function () {
this.timeout(10);
testHooks.length = 0;
testHooks.push(makeHook(), makeHook(Promise.resolve()));
assert.deepEqual(await hooks.aCallAll(hookName), []);