Home Reference Source Test Repository

tests/PluginManager.test.js

import Moment from 'moment';
import chai, { expect } from 'chai';
import PluginManager from './../src/PluginManager';

chai.use(require('dirty-chai'));

describe('PluginManager', () => {
  let manager;
  let npm;

  const options = {
    context: 'test-context',
    debug: true,
  };

  beforeEach(() => {
    function onError() { }
    function setInitialisedAt() { }
    function setDefaultMaxHandlers() { }
    function cleanUp(event) { event.context._events = {}; }

    manager = new PluginManager(options);
    npm = {
      generateConfig: (mgr) => {
        mgr._events = {
          error: [onError],
          postInit: [setDefaultMaxHandlers, setInitialisedAt],
          exit: [cleanUp],
        };

        return mgr;
      },
    };
  });

  it('gets created successfully', () => {
    expect(manager instanceof PluginManager).to.equal(true);
    expect(manager.context).to.equal(options.context);
    expect(manager.debug).to.equal(options.debug);
  });

  it('has logger', () => {
    expect(typeof manager.log._debug === 'boolean').to.equal(true);
  });

  describe('init', () => {
    it('gets initialised successfully', async () => {
      const result = await manager.init({}, npm);

      expect(result).to.deep.equal(manager);
      expect(typeof result._events.error[0]).to.equal('function');
      expect(typeof result._events.postInit[0]).to.equal('function');
      expect(typeof result._events.postInit[1]).to.equal('function');
    }).timeout(10000);

    it('with local event handlers', async () => {
      const onGenerateConfig = (event) => {
        event.context.createdAt = new Moment();
      };

      const plugin = {
        provides: {
          generateConfig: onGenerateConfig,
        },
      };

      const result = await manager.init(plugin, npm);

      expect(result).to.deep.equal(manager);
      expect(typeof result._events.generateConfig[0]).to.equal('function');
      expect(typeof result._events.error[0]).to.equal('function');
      expect(typeof result._events.postInit[0]).to.equal('function');
      expect(typeof result._events.postInit[1]).to.equal('function');
      expect(typeof result._events.exit[0]).to.equal('function');
    });

    it('removes handler on exit', async () => {
      const result = await manager.init({}, npm);

      await manager.dispatch('exit', manager);

      expect(result).to.deep.equal(manager);
      expect(Object.keys(result._events).length).to.equal(0);
    });

    it('local event handler overrides external', async () => {
      const setDefaultMaxHandlers = (event) => {
        const mgr = event.context;

        if (mgr) {
          mgr.setMaxHandlers(10);
        }
      };

      const plugin = {
        provides: {
          postInit: setDefaultMaxHandlers,
        },
      };

      await manager.init(plugin, npm);

      const handlers = manager.handlers('postInit')
        .filter((handler) =>
          handler.name === 'setDefaultMaxHandlers');

      expect(handlers.length).to.equal(1);
      expect(manager._defaultMaxHandlers).to.equal(10);
    });

    it('local event handler adds to external', async () => {
      const setDefaultMaxHandlers = (event) => {
        const mgr = event.context;

        if (mgr) {
          mgr.setMaxHandlers(20);
        }
      };

      manager._override = false;

      const plugin = {
        provides: {
          postInit: setDefaultMaxHandlers,
        },
      };

      await manager.init(plugin, npm);

      const handlers = manager.handlers('postInit')
        .filter((handler) =>
          handler.name === 'setDefaultMaxHandlers');

      expect(handlers.length).to.equal(2);
      expect(manager._defaultMaxHandlers).to.equal(20);
    });
  });

  describe('hasHandlers', () => {
    it('returns true if it has at least one handler for an event', async () => {
      await manager.init({}, npm);

      expect(manager.hasHandlers('postInit')).to.equal(true);
    });

    it('returns false if it does not have any handlers for an event', async () => {
      await manager.init({}, npm);

      expect(manager.hasHandlers('preInit')).to.equal(false);
    });

    it('throw error if hasHandlers() not passed an event name', async () => {
      await manager.init({}, npm);

      try {
        manager.hasHandlers();
      } catch (error) {
        expect(error.message).to.equal('Undefined event name');
      }
    });
  });

  describe('dispatch', () => {
    it('throws error if event name is not provided', async () => {
      try {
        await manager.init({}, npm);

        await manager.dispatch();
      } catch (error) {
        expect(error.message).to.equal('Event name not provided');
      }
    });

    it('dispatch event without context object should work', async () => {
      const config = { debug: true, start: 0 };

      const getConfig = (event) => {
        event.context.config = config;
      };

      const plugin = {
        provides: {
          preExec: getConfig,
        },
      };

      await manager.init(plugin, npm);

      const result = await manager.dispatch('preExec');

      expect(result.config).to.deep.equal(config);
    });
  });

  describe('addHandler', () => {
    it('accepts a new function handler for event', () => {
      const handler = (event) => {
        const context = event.context;

        context.data = 'data';
      };

      let handlers = manager.handlers('getData');

      expect(handlers.length).to.equal(0);

      const man = manager.addHandler('getData', handler);

      handlers = man.handlers('getData');

      expect(handlers.length).to.equal(1);
    });

    it('throws error when too many handlers are added for event', () => {
      try {
        const handler = (event) => {
          const context = event.context;

          context.data = 'data';
        };

        manager._defaultMaxHandlers = 1;

        manager.addHandler('getData', handler);
        manager.addHandler('getData', handler);
      } catch (error) {
        expect(error.message).to.equal('Exceeded maximum number of handlers for \'getData\' event');
      }
    });
  });

  describe('removeAllHandlers', () => {
    it('removes all handlers for an event', async () => {
      await manager.init({}, npm);

      expect(manager.handlers('postInit').length).to.equal(2);

      manager.removeAllHandlers('postInit');

      expect(manager.handlers('postInit').length).to.equal(0);
    });
  });

  describe('_getCallback', () => {
    it('loads plugin functions', async () => {
      const plugin = 'plugged-in-extras-plugin';
      const handlerName = 'cleanUp';

      const handler = await manager._getCallback(plugin, handlerName);

      expect(typeof handler).to.equal('function');
      expect(handler.name).to.equal(handlerName);
    });
  });
});