Viewing File: /usr/local/cpanel/base/frontend/jupiter/passenger/test/eventSourceMock.js

/*
 * eventSourceMock.js                                Copyright 2022 cPanel, L.L.C.
 *                                                           All rights reserved.
 * copyright@cpanel.net                                         http://cpanel.net
 * This code is subject to the cPanel license. Unauthorized copying is prohibited
 */

/* global define: false */

define([
    "lodash"
], function(
        _
    ) {
    "use strict";

    var ReadyStateType = {
        created: 0,
        opened: 1,
        closed: 2
    };

    var defaultConfig = {
        withCredentials: false
    };

    var defaultEventSource;

    var sources = {};

    /**
     * Get the EventSourceMock for a given url
     *
     * @private
     * @param  {String} url
     * @return {EventSourceMock}
     */
    function _getSource(url) {
        var source = sources[url];
        if (!source) {
            throw "Attempted to use an EventSource that was not registered: " + url;
        }
        return source;
    }

    /**
     * Fire an event
     *
     * @private
     * @param  {EventSourceMock} source
     * @param  {String}          eventName Name of the event to fire.
     * @param  {EventMock}       event     Mock event object.
     */
    function _fireEvent(source, eventName, event) {
        var listeners = source.events[eventName];
        if (listeners) {
            listeners.forEach(function(listener) {
                if (typeof listener === "function") {
                    listener(event);
                }
            });
        }
    }

    return {
        install: function() {
            if (defaultEventSource) {
                throw "EventSource is already mocked.";
            }

            defaultEventSource = window.EventSource;

            /**
             * Mock EventSource. Mimics the internal behaviors of the EventSource without actually
             * making any network connections or relying on a backend.
             *
             * @example
             *
             *   define([
             *       "passenger/test/eventSourceMock",
             *   ], function(angular, EVENTS) {
             *       "use strict";
             *
             *       describe("", function() {
             *           var url = "some/end/point";
             *
             *           EVENTS.install(url);
             *
             *           var sse = new EventSource(url);
             *           expect(sse.readyState).toBe(0);
             *
             *           spyOn(sse.onopen).and.callThrough();
             *           spyOn(sse.onmessage).and.callThrough();
             *           spyOn(sse.onerror).and.callThrough();
             *
             *           EVENTS.emitOpen(url);
             *           expect(sse.onopen).toHaveBeenCalled();
             *           expect(sse.readyState).toBe(1);
             *
             *           EVENTS.emitMessage(url, "message");
             *           expect(sse.onmessage).toHaveBeenCalledWith("message");
             *
             *           EVENTS.emitError(url, "failed");
             *           expect(sse.onerror).toHaveBeenCalledWith("failed");
             *
             *           sse.close();
             *           expect(sse.readyState).toBe(2);
             *
             *           EVENTS.uninstall(url);
             *       });
             *   });
             *
             * @class EventSourceMock
             * @property {String} url
             * @property {Object} [config]
             * @property {Number} readyState
             * @property {Function} [onopen]
             * @property {Function} [onerror]
             * @property {Function} [onmessage]
             */

            /**
             * Constructor for the EventSourceMock
             *
             * @protected
             * @constructor
             * @param {String} url
             * @param {Object} config configuration thats passed to EventSource
             */
            window.EventSource = function EventSourceMock(url, config) {
                this.url = url;
                this.config = config || defaultConfig;
                this.readyState = ReadyStateType.created;
                this.onopen = null;
                this.onerror = null;
                this.onmessage = null;
                this.events = {};

                /**
                 * Add the event listener for a given event name.
                 *
                 * @class EventSourceMock
                 * @method addEventListener
                 * @param {String}   eventName
                 * @param {Function} listener
                 */
                this.addEventListener = function(eventName, listener) {
                    if (!this.events[eventName]) {
                        this.events[eventName] = [];
                    }
                    this.events[eventName].push(listener);
                };

                /**
                 * Remove the event listener for a given event name.
                 *
                 * @class EventSourceMock
                 * @method removeEventListener
                 * @param {String}   eventName
                 * @param {Function} listener
                 */
                this.removeEventListener = function(eventName, listener) {
                    if (!this.events[eventName]) {
                        throw "Attempted to remove an unregistered event listener: " + eventName;
                    }
                    _.remove(this.events[eventName], listener);
                };

                /**
                 * Close the connect;
                 *
                 * @class EventSourceMock
                 * @method close
                 */
                this.close = function() {
                    this.readyState = ReadyStateType.closed;
                };

                sources[url] = this;
                return this;
            };
        },

        /**
         * Use to trigger the error event for the EventSource
         *
         * @param {String} url   SSE url for the request
         * @param {String} error Error message for the request
         */
        emitError: function(url, error) {
            var source = _getSource(url);
            if (typeof source.onerror === "function") {
                source.onerror(error);
            }
        },

        /**
         * Use to trigger the open event for the EventSource
         *
         * @param  {String} url  SSE url for the request
         */
        emitOpen: function(url) {
            var source = _getSource(url);
            source.readyState = ReadyStateType.opened;
            if (typeof source.onopen === "function") {
                source.onopen();
            }
        },

        /**
         * Used by tests to trigger a message event.
         *
         * @param  {String} url  SSE url for the request
         * @param  {String} eventName Event message name
         * @param  {String} data Event message data
         */
        emitMessage: function(url, eventName, data) {
            var source = _getSource(url);
            var event = {
                type: eventName,
                data: data
            };

            if (typeof source.onmessage === "function") {
                source.onmessage(event);
            }

            _fireEvent(source, eventName, event);
        },

        /**
         * Uninstall the mock EventSource
         */
        uninstall: function() {
            if (!defaultEventSource) {
                throw "EventSource is not mocked.";
            }

            window.EventSource = defaultEventSource;
            defaultEventSource = null;
        },

        /**
         * Get the source so we can spy on methods on it.
         *
         * @param  {String} url
         * @return {EventSourceMock}
         */
        get: function(url) {
            return _getSource(url);
        }
    };
});
Back to Directory File Manager