Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reporting no testrun #3

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,4 @@
/bower_components
/node_modules
npm-debug.log
typings/
runner/*.js
runner/*.d.ts
runner/*.js.map
test/*.js
test/*.d.ts
test/*.js.map
test/unit/*.js
test/unit/*.d.ts
test/unit/*.js.map
test/integration/*.js
test/integration/*.d.ts
test/integration/*.js.map
test/fixtures/integration/temp

browser/*.js
browser/*.js.map
browser/environment/*.js*
browser/mocha/*.js*
browser/reporters/*.js*
19 changes: 18 additions & 1 deletion browser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion browser.js.map

Large diffs are not rendered by default.

175 changes: 175 additions & 0 deletions browser/childrunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/**
* @license
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt The complete set of authors may be found
* at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
* be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
* Google as part of the polymer project is also subject to an additional IP
* rights grant found at http://polymer.github.io/PATENTS.txt
*/
import * as util from './util.js';
/**
* A Mocha suite (or suites) run within a child iframe, but reported as if they
* are part of the current context.
*/
var ChildRunner = /** @class */ (function () {
function ChildRunner(url, parentScope) {
this.eventListenersToRemoveOnClean = [];
this.parentScope = parentScope;
var urlBits = util.parseUrl(url);
util.mergeParams(urlBits.params, util.getParams(parentScope.location.search));
delete urlBits.params.cli_browser_id;
this.url = "" + urlBits.base + util.paramsToQuery(urlBits.params);
this.state = 'initializing';
}
/**
* Listeners added using this method will be removed on done()
*
* @param type event type
* @param listener object which receives a notification
* @param target event target
*/
ChildRunner.prototype.addEventListener = function (type, listener, target) {
target.addEventListener(type, listener);
var descriptor = { target: target, type: type, listener: listener };
this.eventListenersToRemoveOnClean.push(descriptor);
};
/**
* Removes all event listeners added by a method addEventListener defined
* on an instance of ChildRunner.
*/
ChildRunner.prototype.removeAllEventListeners = function () {
this.eventListenersToRemoveOnClean.forEach(function (_a) {
var target = _a.target, type = _a.type, listener = _a.listener;
return target.removeEventListener(type, listener);
});
};
/**
* @return {ChildRunner} The `ChildRunner` that was registered for this
* window.
*/
ChildRunner.current = function () {
return ChildRunner.get(window);
};
/**
* @param {!Window} target A window to find the ChildRunner of.
* @param {boolean} traversal Whether this is a traversal from a child window.
* @return {ChildRunner} The `ChildRunner` that was registered for `target`.
*/
ChildRunner.get = function (target, traversal) {
var childRunner = ChildRunner.byUrl[target.location.href];
if (childRunner) {
return childRunner;
}
if (window.parent === window) {
// Top window.
if (traversal) {
console.warn('Subsuite loaded but was never registered. This most likely is due to wonky history behavior. Reloading...');
window.location.reload();
}
return null;
}
// Otherwise, traverse.
return window.parent.WCT._ChildRunner.get(target, true);
};
/**
* Loads and runs the subsuite.
*
* @param {function} done Node-style callback.
*/
ChildRunner.prototype.run = function (done) {
var _this = this;
util.debug('ChildRunner#run', this.url);
this.state = 'loading';
this.onRunComplete = done;
this.container = document.getElementById('subsuites');
if (!this.container) {
var container_1 = (this.container = document.createElement('div'));
container_1.id = 'subsuites';
document.body.appendChild(container_1);
}
var container = this.container;
var iframe = (this.iframe = document.createElement('iframe'));
iframe.classList.add('subsuite');
iframe.src = this.url;
// Let the iframe expand the URL for us.
var url = (this.url = iframe.src);
container.appendChild(iframe);
ChildRunner.byUrl[url] = this;
this.timeoutId = setTimeout(function () { return _this.loaded(new Error('Timed out loading ' + url)); }, ChildRunner.loadTimeout);
this.addEventListener('error', function () { return _this.loaded(new Error('Failed to load document ' + _this.url)); }, iframe);
this.addEventListener('DOMContentLoaded', function () { return _this.loaded(); }, iframe.contentWindow);
};
/**
* Called when the sub suite's iframe has loaded (or errored during load).
*
* @param {*} error The error that occured, if any.
*/
ChildRunner.prototype.loaded = function (error) {
util.debug('ChildRunner#loaded', this.url, error);
if (this.iframe.contentWindow == null && error) {
this.signalRunComplete(error);
this.done();
return;
}
// Not all targets have WCT loaded (compatiblity mode)
if (this.iframe.contentWindow.WCT) {
this.share = this.iframe.contentWindow.WCT.share;
}
if (error) {
this.signalRunComplete(error);
this.done();
}
};
/**
* Called in mocha/run.js when all dependencies have loaded, and the child is
* ready to start running tests
*
* @param {*} error The error that occured, if any.
*/
ChildRunner.prototype.ready = function (error) {
util.debug('ChildRunner#ready', this.url, error);
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
if (error) {
this.signalRunComplete(error);
this.done();
}
};
/**
* Called when the sub suite's tests are complete, so that it can clean up.
*/
ChildRunner.prototype.done = function () {
var _this = this;
util.debug('ChildRunner#done', this.url, arguments);
// Make sure to clear that timeout.
this.ready();
this.signalRunComplete();
if (this.iframe) {
// Be safe and avoid potential browser crashes when logic attempts to
// interact with the removed iframe.
setTimeout(function () {
_this.removeAllEventListeners();
_this.container.removeChild(_this.iframe);
_this.iframe = undefined;
_this.share = null;
}, 0);
}
};
ChildRunner.prototype.signalRunComplete = function (error) {
if (this.onRunComplete) {
this.state = 'complete';
this.onRunComplete(error);
this.onRunComplete = null;
}
};
// ChildRunners get a pretty generous load timeout by default.
ChildRunner.loadTimeout = 60000;
// We can't maintain properties on iframe elements in Firefox/Safari/???, so
// we track childRunners by URL.
ChildRunner.byUrl = {};
return ChildRunner;
}());
export default ChildRunner;
139 changes: 139 additions & 0 deletions browser/clisocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* @license
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at
* http://polymer.github.io/LICENSE.txt The complete set of authors may be found
* at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
* be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
* Google as part of the polymer project is also subject to an additional IP
* rights grant found at http://polymer.github.io/PATENTS.txt
*/
import ChildRunner from './childrunner.js';
import * as util from './util.js';
var SOCKETIO_ENDPOINT = window.location.protocol + '//' + window.location.host;
var SOCKETIO_LIBRARY = SOCKETIO_ENDPOINT + '/socket.io/socket.io.js';
/**
* A socket for communication between the CLI and browser runners.
*
* @param {string} browserId An ID generated by the CLI runner.
* @param {!io.Socket} socket The socket.io `Socket` to communicate over.
*/
var CLISocket = /** @class */ (function () {
function CLISocket(browserId, socket) {
this.browserId = browserId;
this.socket = socket;
}
/**
* @param {!Mocha.Runner} runner The Mocha `Runner` to observe, reporting
* interesting events back to the CLI runner.
*/
CLISocket.prototype.observe = function (runner) {
var _this = this;
this.emitEvent('browser-start', {
url: window.location.toString(),
});
// We only emit a subset of events that we care about, and follow a more
// general event format that is hopefully applicable to test runners beyond
// mocha.
//
// For all possible mocha events, see:
// https://github.com/visionmedia/mocha/blob/master/lib/runner.js#L36
runner.on('test', function (test) {
_this.emitEvent('test-start', { test: getTitles(test) });
});
runner.on('test end', function (test) {
_this.emitEvent('test-end', {
state: getState(test),
test: getTitles(test),
duration: test.duration,
error: test.err,
});
});
runner.on('fail', function (test, err) {
// fail the test run if we catch errors outside of a test function
if (test.type !== 'test') {
_this.emitEvent('browser-fail', 'Error thrown outside of test function: ' + err.stack);
}
});
runner.on('childRunner start', function (childRunner) {
_this.emitEvent('sub-suite-start', childRunner.share);
});
runner.on('childRunner end', function (childRunner) {
_this.emitEvent('sub-suite-end', childRunner.share);
});
runner.on('end', function () {
_this.emitEvent('browser-end');
});
};
/**
* @param {string} event The name of the event to fire.
* @param {*} data Additional data to pass with the event.
*/
CLISocket.prototype.emitEvent = function (event, data) {
this.socket.emit('client-event', {
browserId: this.browserId,
event: event,
data: data,
});
};
/**
* Builds a `CLISocket` if we are within a CLI-run environment; short-circuits
* otherwise.
*
* @param {function(*, CLISocket)} done Node-style callback.
*/
CLISocket.init = function (done) {
var browserId = util.getParam('cli_browser_id');
if (!browserId)
return done();
// Only fire up the socket for root runners.
if (ChildRunner.current())
return done();
util.loadScript(SOCKETIO_LIBRARY, function (error) {
if (error)
return done(error);
var socket = io(SOCKETIO_ENDPOINT);
socket.on('error', function (error) {
socket.off();
done(error);
});
socket.on('connect', function () {
socket.off();
done(null, new CLISocket(browserId, socket));
});
});
};
return CLISocket;
}());
export default CLISocket;
// Misc Utility
/**
* @param {!Mocha.Runnable} runnable The test or suite to extract titles from.
* @return {!Array.<string>} The titles of the runnable and its parents.
*/
function getTitles(runnable) {
var titles = [];
while (runnable && !runnable.root && runnable.title) {
titles.unshift(runnable.title);
runnable = runnable.parent;
}
return titles;
}
/**
* @param {!Mocha.Runnable} runnable
* @return {string}
*/
function getState(runnable) {
if (runnable.state === 'passed') {
return 'passing';
}
else if (runnable.state === 'failed') {
return 'failing';
}
else if (runnable.pending) {
return 'pending';
}
else {
return 'unknown';
}
}
Loading