Best JavaScript code snippet using storybook-root
hooks.js
Source:hooks.js  
1/******/ (function() { // webpackBootstrap2/******/ 	"use strict";3/******/ 	// The require scope4/******/ 	var __webpack_require__ = {};5/******/ 	6/************************************************************************/7/******/ 	/* webpack/runtime/define property getters */8/******/ 	!function() {9/******/ 		// define getter functions for harmony exports10/******/ 		__webpack_require__.d = function(exports, definition) {11/******/ 			for(var key in definition) {12/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {13/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });14/******/ 				}15/******/ 			}16/******/ 		};17/******/ 	}();18/******/ 	19/******/ 	/* webpack/runtime/hasOwnProperty shorthand */20/******/ 	!function() {21/******/ 		__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }22/******/ 	}();23/******/ 	24/******/ 	/* webpack/runtime/make namespace object */25/******/ 	!function() {26/******/ 		// define __esModule on exports27/******/ 		__webpack_require__.r = function(exports) {28/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {29/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });30/******/ 			}31/******/ 			Object.defineProperty(exports, '__esModule', { value: true });32/******/ 		};33/******/ 	}();34/******/ 	35/************************************************************************/36var __webpack_exports__ = {};37// ESM COMPAT FLAG38__webpack_require__.r(__webpack_exports__);39// EXPORTS40__webpack_require__.d(__webpack_exports__, {41  "actions": function() { return /* binding */ actions; },42  "addAction": function() { return /* binding */ addAction; },43  "addFilter": function() { return /* binding */ addFilter; },44  "applyFilters": function() { return /* binding */ applyFilters; },45  "createHooks": function() { return /* reexport */ build_module_createHooks; },46  "currentAction": function() { return /* binding */ currentAction; },47  "currentFilter": function() { return /* binding */ currentFilter; },48  "defaultHooks": function() { return /* binding */ defaultHooks; },49  "didAction": function() { return /* binding */ didAction; },50  "didFilter": function() { return /* binding */ didFilter; },51  "doAction": function() { return /* binding */ doAction; },52  "doingAction": function() { return /* binding */ doingAction; },53  "doingFilter": function() { return /* binding */ doingFilter; },54  "filters": function() { return /* binding */ filters; },55  "hasAction": function() { return /* binding */ hasAction; },56  "hasFilter": function() { return /* binding */ hasFilter; },57  "removeAction": function() { return /* binding */ removeAction; },58  "removeAllActions": function() { return /* binding */ removeAllActions; },59  "removeAllFilters": function() { return /* binding */ removeAllFilters; },60  "removeFilter": function() { return /* binding */ removeFilter; }61});62;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/validateNamespace.js63/**64 * Validate a namespace string.65 *66 * @param {string} namespace The namespace to validate - should take the form67 *                           `vendor/plugin/function`.68 *69 * @return {boolean} Whether the namespace is valid.70 */71function validateNamespace(namespace) {72  if ('string' !== typeof namespace || '' === namespace) {73    // eslint-disable-next-line no-console74    console.error('The namespace must be a non-empty string.');75    return false;76  }77  if (!/^[a-zA-Z][a-zA-Z0-9_.\-\/]*$/.test(namespace)) {78    // eslint-disable-next-line no-console79    console.error('The namespace can only contain numbers, letters, dashes, periods, underscores and slashes.');80    return false;81  }82  return true;83}84/* harmony default export */ var build_module_validateNamespace = (validateNamespace);85;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/validateHookName.js86/**87 * Validate a hookName string.88 *89 * @param {string} hookName The hook name to validate. Should be a non empty string containing90 *                          only numbers, letters, dashes, periods and underscores. Also,91 *                          the hook name cannot begin with `__`.92 *93 * @return {boolean} Whether the hook name is valid.94 */95function validateHookName(hookName) {96  if ('string' !== typeof hookName || '' === hookName) {97    // eslint-disable-next-line no-console98    console.error('The hook name must be a non-empty string.');99    return false;100  }101  if (/^__/.test(hookName)) {102    // eslint-disable-next-line no-console103    console.error('The hook name cannot begin with `__`.');104    return false;105  }106  if (!/^[a-zA-Z][a-zA-Z0-9_.-]*$/.test(hookName)) {107    // eslint-disable-next-line no-console108    console.error('The hook name can only contain numbers, letters, dashes, periods and underscores.');109    return false;110  }111  return true;112}113/* harmony default export */ var build_module_validateHookName = (validateHookName);114;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createAddHook.js115/**116 * Internal dependencies117 */118/**119 * @callback AddHook120 *121 * Adds the hook to the appropriate hooks container.122 *123 * @param {string}               hookName      Name of hook to add124 * @param {string}               namespace     The unique namespace identifying the callback in the form `vendor/plugin/function`.125 * @param {import('.').Callback} callback      Function to call when the hook is run126 * @param {number}               [priority=10] Priority of this hook127 */128/**129 * Returns a function which, when invoked, will add a hook.130 *131 * @param {import('.').Hooks}    hooks    Hooks instance.132 * @param {import('.').StoreKey} storeKey133 *134 * @return {AddHook} Function that adds a new hook.135 */136function createAddHook(hooks, storeKey) {137  return function addHook(hookName, namespace, callback) {138    let priority = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 10;139    const hooksStore = hooks[storeKey];140    if (!build_module_validateHookName(hookName)) {141      return;142    }143    if (!build_module_validateNamespace(namespace)) {144      return;145    }146    if ('function' !== typeof callback) {147      // eslint-disable-next-line no-console148      console.error('The hook callback must be a function.');149      return;150    } // Validate numeric priority151    if ('number' !== typeof priority) {152      // eslint-disable-next-line no-console153      console.error('If specified, the hook priority must be a number.');154      return;155    }156    const handler = {157      callback,158      priority,159      namespace160    };161    if (hooksStore[hookName]) {162      // Find the correct insert index of the new hook.163      const handlers = hooksStore[hookName].handlers;164      /** @type {number} */165      let i;166      for (i = handlers.length; i > 0; i--) {167        if (priority >= handlers[i - 1].priority) {168          break;169        }170      }171      if (i === handlers.length) {172        // If append, operate via direct assignment.173        handlers[i] = handler;174      } else {175        // Otherwise, insert before index via splice.176        handlers.splice(i, 0, handler);177      } // We may also be currently executing this hook.  If the callback178      // we're adding would come after the current callback, there's no179      // problem; otherwise we need to increase the execution index of180      // any other runs by 1 to account for the added element.181      hooksStore.__current.forEach(hookInfo => {182        if (hookInfo.name === hookName && hookInfo.currentIndex >= i) {183          hookInfo.currentIndex++;184        }185      });186    } else {187      // This is the first hook of its type.188      hooksStore[hookName] = {189        handlers: [handler],190        runs: 0191      };192    }193    if (hookName !== 'hookAdded') {194      hooks.doAction('hookAdded', hookName, namespace, callback, priority);195    }196  };197}198/* harmony default export */ var build_module_createAddHook = (createAddHook);199;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createRemoveHook.js200/**201 * Internal dependencies202 */203/**204 * @callback RemoveHook205 * Removes the specified callback (or all callbacks) from the hook with a given hookName206 * and namespace.207 *208 * @param {string} hookName  The name of the hook to modify.209 * @param {string} namespace The unique namespace identifying the callback in the210 *                           form `vendor/plugin/function`.211 *212 * @return {number | undefined} The number of callbacks removed.213 */214/**215 * Returns a function which, when invoked, will remove a specified hook or all216 * hooks by the given name.217 *218 * @param {import('.').Hooks}    hooks             Hooks instance.219 * @param {import('.').StoreKey} storeKey220 * @param {boolean}              [removeAll=false] Whether to remove all callbacks for a hookName,221 *                                                 without regard to namespace. Used to create222 *                                                 `removeAll*` functions.223 *224 * @return {RemoveHook} Function that removes hooks.225 */226function createRemoveHook(hooks, storeKey) {227  let removeAll = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;228  return function removeHook(hookName, namespace) {229    const hooksStore = hooks[storeKey];230    if (!build_module_validateHookName(hookName)) {231      return;232    }233    if (!removeAll && !build_module_validateNamespace(namespace)) {234      return;235    } // Bail if no hooks exist by this name.236    if (!hooksStore[hookName]) {237      return 0;238    }239    let handlersRemoved = 0;240    if (removeAll) {241      handlersRemoved = hooksStore[hookName].handlers.length;242      hooksStore[hookName] = {243        runs: hooksStore[hookName].runs,244        handlers: []245      };246    } else {247      // Try to find the specified callback to remove.248      const handlers = hooksStore[hookName].handlers;249      for (let i = handlers.length - 1; i >= 0; i--) {250        if (handlers[i].namespace === namespace) {251          handlers.splice(i, 1);252          handlersRemoved++; // This callback may also be part of a hook that is253          // currently executing.  If the callback we're removing254          // comes after the current callback, there's no problem;255          // otherwise we need to decrease the execution index of any256          // other runs by 1 to account for the removed element.257          hooksStore.__current.forEach(hookInfo => {258            if (hookInfo.name === hookName && hookInfo.currentIndex >= i) {259              hookInfo.currentIndex--;260            }261          });262        }263      }264    }265    if (hookName !== 'hookRemoved') {266      hooks.doAction('hookRemoved', hookName, namespace);267    }268    return handlersRemoved;269  };270}271/* harmony default export */ var build_module_createRemoveHook = (createRemoveHook);272;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createHasHook.js273/**274 * @callback HasHook275 *276 * Returns whether any handlers are attached for the given hookName and optional namespace.277 *278 * @param {string} hookName    The name of the hook to check for.279 * @param {string} [namespace] Optional. The unique namespace identifying the callback280 *                             in the form `vendor/plugin/function`.281 *282 * @return {boolean} Whether there are handlers that are attached to the given hook.283 */284/**285 * Returns a function which, when invoked, will return whether any handlers are286 * attached to a particular hook.287 *288 * @param {import('.').Hooks}    hooks    Hooks instance.289 * @param {import('.').StoreKey} storeKey290 *291 * @return {HasHook} Function that returns whether any handlers are292 *                   attached to a particular hook and optional namespace.293 */294function createHasHook(hooks, storeKey) {295  return function hasHook(hookName, namespace) {296    const hooksStore = hooks[storeKey]; // Use the namespace if provided.297    if ('undefined' !== typeof namespace) {298      return hookName in hooksStore && hooksStore[hookName].handlers.some(hook => hook.namespace === namespace);299    }300    return hookName in hooksStore;301  };302}303/* harmony default export */ var build_module_createHasHook = (createHasHook);304;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createRunHook.js305/**306 * Returns a function which, when invoked, will execute all callbacks307 * registered to a hook of the specified type, optionally returning the final308 * value of the call chain.309 *310 * @param {import('.').Hooks}    hooks                  Hooks instance.311 * @param {import('.').StoreKey} storeKey312 * @param {boolean}              [returnFirstArg=false] Whether each hook callback is expected to313 *                                                      return its first argument.314 *315 * @return {(hookName:string, ...args: unknown[]) => unknown} Function that runs hook callbacks.316 */317function createRunHook(hooks, storeKey) {318  let returnFirstArg = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;319  return function runHooks(hookName) {320    const hooksStore = hooks[storeKey];321    if (!hooksStore[hookName]) {322      hooksStore[hookName] = {323        handlers: [],324        runs: 0325      };326    }327    hooksStore[hookName].runs++;328    const handlers = hooksStore[hookName].handlers; // The following code is stripped from production builds.329    if (false) {}330    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {331      args[_key - 1] = arguments[_key];332    }333    if (!handlers || !handlers.length) {334      return returnFirstArg ? args[0] : undefined;335    }336    const hookInfo = {337      name: hookName,338      currentIndex: 0339    };340    hooksStore.__current.push(hookInfo);341    while (hookInfo.currentIndex < handlers.length) {342      const handler = handlers[hookInfo.currentIndex];343      const result = handler.callback.apply(null, args);344      if (returnFirstArg) {345        args[0] = result;346      }347      hookInfo.currentIndex++;348    }349    hooksStore.__current.pop();350    if (returnFirstArg) {351      return args[0];352    }353  };354}355/* harmony default export */ var build_module_createRunHook = (createRunHook);356;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createCurrentHook.js357/**358 * Returns a function which, when invoked, will return the name of the359 * currently running hook, or `null` if no hook of the given type is currently360 * running.361 *362 * @param {import('.').Hooks}    hooks    Hooks instance.363 * @param {import('.').StoreKey} storeKey364 *365 * @return {() => string | null} Function that returns the current hook name or null.366 */367function createCurrentHook(hooks, storeKey) {368  return function currentHook() {369    var _hooksStore$__current, _hooksStore$__current2;370    const hooksStore = hooks[storeKey];371    return (_hooksStore$__current = (_hooksStore$__current2 = hooksStore.__current[hooksStore.__current.length - 1]) === null || _hooksStore$__current2 === void 0 ? void 0 : _hooksStore$__current2.name) !== null && _hooksStore$__current !== void 0 ? _hooksStore$__current : null;372  };373}374/* harmony default export */ var build_module_createCurrentHook = (createCurrentHook);375;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createDoingHook.js376/**377 * @callback DoingHook378 * Returns whether a hook is currently being executed.379 *380 * @param {string} [hookName] The name of the hook to check for.  If381 *                            omitted, will check for any hook being executed.382 *383 * @return {boolean} Whether the hook is being executed.384 */385/**386 * Returns a function which, when invoked, will return whether a hook is387 * currently being executed.388 *389 * @param {import('.').Hooks}    hooks    Hooks instance.390 * @param {import('.').StoreKey} storeKey391 *392 * @return {DoingHook} Function that returns whether a hook is currently393 *                     being executed.394 */395function createDoingHook(hooks, storeKey) {396  return function doingHook(hookName) {397    const hooksStore = hooks[storeKey]; // If the hookName was not passed, check for any current hook.398    if ('undefined' === typeof hookName) {399      return 'undefined' !== typeof hooksStore.__current[0];400    } // Return the __current hook.401    return hooksStore.__current[0] ? hookName === hooksStore.__current[0].name : false;402  };403}404/* harmony default export */ var build_module_createDoingHook = (createDoingHook);405;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createDidHook.js406/**407 * Internal dependencies408 */409/**410 * @callback DidHook411 *412 * Returns the number of times an action has been fired.413 *414 * @param {string} hookName The hook name to check.415 *416 * @return {number | undefined} The number of times the hook has run.417 */418/**419 * Returns a function which, when invoked, will return the number of times a420 * hook has been called.421 *422 * @param {import('.').Hooks}    hooks    Hooks instance.423 * @param {import('.').StoreKey} storeKey424 *425 * @return {DidHook} Function that returns a hook's call count.426 */427function createDidHook(hooks, storeKey) {428  return function didHook(hookName) {429    const hooksStore = hooks[storeKey];430    if (!build_module_validateHookName(hookName)) {431      return;432    }433    return hooksStore[hookName] && hooksStore[hookName].runs ? hooksStore[hookName].runs : 0;434  };435}436/* harmony default export */ var build_module_createDidHook = (createDidHook);437;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/createHooks.js438/**439 * Internal dependencies440 */441/**442 * Internal class for constructing hooks. Use `createHooks()` function443 *444 * Note, it is necessary to expose this class to make its type public.445 *446 * @private447 */448class _Hooks {449  constructor() {450    /** @type {import('.').Store} actions */451    this.actions = Object.create(null);452    this.actions.__current = [];453    /** @type {import('.').Store} filters */454    this.filters = Object.create(null);455    this.filters.__current = [];456    this.addAction = build_module_createAddHook(this, 'actions');457    this.addFilter = build_module_createAddHook(this, 'filters');458    this.removeAction = build_module_createRemoveHook(this, 'actions');459    this.removeFilter = build_module_createRemoveHook(this, 'filters');460    this.hasAction = build_module_createHasHook(this, 'actions');461    this.hasFilter = build_module_createHasHook(this, 'filters');462    this.removeAllActions = build_module_createRemoveHook(this, 'actions', true);463    this.removeAllFilters = build_module_createRemoveHook(this, 'filters', true);464    this.doAction = build_module_createRunHook(this, 'actions');465    this.applyFilters = build_module_createRunHook(this, 'filters', true);466    this.currentAction = build_module_createCurrentHook(this, 'actions');467    this.currentFilter = build_module_createCurrentHook(this, 'filters');468    this.doingAction = build_module_createDoingHook(this, 'actions');469    this.doingFilter = build_module_createDoingHook(this, 'filters');470    this.didAction = build_module_createDidHook(this, 'actions');471    this.didFilter = build_module_createDidHook(this, 'filters');472  }473}474/** @typedef {_Hooks} Hooks */475/**476 * Returns an instance of the hooks object.477 *478 * @return {Hooks} A Hooks instance.479 */480function createHooks() {481  return new _Hooks();482}483/* harmony default export */ var build_module_createHooks = (createHooks);484;// CONCATENATED MODULE: ./node_modules/@wordpress/hooks/build-module/index.js485/**486 * Internal dependencies487 */488/** @typedef {(...args: any[])=>any} Callback */489/**490 * @typedef Handler491 * @property {Callback} callback  The callback492 * @property {string}   namespace The namespace493 * @property {number}   priority  The namespace494 */495/**496 * @typedef Hook497 * @property {Handler[]} handlers Array of handlers498 * @property {number}    runs     Run counter499 */500/**501 * @typedef Current502 * @property {string} name         Hook name503 * @property {number} currentIndex The index504 */505/**506 * @typedef {Record<string, Hook> & {__current: Current[]}} Store507 */508/**509 * @typedef {'actions' | 'filters'} StoreKey510 */511/**512 * @typedef {import('./createHooks').Hooks} Hooks513 */514const defaultHooks = build_module_createHooks();515const {516  addAction,517  addFilter,518  removeAction,519  removeFilter,520  hasAction,521  hasFilter,522  removeAllActions,523  removeAllFilters,524  doAction,525  applyFilters,526  currentAction,527  currentFilter,528  doingAction,529  doingFilter,530  didAction,531  didFilter,532  actions,533  filters534} = defaultHooks;535(window.wp = window.wp || {}).hooks = __webpack_exports__;536/******/ })()...PluginHooks.spec.js
Source:PluginHooks.spec.js  
1describe('PluginHooks', function () {2  var id = 'testContainer';3  beforeEach(function () {4    this.$container = $('<div id="' + id + '"></div>').appendTo('body');5  });6  afterEach(function () {7    if (this.$container) {8      destroy();9      this.$container.remove();10    }11  });12  describe('unit tests', function() {13    it('should create global empty bucket on construct', function () {14      var hooks = new Handsontable.utils.Hooks();15      expect(hooks.globalBucket).toBeDefined();16      expect(hooks.globalBucket.afterInit).toEqual([]);17      expect(hooks.globalBucket.beforeInit).toEqual([]);18      expect(hooks.globalBucket.init).toEqual([]);19    });20    it('should create empty object (bucket) on createEmptyBucket call', function () {21      var hooks = new Handsontable.utils.Hooks();22      var bucket = hooks.createEmptyBucket();23      expect(bucket.afterInit).toEqual([]);24      expect(bucket.beforeInit).toEqual([]);25      expect(bucket.init).toEqual([]);26      expect(bucket).not.toBe(hooks.createEmptyBucket());27    });28    it('should create and get local bucket when context is passed', function () {29      var hooks = new Handsontable.utils.Hooks();30      var context = {};31      var bucket = hooks.getBucket(context);32      expect(context.pluginHookBucket).toBeDefined();33      expect(context.pluginHookBucket).toBe(bucket);34    });35    it('should get global bucket when context is empty', function () {36      var hooks = new Handsontable.utils.Hooks();37      var bucket = hooks.getBucket();38      expect(bucket).toBe(hooks.globalBucket);39    });40    it('should add hooks as array', function () {41      var hooks = new Handsontable.utils.Hooks();42      var fn1 = function () {};43      var fn2 = function () {};44      var fn3 = function () {};45      var context = {};46      var bucket = {};47      spyOn(hooks, 'getBucket').and.returnValue(bucket);48      spyOn(hooks, 'register');49      hooks.add('test', [fn1, fn2, fn3, fn3, fn3], context);50      expect(hooks.getBucket.calls.count()).toBe(5);51      expect(hooks.getBucket.calls.mostRecent()).toEqual({object: hooks, args: [{}], returnValue: bucket});52      expect(hooks.register.calls.count()).toBe(1);53      expect(hooks.register.calls.mostRecent()).toEqual({object: hooks, args: ['test'], returnValue: void 0});54      expect(bucket.test.length).toBe(3);55      expect(bucket.test[0]).toBe(fn1);56      expect(bucket.test[1]).toBe(fn2);57      expect(bucket.test[2]).toBe(fn3);58    });59    it('should add hook as function', function () {60      var hooks = new Handsontable.utils.Hooks();61      var fn1 = function () {};62      var fn2 = function () {};63      var context = {};64      var bucket = {test: []};65      spyOn(hooks, 'getBucket').and.returnValue(bucket);66      spyOn(hooks, 'register');67      hooks.add('test', fn1, context);68      hooks.add('test', fn1);69      hooks.add('test', fn2, context);70      expect(hooks.getBucket.calls.count()).toBe(3);71      expect(hooks.getBucket.calls.argsFor(0)[0]).toBe(context);72      expect(hooks.getBucket.calls.argsFor(1)[0]).toBe(null);73      expect(hooks.getBucket.calls.argsFor(2)[0]).toBe(context);74      expect(hooks.register).not.toHaveBeenCalled();75      expect(bucket.test.length).toBe(2);76      expect(bucket.test[0]).toBe(fn1);77      expect(bucket.test[1]).toBe(fn2);78    });79    it('should add hook once as array', function () {80      var hooks = new Handsontable.utils.Hooks();81      var fn1 = function () {};82      var fn2 = function () {};83      var fn3 = function () {};84      var context = {};85      var bucket = {};86      spyOn(hooks, 'add');87      hooks.once('test', [fn1, fn2, fn3, fn3, fn3], context);88      expect(fn1.runOnce).toBe(true);89      expect(fn2.runOnce).toBe(true);90      expect(fn3.runOnce).toBe(true);91      expect(hooks.add.calls.count()).toBe(5);92      expect(hooks.add.calls.mostRecent()).toEqual({object: hooks, args: ['test', fn3, context], returnValue: void 0});93    });94    it('should add hook once as function', function () {95      var hooks = new Handsontable.utils.Hooks();96      var fn1 = function () {};97      var fn2 = function () {};98      var context = {};99      var bucket = {};100      spyOn(hooks, 'add');101      hooks.once('test', fn1, context);102      hooks.once('test', fn2);103      expect(fn1.runOnce).toBe(true);104      expect(fn2.runOnce).toBe(true);105      expect(hooks.add.calls.count()).toBe(2);106      expect(hooks.add.calls.argsFor(0)[0]).toBe('test')107      expect(hooks.add.calls.argsFor(0)[1]).toBe(fn1);108      expect(hooks.add.calls.argsFor(0)[2]).toBe(context);109      expect(hooks.add.calls.argsFor(1)[0]).toBe('test')110      expect(hooks.add.calls.argsFor(1)[1]).toBe(fn2);111      expect(hooks.add.calls.argsFor(1)[2]).toBe(null);112    });113    it('should remove hook', function () {114      var hooks = new Handsontable.utils.Hooks();115      var fn1 = function () {};116      var fn2 = function () {};117      var fn3 = function () {};118      var context = {};119      var bucket = {test: [fn1, fn2]};120      var result;121      spyOn(hooks, 'getBucket').and.returnValue(bucket);122      result = hooks.remove('test2', fn1);123      expect(result).toBe(false);124      expect(bucket.test.length).toBe(2);125      result = hooks.remove('test', fn3);126      expect(result).toBe(false);127      expect(bucket.test.length).toBe(2);128      result = hooks.remove('test', fn1);129      expect(result).toBe(true);130      expect(bucket.test[0].skip).toBe(true);131      expect(bucket.test.length).toBe(2);132    });133    it('should run hook', function () {134      var hooks = new Handsontable.utils.Hooks();135      var fn1 = jasmine.createSpy('fn1').and.returnValue('Foo');136      var fn2 = jasmine.createSpy('fn2').and.returnValue('Bar');137      var fn3 = jasmine.createSpy('fn3');138      var context = {};139      var bucket = {test: [fn1, fn2]};140      var result;141      hooks.globalBucket.test = [fn3];142      spyOn(hooks, 'getBucket').and.returnValue(bucket);143      spyOn(hooks, 'remove');144      result = hooks.run(context, 'test');145      expect(result).toBe('Bar');146      expect(hooks.getBucket).toHaveBeenCalledWith(context);147      expect(hooks.remove).not.toHaveBeenCalled();148      expect(fn1).toHaveBeenCalled();149      expect(fn2).toHaveBeenCalled();150      expect(fn3).toHaveBeenCalled();151      fn1.calls.reset();152      fn1.runOnce = true;153      fn2.calls.reset();154      fn3.calls.reset();155      result = hooks.run(context, 'test', 1, 2, 'AB');156      expect(result).toBe('Bar');157      expect(hooks.remove).toHaveBeenCalledWith('test', fn1, context);158      expect(fn1).toHaveBeenCalledWith(1, 2, 'AB', void 0, void 0, void 0);159      expect(fn2).toHaveBeenCalledWith('Foo', 2, 'AB', void 0, void 0, void 0);160      expect(fn3).toHaveBeenCalledWith(1, 2, 'AB', void 0, void 0, void 0);161    });162    it('should run hooks added as once', function () {163      var hooks = new Handsontable.utils.Hooks();164      var fn1 = jasmine.createSpy('fn1').and.returnValue('Foo');165      var fn2 = jasmine.createSpy('fn2').and.returnValue('Bar');166      var fn3 = jasmine.createSpy('fn3');167      var context = {pluginHookBucket: {test: [fn1, fn2]}};168      var result;169      fn1.runOnce = true;170      fn2.runOnce = true;171      fn3.runOnce = true;172      hooks.globalBucket = {test: [fn3]}173      hooks.run(context, 'test');174      hooks.run(context, 'test');175      hooks.run(context, 'test');176      expect(fn1.calls.count()).toBe(1);177      expect(fn2.calls.count()).toBe(1);178      expect(fn3.calls.count()).toBe(1);179    });180    it('should destroy hooks', function () {181      var hooks = new Handsontable.utils.Hooks();182      var fn1 = jasmine.createSpy('fn1').and.returnValue('Foo');183      var fn2 = jasmine.createSpy('fn2').and.returnValue('Bar');184      var fn3 = jasmine.createSpy('fn3');185      var context = {};186      var bucket = {test: [fn1, fn2, fn3], test2: [fn3]};187      spyOn(hooks, 'getBucket').and.returnValue(bucket);188      hooks.destroy(context);189      expect(hooks.getBucket).toHaveBeenCalledWith(context);190      expect(bucket.test.length).toBe(0);191      expect(bucket.test2.length).toBe(0);192    });193    it('should register hook', function () {194      var hooks = new Handsontable.utils.Hooks();195      spyOn(hooks, 'isRegistered').and.returnValue(false);196      hooks.register('test');197      expect(hooks.isRegistered).toHaveBeenCalledWith('test');198      expect(hooks.getRegistered().indexOf('test')).toBeGreaterThan(-1);199      hooks.isRegistered.and.returnValue(true);200      hooks.register('test2');201      expect(hooks.isRegistered).toHaveBeenCalledWith('test2');202      expect(hooks.getRegistered().indexOf('test2')).toBe(-1);203    });204    it('should deregister hook', function () {205      var hooks = new Handsontable.utils.Hooks();206      spyOn(hooks, 'isRegistered').and.returnValue(false);207      hooks.register('test');208      hooks.deregister('test');209      expect(hooks.isRegistered).toHaveBeenCalledWith('test');210      expect(hooks.getRegistered().indexOf('test')).toBeGreaterThan(-1);211      hooks.isRegistered.and.returnValue(true);212      hooks.deregister('test2');213      expect(hooks.isRegistered).toHaveBeenCalledWith('test2');214      expect(hooks.getRegistered().indexOf('test2')).toBe(-1);215    });216    it('should returns `true` if hooks is registered', function () {217      var hooks = new Handsontable.utils.Hooks();218      hooks.register('test');219      expect(hooks.isRegistered('test')).toBe(true);220      expect(hooks.isRegistered('test2')).toBe(false);221    });222    it('should returns array of registered hooks', function () {223      var hooks = new Handsontable.utils.Hooks();224      expect(hooks.getRegistered().length).toBeGreaterThan(0);225    });226    it('should returns `true` if at least one listener was added to the hook', function () {227      var hooks = new Handsontable.utils.Hooks();228      var context = {};229      expect(hooks.has('beforeInit', context)).toBe(false);230      hooks.add('beforeInit', function() {}, context);231      expect(hooks.has('beforeInit', context)).toBe(true);232    });233  });234  it('should add a many local hooks at init (as array)', function () {235    var handler1 = jasmine.createSpy('handler1');236    var handler2 = jasmine.createSpy('handler2');237    var handler3 = jasmine.createSpy('handler3');238    handsontable({239      afterInit: [handler1, handler2, handler3]240    });241    expect(handler1).toHaveBeenCalled();242    expect(handler2).toHaveBeenCalled();243    expect(handler3).toHaveBeenCalled();244  });245  it('should remove a global hook', function () {246    var247      test = 0,248      hook = function () {249        test = 5;250      };251    Handsontable.hooks.add('afterInit', hook);252    Handsontable.hooks.remove('afterInit', hook);253    handsontable();254    expect(test).toEqual(0);255  });256  it('should remove a local hook', function () {257    var258      test = 0,259      hook = function () {260        test = 5;261      };262    handsontable();263    getInstance().addHook('afterInit', hook);264    getInstance().removeHook('afterInit', hook);265    expect(test).toEqual(0);266  });267  it('should run global hook', function () {268    var test = 0;269    Handsontable.hooks.add('afterInit', function () {270      test = 5;271    });272    handsontable();273    expect(test).toEqual(5);274  });275  it('should run local hook', function () {276    var test = 0;277    handsontable();278    getInstance().addHook('myHook', function () {279      test += 5;280    });281    getInstance().runHooks('myHook');282    getInstance().runHooks('myHook');283    expect(test).toEqual(10);284  });285  it('should run local hook once', function () {286    var test = 0;287    handsontable();288    getInstance().addHookOnce('myHook', function () {289      test += 5;290    });291    getInstance().runHooks('myHook');292    getInstance().runHooks('myHook');293    expect(test).toEqual(5);294  });295  it('should run all hooks', function () {296    var test = 0;297    Handsontable.hooks.add('afterInit', function () {298      test += 5;299    });300    handsontable({301      afterInit: function () {302        test += 5;303      }304    });305    expect(test).toEqual(10);306  });307  it('list of all avaliable plugin hooks should be exposed as a public method', function () {308    var hooks = Handsontable.hooks.getRegistered(); //this is used in demo/callbacks.html309    expect(hooks.indexOf('beforeInit')).toBeGreaterThan(-1);310  });311  it('should add a local hook with addHooks method', function(){312    var hot1 = handsontable();313    var test = 0;314    hot1.addHook('myHook', function(){315      test += 5;316    });317    hot1.runHooks('myHook');318    expect(test).toEqual(5);319  });320  it('should remove a local hook with removeHook method', function(){321    var hot1 = handsontable();322    var test = 0;323    var handler = function(){324      test += 5;325    };326    hot1.addHook('myHook', handler);327    hot1.runHooks('myHook');328    hot1.runHooks('myHook');329    expect(test).toEqual(10);330    hot1.removeHook('myHook', handler);331    hot1.runHooks('myHook');332    expect(test).toEqual(10);333  });334  it('should add a local hook with addHookOnce method and run it just once', function(){335    var hot1 = handsontable();336    var test = 0;337    var handler = function(){338      test += 5;339    };340    hot1.addHookOnce('myHook', handler);341    hot1.runHooks('myHook');342    hot1.runHooks('myHook');343    expect(test).toEqual(5);344  });345  it('should run hook with runHooks and return value', function(){346    var hot = handsontable();347    var handler = function(){348      return 5;349    };350    hot.addHook('myHook', handler);351    expect(hot.runHooks('myHook')).toEqual(5);352  });353  it('should run two "once" hooks in desired order', function(){354    var hot = handsontable();355    var arr = [];356    hot.addHookOnce('myHook', function(){357      arr.push(1);358    });359    hot.addHookOnce('myHook', function(){360      arr.push(2);361    });362    hot.runHooks('myHook');363    expect(arr).toEqual([1,2]);364  });365  it('should execute two "once" hooks in desired order', function(){366    var hot = handsontable();367    var str = 'a';368    hot.addHookOnce('myHook', function(str){369      return str + 'b';370    });371    hot.addHookOnce('myHook', function(str){372      return str + 'c';373    });374    expect(hot.runHooks('myHook', str)).toEqual('abc');375  });376  it('adding same hook twice should register it only once (without an error)', function () {377    var i = 0;378    var fn = function(){379      i++;380    };381    var hot = handsontable({382      afterOnCellMouseOver: fn383    });384    hot.getInstance().updateSettings({afterOnCellMouseOver: fn});385    hot.runHooks('afterOnCellMouseOver');386    expect(i).toEqual(1);387  });388  describe("controlling handler queue execution", function () {389    it("should execute all handlers if none of them hasn't skipped", function () {390      var handler1 = jasmine.createSpy('handler1');391      var handler2 = jasmine.createSpy('handler2');392      var handler3 = jasmine.createSpy('handler3');393      var hot = handsontable();394      hot.addHook('fakeEvent', handler1);395      hot.addHook('fakeEvent', handler2);396      hot.addHook('fakeEvent', handler3);397      expect(handler1).not.toHaveBeenCalled();398      expect(handler2).not.toHaveBeenCalled();399      expect(handler3).not.toHaveBeenCalled();400      hot.runHooks('fakeEvent');401      expect(handler1).toHaveBeenCalled();402      expect(handler2).toHaveBeenCalled();403      expect(handler3).toHaveBeenCalled();404    });405  });...examples.test.js
Source:examples.test.js  
1var assert = require('assert');2var Kareem = require('../');3/* Much like [hooks](https://npmjs.org/package/hooks), kareem lets you define4 * pre and post hooks: pre hooks are called before a given function executes.5 * Unlike hooks, kareem stores hooks and other internal state in a separate6 * object, rather than relying on inheritance. Furthermore, kareem exposes7 * an `execPre()` function that allows you to execute your pre hooks when8 * appropriate, giving you more fine-grained control over your function hooks.9 */10describe('pre hooks', function() {11  var hooks;12  beforeEach(function() {13    hooks = new Kareem();14  });15  it('runs without any hooks specified', function(done) {16    hooks.execPre('cook', null, function() {17      // ...18      // acquit:ignore:start19      done();20      // acquit:ignore:end21    });22  });23  /* pre hook functions take one parameter, a "done" function that you execute24   * when your pre hook is finished.25   */26  it('runs basic serial pre hooks', function(done) {27    var count = 0;28    hooks.pre('cook', function(done) {29      ++count;30      done();31    });32    hooks.execPre('cook', null, function() {33      assert.equal(1, count);34      // acquit:ignore:start35      done();36      // acquit:ignore:end37    });38  });39  it('can run multipe pre hooks', function(done) {40    var count1 = 0;41    var count2 = 0;42    hooks.pre('cook', function(done) {43      ++count1;44      done();45    });46    hooks.pre('cook', function(done) {47      ++count2;48      done();49    });50    hooks.execPre('cook', null, function() {51      assert.equal(1, count1);52      assert.equal(1, count2);53      // acquit:ignore:start54      done();55      // acquit:ignore:end56    });57  });58  /* If your pre hook function takes no parameters, its assumed to be59   * fully synchronous.60   */61  it('can run fully synchronous pre hooks', function(done) {62    var count1 = 0;63    var count2 = 0;64    hooks.pre('cook', function() {65      ++count1;66    });67    hooks.pre('cook', function() {68      ++count2;69    });70    hooks.execPre('cook', null, function(error) {71      assert.equal(null, error);72      assert.equal(1, count1);73      assert.equal(1, count2);74      // acquit:ignore:start75      done();76      // acquit:ignore:end77    });78  });79  /* Pre save hook functions are bound to the second parameter to `execPre()`80   */81  it('properly attaches context to pre hooks', function(done) {82    hooks.pre('cook', function(done) {83      this.bacon = 3;84      done();85    });86    hooks.pre('cook', function(done) {87      this.eggs = 4;88      done();89    });90    var obj = { bacon: 0, eggs: 0 };91    // In the pre hooks, `this` will refer to `obj`92    hooks.execPre('cook', obj, function(error) {93      assert.equal(null, error);94      assert.equal(3, obj.bacon);95      assert.equal(4, obj.eggs);96      // acquit:ignore:start97      done();98      // acquit:ignore:end99    });100  });101  /* Like the hooks module, you can declare "async" pre hooks - these take two102   * parameters, the functions `next()` and `done()`. `next()` passes control to103   * the next pre hook, but the underlying function won't be called until all104   * async pre hooks have called `done()`.105   */106  it('can execute parallel (async) pre hooks', function(done) {107    hooks.pre('cook', true, function(next, done) {108      this.bacon = 3;109      next();110      setTimeout(function() {111        done();112      }, 5);113    });114    hooks.pre('cook', true, function(next, done) {115      next();116      var _this = this;117      setTimeout(function() {118        _this.eggs = 4;119        done();120      }, 10);121    });122    hooks.pre('cook', function(next) {123      this.waffles = false;124      next();125    });126    var obj = { bacon: 0, eggs: 0 };127    hooks.execPre('cook', obj, function() {128      assert.equal(3, obj.bacon);129      assert.equal(4, obj.eggs);130      assert.equal(false, obj.waffles);131      // acquit:ignore:start132      done();133      // acquit:ignore:end134    });135  });136  /* You can also return a promise from your pre hooks instead of calling137   * `next()`. When the returned promise resolves, kareem will kick off the138   * next middleware.139   */140  it('supports returning a promise', function(done) {141    hooks.pre('cook', function() {142      return new Promise(resolve => {143        setTimeout(() => {144          this.bacon = 3;145          resolve();146        }, 100);147      });148    });149    var obj = { bacon: 0 };150    hooks.execPre('cook', obj, function() {151      assert.equal(3, obj.bacon);152      // acquit:ignore:start153      done();154      // acquit:ignore:end155    });156  });157});158describe('post hooks', function() {159  var hooks;160  beforeEach(function() {161    hooks = new Kareem();162  });163  it('runs without any hooks specified', function(done) {164    hooks.execPost('cook', null, [1], function(error, eggs) {165      assert.ifError(error);166      assert.equal(1, eggs);167      done();168    });169  });170  it('executes with parameters passed in', function(done) {171    hooks.post('cook', function(eggs, bacon, callback) {172      assert.equal(1, eggs);173      assert.equal(2, bacon);174      callback();175    });176    hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {177      assert.ifError(error);178      assert.equal(1, eggs);179      assert.equal(2, bacon);180      // acquit:ignore:start181      done();182      // acquit:ignore:end183    });184  });185  it('can use synchronous post hooks', function(done) {186    var execed = {};187    hooks.post('cook', function(eggs, bacon) {188      execed.first = true;189      assert.equal(1, eggs);190      assert.equal(2, bacon);191    });192    hooks.post('cook', function(eggs, bacon, callback) {193      execed.second = true;194      assert.equal(1, eggs);195      assert.equal(2, bacon);196      callback();197    });198    hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {199      assert.ifError(error);200      assert.equal(2, Object.keys(execed).length);201      assert.ok(execed.first);202      assert.ok(execed.second);203      assert.equal(1, eggs);204      assert.equal(2, bacon);205      // acquit:ignore:start206      done();207      // acquit:ignore:end208    });209  });210  /* You can also return a promise from your post hooks instead of calling211   * `next()`. When the returned promise resolves, kareem will kick off the212   * next middleware.213   */214  it('supports returning a promise', function(done) {215    hooks.post('cook', function(bacon) {216      return new Promise(resolve => {217        setTimeout(() => {218          this.bacon = 3;219          resolve();220        }, 100);221      });222    });223    var obj = { bacon: 0 };224    hooks.execPost('cook', obj, obj, function() {225      assert.equal(obj.bacon, 3);226      // acquit:ignore:start227      done();228      // acquit:ignore:end229    });230  });231});232describe('wrap()', function() {233  var hooks;234  beforeEach(function() {235    hooks = new Kareem();236  });237  it('wraps pre and post calls into one call', function(done) {238    hooks.pre('cook', true, function(next, done) {239      this.bacon = 3;240      next();241      setTimeout(function() {242        done();243      }, 5);244    });245    hooks.pre('cook', true, function(next, done) {246      next();247      var _this = this;248      setTimeout(function() {249        _this.eggs = 4;250        done();251      }, 10);252    });253    hooks.pre('cook', function(next) {254      this.waffles = false;255      next();256    });257    hooks.post('cook', function(obj) {258      obj.tofu = 'no';259    });260    var obj = { bacon: 0, eggs: 0 };261    var args = [obj];262    args.push(function(error, result) {263      assert.ifError(error);264      assert.equal(null, error);265      assert.equal(3, obj.bacon);266      assert.equal(4, obj.eggs);267      assert.equal(false, obj.waffles);268      assert.equal('no', obj.tofu);269      assert.equal(obj, result);270      // acquit:ignore:start271      done();272      // acquit:ignore:end273    });274    hooks.wrap(275      'cook',276      function(o, callback) {277        assert.equal(3, obj.bacon);278        assert.equal(4, obj.eggs);279        assert.equal(false, obj.waffles);280        assert.equal(undefined, obj.tofu);281        callback(null, o);282      },283      obj,284      args);285  });286});287describe('createWrapper()', function() {288  var hooks;289  beforeEach(function() {290    hooks = new Kareem();291  });292  it('wraps wrap() into a callable function', function(done) {293    hooks.pre('cook', true, function(next, done) {294      this.bacon = 3;295      next();296      setTimeout(function() {297        done();298      }, 5);299    });300    hooks.pre('cook', true, function(next, done) {301      next();302      var _this = this;303      setTimeout(function() {304        _this.eggs = 4;305        done();306      }, 10);307    });308    hooks.pre('cook', function(next) {309      this.waffles = false;310      next();311    });312    hooks.post('cook', function(obj) {313      obj.tofu = 'no';314    });315    var obj = { bacon: 0, eggs: 0 };316    var cook = hooks.createWrapper(317      'cook',318      function(o, callback) {319        assert.equal(3, obj.bacon);320        assert.equal(4, obj.eggs);321        assert.equal(false, obj.waffles);322        assert.equal(undefined, obj.tofu);323        callback(null, o);324      },325      obj);326    cook(obj, function(error, result) {327      assert.ifError(error);328      assert.equal(3, obj.bacon);329      assert.equal(4, obj.eggs);330      assert.equal(false, obj.waffles);331      assert.equal('no', obj.tofu);332      assert.equal(obj, result);333      // acquit:ignore:start334      done();335      // acquit:ignore:end336    });337  });338});339describe('clone()', function() {340  it('clones a Kareem object', function() {341    var k1 = new Kareem();342    k1.pre('cook', function() {});343    k1.post('cook', function() {});344    var k2 = k1.clone();345    assert.deepEqual(Array.from(k2._pres.keys()), ['cook']);346    assert.deepEqual(Array.from(k2._posts.keys()), ['cook']);347  });348});349describe('merge()', function() {350  it('pulls hooks from another Kareem object', function() {351    var k1 = new Kareem();352    var test1 = function() {};353    k1.pre('cook', test1);354    k1.post('cook', function() {});355    var k2 = new Kareem();356    var test2 = function() {};357    k2.pre('cook', test2);358    var k3 = k2.merge(k1);359    assert.equal(k3._pres.get('cook').length, 2);360    assert.equal(k3._pres.get('cook')[0].fn, test2);361    assert.equal(k3._pres.get('cook')[1].fn, test1);362    assert.equal(k3._posts.get('cook').length, 1);363  });...hookBuilder.ts
Source:hookBuilder.ts  
1/** @module transition */ /** for typedoc */2import {IInjectable, extend, tail, assertPredicate, unnestR, flatten, identity} from "../common/common";3import {isArray} from "../common/predicates";4import {TransitionOptions, TransitionHookOptions, IHookRegistry, TreeChanges, IEventHook, ITransitionService, IMatchingNodes} from "./interface";5import {Transition, TransitionHook} from "./module";6import {State} from "../state/module";7import {Node} from "../path/module";8/**9 * This class returns applicable TransitionHooks for a specific Transition instance.10 *11 * Hooks (IEventHook) may be registered globally, e.g., $transitions.onEnter(...), or locally, e.g.12 * myTransition.onEnter(...).  The HookBuilder finds matching IEventHooks (where the match criteria is13 * determined by the type of hook)14 *15 * The HookBuilder also converts IEventHooks objects to TransitionHook objects, which are used to run a Transition.16 *17 * The HookBuilder constructor is given the $transitions service and a Transition instance.  Thus, a HookBuilder18 * instance may only be used for one specific Transition object. (side note: the _treeChanges accessor is private19 * in the Transition class, so we must also provide the Transition's _treeChanges)20 *21 */22export class HookBuilder {23  treeChanges: TreeChanges;24  transitionOptions: TransitionOptions;25  toState: State;26  fromState: State;27  constructor(private $transitions: ITransitionService, private transition: Transition, private baseHookOptions: TransitionHookOptions) {28    this.treeChanges        = transition.treeChanges();29    this.toState            = tail(this.treeChanges.to).state;30    this.fromState          = tail(this.treeChanges.from).state;31    this.transitionOptions  = transition.options();32  }33  // TODO: These get* methods are returning different cardinalities of hooks34  // onBefore/onStart/onFinish/onSuccess/onError returns an array of hooks35  // onExit/onRetain/onEnter returns an array of arrays of hooks36  getOnBeforeHooks  = () => this._buildNodeHooks("onBefore",  "to",       tupleSort(), undefined, { async: false });37  getOnStartHooks   = () => this._buildNodeHooks("onStart",   "to",       tupleSort());38  getOnExitHooks    = () => this._buildNodeHooks("onExit",    "exiting",  tupleSort(true), (node) => ({ $state$: node.state }));39  getOnRetainHooks  = () => this._buildNodeHooks("onRetain",  "retained", tupleSort(), (node) => ({ $state$: node.state }));40  getOnEnterHooks   = () => this._buildNodeHooks("onEnter",   "entering", tupleSort(), (node) => ({ $state$: node.state }));41  getOnFinishHooks  = () => this._buildNodeHooks("onFinish",  "to",       tupleSort(), (node) => ({ $treeChanges$: this.treeChanges }));42  getOnSuccessHooks = () => this._buildNodeHooks("onSuccess", "to",       tupleSort(), undefined, {async: false, rejectIfSuperseded: false});43  getOnErrorHooks   = () => this._buildNodeHooks("onError",   "to",     tupleSort(), undefined, {async: false, rejectIfSuperseded: false});44  asyncHooks() {45    let onStartHooks    = this.getOnStartHooks();46    let onExitHooks     = this.getOnExitHooks();47    let onRetainHooks   = this.getOnRetainHooks();48    let onEnterHooks    = this.getOnEnterHooks();49    let onFinishHooks   = this.getOnFinishHooks();50    let asyncHooks = [onStartHooks, onExitHooks, onRetainHooks, onEnterHooks, onFinishHooks];51    return asyncHooks.reduce(unnestR, []).filter(identity);52  }53  /**54   * Returns an array of newly built TransitionHook objects.55   *56   * - Finds all IEventHooks registered for the given `hookType` which matched the transition's [[TreeChanges]].57   * - Finds [[Node]] (or `Node[]`) to use as the TransitionHook context(s)58   * - For each of the [[Node]]s, creates a TransitionHook59   *60   * @param hookType the name of the hook registration function, e.g., 'onEnter', 'onFinish'.61   * @param matchingNodesProp selects which [[Node]]s from the [[IMatchingNodes]] object to create hooks for.62   * @param getLocals a function which accepts a [[Node]] and returns additional locals to provide to the hook as injectables63   * @param sortHooksFn a function which compares two HookTuple and returns <1, 0, or >164   * @param options any specific Transition Hook Options65   */66  private _buildNodeHooks(hookType: string,67                          matchingNodesProp: string,68                          sortHooksFn: (l: HookTuple, r: HookTuple) => number,69                          getLocals: (node: Node) => any = (node) => ({}),70                          options: TransitionHookOptions = {}): TransitionHook[] {71    // Find all the matching registered hooks for a given hook type72    let matchingHooks = this._matchingHooks(hookType, this.treeChanges);73    if (!matchingHooks) return [];74     const makeTransitionHooks = (hook: IEventHook) => {75      // Fetch the Nodes that caused this hook to match.76      let matches: IMatchingNodes = hook.matches(this.treeChanges);77      // Select the Node[] that will be used as TransitionHook context objects78      let nodes: Node[] = matches[matchingNodesProp];79      // Return an array of HookTuples80      return nodes.map(node => {81        let _options = extend({ traceData: { hookType, context: node} }, this.baseHookOptions, options);82        let transitionHook = new TransitionHook(hook.callback, getLocals(node), node.resolveContext, _options);83        return <HookTuple> { hook, node, transitionHook };84      });85    };86    return matchingHooks.map(makeTransitionHooks)87        .reduce(unnestR, [])88        .sort(sortHooksFn)89        .map(tuple => tuple.transitionHook);90  }91  /**92   * Finds all IEventHooks from:93   * - The Transition object instance hook registry94   * - The TransitionService ($transitions) global hook registry95   *96   * which matched:97   * - the eventType98   * - the matchCriteria (to, from, exiting, retained, entering)99   *100   * @returns an array of matched [[IEventHook]]s101   */102  private _matchingHooks(hookName: string, treeChanges: TreeChanges): IEventHook[] {103    return [ this.transition, this.$transitions ]                             // Instance and Global hook registries104        .map((reg: IHookRegistry) => reg.getHooks(hookName))                  // Get named hooks from registries105        .filter(assertPredicate(isArray, `broken event named: ${hookName}`))  // Sanity check106        .reduce(unnestR, [])                                                  // Un-nest IEventHook[][] to IEventHook[] array107        .filter(hook => hook.matches(treeChanges));                           // Only those satisfying matchCriteria108  }109}110interface HookTuple { hook: IEventHook, node: Node, transitionHook: TransitionHook }111/**112 * A factory for a sort function for HookTuples.113 *114 * The sort function first compares the Node depth (how deep in the state tree a node is), then compares115 * the EventHook priority.116 *117 * @param reverseDepthSort a boolean, when true, reverses the sort order for the node depth118 * @returns a tuple sort function119 */120function tupleSort(reverseDepthSort = false) {121  return function nodeDepthThenPriority(l: HookTuple, r: HookTuple): number {122    let factor = reverseDepthSort ? -1 : 1;123    let depthDelta = (l.node.state.path.length - r.node.state.path.length) * factor;124    return depthDelta !== 0 ? depthDelta : r.hook.priority - l.hook.priority;125  }...Using AI Code Generation
1import { withRootDecorator } from 'storybook-root-decorator';2import { withInfo } from '@storybook/addon-info';3import { withA11y } from '@storybook/addon-a11y';4import { withKnobs } from '@storybook/addon-knobs';5import { withNotes } from '@storybook/addon-notes';6];7### `rootDecorator` (optional)8import { configure, addDecorator } from '@storybook/react';9import { withRootDecorator } from 'storybook-root-decorator';10import { ThemeProvider } from 'styled-components';11import { theme } from '../src/theme';12addDecorator(withRootDecorator);13export const decorators = [withRootDecorator];14export const decorators = [withRootDecorator];15module.exports = {16};17export const decorators = [withRootDecorator];18module.exports = {19};20import { withRootDecorator } from 'storybook-root-decorator';21import { withInfo } from '@storybook/addon-info';22import { withA11y } from '@storybook/addon-a11y';23import { withKnobs } from '@storybook/addon-knobs';24import { withNotes } from '@storybook/addon-notes';25importUsing AI Code Generation
1import { withHooks } from 'storybook-addon-hooks';2import { withKnobs } from '@storybook/addon-knobs';3import { withNotes } from '@storybook/addon-notes';4import { withA11y } from '@storybook/addon-a11y';5import { withInfo } from '@storybook/addon-info';6import { withOptions } from '@storybook/addon-options';7import { withBackgrounds } from '@storybook/addon-backgrounds';8import { withViewport } from '@storybook/addon-viewport';9import { withConsole } from '@storybook/addon-console';10import { withTests } from '@storybook/addon-jest';11import { withLinks } from '@storybook/addon-links';12import { withActions } from '@storybook/addon-actions';13import { withOptions } from '@storybook/addon-options';14import { withInfo } from '@storybook/addon-info';15import { withA11y } from '@storybook/addon-a11y';16import { withNotes } from '@storybook/addon-notes';17import { withKnobs } from '@storybook/addon-knobs';18import { withHooks } from 'storybook-addon-hooks';19addDecorator(withHooks);20addDecorator(withKnobs);21addDecorator(withNotes);22addDecorator(withA11y);23addDecorator(withInfo);24addDecorator(withOptions);25addDecorator(withBackgrounds);26addDecorator(withViewport);27addDecorator((storyFn, context) => withConsole()(storyFn)(context));28addDecorator(withTests);29addDecorator(withLinks);30addDecorator(withActions);31addDecorator(withOptions);32addDecorator(withInfo);33addDecorator(withA11y);34addDecorator(withNotes);35addDecorator(withKnobs);36addDecorator(withHooks);37import withHooks from 'storybook-addon-hooks';38import { withKnobs } from '@storybook/addon-knobs';39import { withNotes } from '@storybook/addon-notes';40import { withA11y } from '@storybook/addon-a11y';41import { withInfo } from '@storybook/addon-info';42import { withOptions } from '@storybook/addon-options';43import { withBackgrounds } from '@storybook/addon-backgrounds';44import { withViewport } from '@storybook/addon-viewport';45import { withConsole } from '@storybook/addon-console';46import {Using AI Code Generation
1import { addDecorator } from '@storybook/react';2import { withRoot } from 'storybook-addon-root';3addDecorator(withRoot);4import { configure, addDecorator } from '@storybook/react';5import { withRoot } from 'storybook-addon-root';6addDecorator(withRoot);7import { addDecorator } from '@storybook/react';8import { withRoot } from 'storybook-addon-root';9addDecorator(withRoot);10import { addDecorator } from '@storybook/react';11import { withRoot } from 'storybook-addon-root';12addDecorator(withRoot);13import { addDecorator } from '@storybook/react';14import { withRoot } from 'storybook-addon-root';15addDecorator(withRoot);16import { configure, addDecorator } from '@storybook/react';17import { withRoot } from 'storybook-addon-root';18addDecorator(withRoot);19### withRoot(options)20MIT © [Karthik Subramanian](Using AI Code Generation
1import React from 'react'2import { useStorybookState } from '@storybook/api'3const Test = () => {4  const state = useStorybookState()5  return <div>{JSON.stringify(state)}</div>6}7MIT © [josephluck](Using AI Code Generation
1import { withRoot } from 'storybook-addon-root';2import { withKnobs } from '@storybook/addon-knobs';3export const decorators = [withKnobs, withRoot];4export const parameters = {5  root: {6  },7};8import { withRoot } from 'storybook-addon-root';9export const decorators = [withRoot];10export const Default = () => <div>default</div>;11export const WithOptions = () => <div>with options</div>;12WithOptions.parameters = {13  root: {14  },15};16export const ObserveOnce = () => <div>observe once</div>;17ObserveOnce.parameters = {18  root: {19  },20};21export const ObserveElement = () =>Using AI Code Generation
1import { withRoot } from 'storybook-addon-root';2import { storiesOf } from '@storybook/react';3import { withKnobs, text } from '@storybook/addon-knobs';4import React from 'react';5import { withInfo } from '@storybook/addon-info';6import { withA11y } from '@storybook/addon-a11y';7import { withOptions } from '@storybook/addon-options';8import { withViewport } from '@storybook/addon-viewport';9import { withConsole } from '@storybook/addon-console';10import { withTests } from '@storybook/addon-jest';11import { withContexts } from '@storybook/addon-contexts/react';12import { withBackgrounds } from '@storybook/addon-backgrounds';13import { withLinks } from '@storybook/addon-links';14import { withNotes } from '@storybook/addon-notes';15import { withPropsTable } from 'storybook-addon-react-docgen';16import { withReadme } from 'storybook-readme/with-readme';17import { withStorysource } from '@storybook/addon-storysource';18import { withViewport } from '@storybook/addon-viewport';19import { withTests } from '@storybook/addon-jest';20import { withContexts } from '@storybook/addon-contexts/react';21import { withBackgrounds } from '@storybook/addon-backgrounds';22import { withLinks } from '@storybook/addon-links';23import { withNotes } from '@storybook/addon-notes';24import { withPropsTable } from 'storybook-addon-react-docgen';25import { withReadme } from 'storybook-readme/with-readme';26import { withStorysource } from '@storybook/addon-storysource';27import { withViewport } from '@storybook/addon-viewport';28import { withTests } from '@storybook/addon-jest';29import { withContexts } from '@storybook/addon-contexts/react';30import { withBackgrounds } from '@storybook/addon-backgrounds';31import { withLinks } from '@storybook/addon-links';32import { withNotes } from '@storybook/addon-notes';33import { withPropsTable } from 'storybook-addon-react-docgen';34import { withReadme } from 'storybook-readme/with-readme';35import { withStorysource } from '@storybook/addon-storysource';36import { withViewport } from '@storybook/addon-viewport';37import { withTests } from '@storybook/addon-jest';38import { withContexts } from '@Using AI Code Generation
1import { addDecorator } from '@storybook/react';2import { withRootDecorator } from './storybook-root-decorator';3addDecorator(withRootDecorator);4import { withRootDecorator } from './storybook-root-decorator';5export const decorators = [withRootDecorator];6import { addDecorator } from '@storybook/react';7import { withRootDecorator } from './storybook-root-decorator';8addDecorator(withRootDecorator);9import { configure, addDecorator } from '@storybook/react';10import { withRootDecorator } from './storybook-root-decorator';11addDecorator(withRootDecorator);12configure(loadStories, module);13import { configure, addDecorator } from '@storybook/react';14import { withRootDecorator } from './storybook-root-decorator';15addDecorator(withRootDecorator);16function loadStories() {17  require('../stories/index.js');18}19configure(loadStories, module);20import { configure, addDecorator } from '@storybook/react';21import { withRootDecorator } from './storybook-root-decorator';22addDecorator(withRootDecorator);23function loadStories() {24  require('../stories/index.js');25}26configure(loadStories, module);Using AI Code Generation
1import { useRoot } from 'storybook-root';2import { useRoot } from 'storybook-root/hooks';3const { useRoot } = require('storybook-root');4const { useRoot } = require('storybook-root/hooks');5import { useRoot } from 'storybook-root/hooks';6const [root, setRoot] = useRoot();7const { useRoot } = require('storybook-root/hooks');8const [root, setRoot] = useRoot();9Contributions are welcome! Please see the [Contributing Guide](Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
