VulpesOS/gaia/tests/jsmarionette/runner/marionette-js-runner/lib/ui.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

220 lines
5.4 KiB
JavaScript
Executable file

'use strict';
/**
Custom marionette-runner interface for mocha.
*/
/**
* Module dependencies.
*/
var Suite = require('mocha/lib/suite');
var HostManager = require('./runtime/hostmanager').HostManager;
var RPC = require('./rpc');
var Test = require('mocha/lib/test');
var escapeRe = require('escape-string-regexp');
function MarionetteTest(title, hostManager, fn) {
this.hostManager = hostManager;
Test.call(this, title, fn);
}
MarionetteTest.prototype = {
__proto__: Test.prototype,
run: function(fn) {
return Test.prototype.run.call(this, function(err) {
if (err) {
// In the case of an error we attempt to run host/client specific error
// handles where possible so first we attempt to see if there is a host
// that matches a client...
if (!this.ctx.hosts.length && this.ctx.hosts.length || !err.client) {
return fn(err);
}
var hosts = this.ctx.hosts;
// attempt to find the correct host...
var host;
for (var i = 0; i < hosts.length; i++) {
if (
// In the case of direct match then we found it...
hosts[i].client === err.client ||
// The client's scope method creates prototype chains so if it is in
// the same chain it is also a match...
hosts[i].client.isPrototypeOf(err.client)
) {
host = hosts[i];
host.session.checkError(host.profileConfig, err)
.then(fn)
.catch(fn);
break;
}
}
return;
}
fn();
}.bind(this));
}
};
/**
@param {Object} suite root suite for mocha.
*/
module.exports = function(suite) {
// initialize the RPC bridge...
var rpc = new RPC(process.send.bind(process));
process.on('message', rpc.handle());
var suites = [suite];
var manager = new HostManager();
// setup global hooks
suite.beforeAll('marionette-mocha global init', function() {
this.hosts = [];
this.runner = rpc.client('runner', ['createHost', 'createProfile']);
});
suite.on('pre-require', function(context, file, mocha) {
/**
* Execute before each test case.
*/
context.setup = function(name, fn) {
suites[0].beforeEach(name, fn);
};
/**
* Execute after each test case.
*/
context.teardown = function(name, fn) {
suites[0].afterEach(name, fn);
};
/**
* Execute before the suite.
*/
context.suiteSetup = function(name, fn) {
suites[0].beforeAll(name, fn);
};
/**
* Execute after the suite.
*/
context.suiteTeardown = function(name, fn) {
suites[0].afterAll(name, fn);
};
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.suite = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.file = file;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
};
context.marionette = context.suite;
/**
* global state modifies for marionette
*
* @type {Object}
*/
// Setup global state manager for the marionette runtime.
manager.desiredCapabilities = decode('DESIRED_CAPABILITIES');
manager.verbose = decode('VERBOSE') === '1';
manager.deviceType = decode('DEVICE_TYPE');
context.marionette._manager = manager;
context.marionette.client = manager.createHost.bind(manager);
context.marionette.plugin = manager.addPlugin.bind(manager);
/**
* Pending suite.
*/
context.suite.skip = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.pending = true;
suites.unshift(suite);
fn.call(suite);
suites.shift();
};
/**
* Exclusive test-case.
*/
context.suite.only = function(title, fn) {
var suite = context.suite(title, fn);
mocha.grep(suite.fullTitle());
};
/**
* Describe a specification or test-case
* with the given `title`, `options` list device to run on,
* and callback `fn` acting as a thunk.
*/
context.test = function(title, options, fn) {
// Second argument is optional, put default device if it doesn't exist.
if (typeof options !== 'object') {
if (typeof options === 'function') {
fn = options;
}
// Run only phone tests by default.
options = { devices: ['phone'] };
}
if (options &&
options.devices &&
options.devices.indexOf(manager.deviceType) === -1) {
// Ignore test.
return;
}
var suite = suites[0];
if (suite.pending) fn = null;
var test = new MarionetteTest(title, manager, fn);
test.file = file;
suite.addTest(test);
return test;
};
/**
* Exclusive test-case.
*/
context.test.only = function(title, fn) {
var test = context.test(title, fn);
var reString = '^' + escapeRe(test.fullTitle()) + '$';
mocha.grep(new RegExp(reString));
};
/**
* Pending test case.
*/
context.test.skip = function(title) {
context.test(title);
};
});
};
function decode(name) {
var encoded = process.env[name];
if (!encoded) {
return null;
}
var result;
try {
result = JSON.parse(new Buffer(encoded, 'base64').toString());
} catch (error) {
console.error('Could not parse', name, encoded);
result = null;
}
return result;
}