API Docs for: 0.9.0
Show:

File: lib/plugins/clientDecorator/webDriver.js

// Copyright 2014, Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

var WebDriverManager = require('../../../');
var AbstractClientDecorator = require('preceptor').AbstractClientDecorator;
var Promise = require('promise');
var utils = require('preceptor-core').utils;
var istanbul = require('istanbul');
var minimatch = require('minimatch');
var _ = require('underscore');

/**
 * @class WebDriverClientDecorator
 * @extends AbstractClientDecorator
 *
 * @constructor
 *
 * @property {Driver} _instance
 * @property {WebDriverManager} _webDriverManager
 * @property {WebDriverContainer} _webDriverContainer
 */
var WebDriverClientDecorator = AbstractClientDecorator.extend(

	{
		/**
		 * Initializes the instance
		 *
		 * @method initialize
		 */
		initialize: function () {
			this.getOptions().configuration = utils.deepExtend({}, [
				{
					"isolation": false,
					"client": {},
					"server": {}
				},
				this.getConfiguration()
			]);

			this.__super();

			this._webDriverManager = new WebDriverManager();
		},


		/**
		 * Setup of web-driver
		 *
		 * @method _setup
		 * @return {Promise}
		 * @private
		 */
		_setup: function () {

			var webDriverContainer,
				server,
				client;

			webDriverContainer = this.getWebDriverManager().generate(this.getConfiguration());
			server = webDriverContainer.getServer();
			client = webDriverContainer.getClient();

			this._webDriverContainer = webDriverContainer;

			return server.setup(client.getCapabilities()).then(function () {
				client.setUrl(server.getUrl());
				return client.start();

			}).then(function () {

				var capabilities = client.getCapabilities(),
					id = [];

				if (capabilities.browserName) {
					id.push(capabilities.browserName);
				}
				if (capabilities.version) {
					id.push(capabilities.version);
				}

				global.PRECEPTOR_WEBDRIVER = {
					"driver": client.getInstance(),
					"browserName": capabilities.browserName,
					"browserVersion": capabilities.version,
					"browser": id.join('_'),
					"clientName": client.getType(),
					"serverName": server.getType(),
					"collectCoverage": this.collectCoverage.bind(this)
				};
			}.bind(this));
		},

		/**
		 * Tear-down of web-driver
		 *
		 * @method _tearDown
		 * @return {Promise}
		 * @private
		 */
		_tearDown: function () {
			var webDriverContainer = this._webDriverContainer;

			return this.collectCoverage().then(function () {
				return webDriverContainer.getClient().stop().then(function () {
					return webDriverContainer.getServer().tearDown();
				});

			}).then(function () {
				delete global.PRECEPTOR_WEBDRIVER;
			});
		},

		/**
		 * Collects the coverage-report when requested
		 *
		 * @returns {Promise}
		 */
		collectCoverage: function () {

			var coverageVar,
				coverageObj;

			// Should remote coverage be retrieved?
			coverageObj = this._webDriverContainer.getCoverage();

			if (coverageObj.isActive()) {

				// Load remote coverage
				coverageVar = coverageObj.getCoverageVar();
				return this._webDriverContainer.getClient().loadCoverage(coverageVar).then(function (coverage) {

					var collector, excludes;

					// Filter coverage
					excludes = coverageObj.getExcludes();
					if (excludes && (excludes.length !== 0)) {
						coverage = this._filterCoverage(coverage, excludes);
					}

					// Mapping
					if (coverageObj.hasMapping()) {
						coverage = this._mapCoverage(coverage, coverageObj.getMapping());
					}

					// Combine local and remote coverage
					collector = new istanbul.Collector();
					collector.add(global.__preceptorCoverage__ || {});
					collector.add(coverage);

					// Set new Preceptor coverage
					global.__preceptorCoverage__ = collector.getFinalCoverage() || {};

				}.bind(this));

			} else {
				return Promise.resolve();
			}
		},

		/**
		 * Filters the coverage report according to excludes
		 *
		 * @param {object} coverage
		 * @param {string[]} excludes
		 * @returns {object}
		 * @private
		 */
		_filterCoverage: function (coverage, excludes) {
			var keys = _.keys(coverage),
				result = {};

			_.each(keys, function (key) {
				var allowed = true;

				_.each(excludes, function (exclude) {
					allowed = allowed && !minimatch(key, exclude);
				});

				if (allowed) {
					result[key] = coverage[key];
				}
			});

			return result;
		},

		/**
		 * Maps coverage paths to a new path
		 *
		 * @param {object} coverage
		 * @param {object[]} mappingList
		 * @returns {object}
		 * @private
		 */
		_mapCoverage: function (coverage, mappingList) {
			var keys = _.keys(coverage),
				result = {};

			_.each(keys, function (key) {
				var path = key;

				// Update paths
				_.each(mappingList, function (mapping) {
					path = path.replace(new RegExp(mapping.from), mapping.to);
				});

				// Copy coverage
				result[key] = coverage[key];

				// Replace path in child
				if (result[key].path) {
					result[key].path = path;
				}
			});

			return result;
		},


		/**
		 * Gets the web-driver manager
		 *
		 * @method getWebDriverManager
		 * @return {WebDriverManager}
		 */
		getWebDriverManager: function () {
			return this._webDriverManager;
		},


		/**
		 * Should tests be run in isolation?
		 *
		 * @method inIsolation
		 * @return {boolean}
		 */
		inIsolation: function () {
			return this.getConfiguration().isolation;
		},


		/**
		 * Processes the begin of the testing environment
		 *
		 * @method processBefore
		 * @return {Promise}
		 */
		processBefore: function () {
			if (!this.inIsolation()) {
				return this._setup();
			} else {
				return Promise.resolve();
			}
		},

		/**
		 * Processes the end of the testing environment
		 *
		 * @method processAfter
		 * @return {Promise}
		 */
		processAfter: function () {
			if (!this.inIsolation()) {
				return this._tearDown();
			} else {
				return Promise.resolve();
			}
		},

		/**
		 * Processes the beginning of a test
		 *
		 * @method processBeforeTest
		 * @return {Promise}
		 */
		processBeforeTest: function () {
			if (this.inIsolation()) {
				return this._setup();
			} else {
				return Promise.resolve();
			}
		},

		/**
		 * Processes the ending of a test
		 *
		 * @method processAfterTest
		 * @return {Promise}
		 */
		processAfterTest: function () {
			if (this.inIsolation()) {
				return this._tearDown();
			} else {
				return Promise.resolve();
			}
		}
	});

module.exports = WebDriverClientDecorator;