UNPKG

kab

Version:

Know About Better - test your code

223 lines (187 loc) 4.81 kB
/** * @file 浏览器集合管理 * @author chris<wfsr@foxmail.com> */ /* eslint-disable guard-for-in */ var launcher = require('edp-browser-launcher2'); var Browser = require('./browser'); var log = require('./log'); /** * 存储所有客户端的键值对 * * 以客户端 userAgent 的 hash 值为 key * Browser 实例为 value * * @namespace * @inner */ var map = {}; /** * 自动打开的浏览器子进程对象数组 * * @type {Array} * @inner */ var instances = []; /** * 是否已初始化 * * @type {boolean} * @inner */ var isInited = false; /** * 客户端(浏览器)的集合管理 * * @type {Object} */ var browsers = { /** * 根据配置文件配置的浏览器打开指定网址 * * @param {string} url 要打开的网址 * @param {Function} failCallback 失败后的回调 * @return {void} */ open: function (url, failCallback) { var browsers = this.config.browsers || []; if (!browsers.length) { log.error('未指定浏览器,请在配置文件或使用 --browsers 参数指定。'); return failCallback(1); } launcher(function (err, launch) { var fail = function () { if (err) { log.error(err); return failCallback(err); } }; if (err) { return fail(err); } browsers.forEach(function (browser) { launch(url, {browser: browser.toLowerCase()}, function (err, instance) { if (err) { return fail(err); } instances.push(instance); }); }); }); }, /** * 初始化,只执行一次 * * @param {Object} config 命令行参数与配置文件合并后的配置 * @return {browsers} 当前模块对象 */ init: function (config) { if (!isInited) { this.finished = 0; this.config = config; this.recount = this.recount.bind(this); // kill all browsers on process exit process.on('exit', this.kill.bind(this)); isInited = true; } return this; }, /** * 添加浏览器 * * @param {Browser|Object} browser 待添加的浏览器实例或客户端相关信息 * @return {Browser} 刚添加的浏览器实例对象 */ add: function (browser) { // 忽略同一浏览器的其他窗口 if (map[browser.id]) { return false; } if (!(browser instanceof Browser)) { browser = new Browser(browser); } map[browser.id] = browser; browser.browsers = this; this.update(); return browser; }, /** * 移除浏览器 * * @param {Browser|Object} browser 要移除的浏览器实例或客户端相关信息 * @return {boolean} 移除执行的结果,不存在时返回 false */ remove: function (browser) { var id = browser.id; if (!map[id]) { return false; } map[id].dispose(); delete map[id]; this.update(); return true; }, /** * 重算执行完成的客户端数 * * @param {EventEmitter} emitter 全局的事件对象实例 */ recount: function (emitter) { var total = this.length; this.finished++; if (total === this.finished) { var fails = 0; this.each(function (browser) { fails += browser.fails; browser.idle(); }); emitter.emit('finish', fails > 0 ? 1 : 0); this.finished = 0; } }, /** * 通知所有客户端更新 * */ update: function () { var browsers = []; var id; for (id in map) { browsers.push(map[id].serialize()); } for (id in map) { map[id].update(browsers); } }, /** * 遍历所有客户端实例的快捷方法 * * @param {Function} callback 迭代回调的方法 */ each: function (callback) { for (var id in map) { callback(map[id]); } }, /** * 杀掉所有浏览器进程 */ kill: function () { var instance; while (instance = instances.shift()) { instance.stop(); } } }; /** * 外部获取客户端数量的接口 * * @name browser.length * @type {number} */ Object.defineProperty(browsers, 'length', { get: function () { return Object.keys(map).length; } }); module.exports = browsers;