2012-10-25 15:47:45 +00:00
|
|
|
// Test support structures and methods for OpenERP
|
|
|
|
openerp.testing = {};
|
|
|
|
(function (testing) {
|
|
|
|
var dependencies = {
|
2012-11-20 10:17:33 +00:00
|
|
|
pyeval: [],
|
2013-08-06 12:26:23 +00:00
|
|
|
core: ['pyeval'],
|
|
|
|
data: ['core'],
|
2012-10-25 15:47:45 +00:00
|
|
|
dates: [],
|
2013-08-06 12:26:23 +00:00
|
|
|
formats: ['core', 'dates'],
|
|
|
|
chrome: ['core'],
|
|
|
|
views: ['core', 'data', 'chrome'],
|
2012-12-05 16:06:56 +00:00
|
|
|
search: ['views', 'formats'],
|
2012-10-25 15:47:45 +00:00
|
|
|
list: ['views', 'data'],
|
|
|
|
form: ['data', 'views', 'list', 'formats'],
|
|
|
|
list_editable: ['list', 'form', 'data'],
|
|
|
|
};
|
|
|
|
|
2014-01-31 15:26:40 +00:00
|
|
|
var initialized = [];
|
|
|
|
/**
|
|
|
|
* openerp.init is a broken-ass piece of shit, makes it impossible to
|
|
|
|
* progressively add modules, using it, retarded openerp_inited flag
|
|
|
|
* means the first tests being run get their dependencies loaded
|
|
|
|
* (basically just base and web), and for *every other module* the tests
|
|
|
|
* run without the dependencies being correctly loaded
|
|
|
|
*/
|
|
|
|
function init(modules) {
|
|
|
|
if (!initialized.length) {
|
|
|
|
openerp.init(modules);
|
|
|
|
initialized = openerp._modules.slice();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var to_initialize = _.difference(modules, initialized);
|
|
|
|
for (var i = 0; i < to_initialize.length; i++) {
|
|
|
|
var modname = to_initialize[i];
|
|
|
|
var fct = openerp[modname];
|
|
|
|
if (typeof fct === 'function') {
|
|
|
|
var module = openerp[modname] = {};
|
|
|
|
for(var k in fct) {
|
|
|
|
if (!fct.hasOwnProperty(k)) { continue; }
|
|
|
|
module[k] = fct[k];
|
|
|
|
}
|
|
|
|
fct(openerp, module)
|
|
|
|
}
|
|
|
|
initialized.push(modname);
|
|
|
|
openerp._modules.push(modname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-25 15:47:45 +00:00
|
|
|
testing.dependencies = window['oe_all_dependencies'] || [];
|
|
|
|
testing.current_module = null;
|
|
|
|
/**
|
|
|
|
* Function which does not do anything
|
|
|
|
*/
|
|
|
|
testing.noop = function () { };
|
|
|
|
/**
|
|
|
|
* Alter provided instance's ``session`` attribute to make response
|
|
|
|
* mockable:
|
|
|
|
*
|
|
|
|
* * The ``responses`` parameter can be used to provide a map of (RPC)
|
|
|
|
* paths (e.g. ``/web/view/load``) to a function returning a response
|
|
|
|
* to the query.
|
|
|
|
* * ``instance.session`` grows a ``responses`` attribute which is
|
|
|
|
* a map of the same (and is in fact initialized to the ``responses``
|
|
|
|
* parameter if one is provided)
|
|
|
|
*
|
|
|
|
* Note that RPC requests to un-mocked URLs will be rejected with an
|
|
|
|
* error message: only explicitly specified urls will get a response.
|
|
|
|
*
|
|
|
|
* Mocked sessions will *never* perform an actual RPC connection.
|
|
|
|
*
|
|
|
|
* @param instance openerp instance being initialized
|
|
|
|
* @param {Object} [responses]
|
|
|
|
*/
|
|
|
|
testing.mockifyRPC = function (instance, responses) {
|
|
|
|
var session = instance.session;
|
|
|
|
session.responses = responses || {};
|
2013-07-31 16:34:15 +00:00
|
|
|
session.rpc = function(url, rparams, options) {
|
|
|
|
if (_.isString(url)) {
|
|
|
|
url = {url: url};
|
|
|
|
}
|
2012-10-25 15:47:45 +00:00
|
|
|
var fn, params;
|
2013-07-31 16:34:15 +00:00
|
|
|
var needle = rparams.model + ':' + rparams.method;
|
2013-11-14 09:46:24 +00:00
|
|
|
if (url.url.substr(0, 20) === '/web/dataset/call_kw' && needle in this.responses) {
|
2012-10-25 15:47:45 +00:00
|
|
|
fn = this.responses[needle];
|
|
|
|
params = [
|
2013-07-31 16:34:15 +00:00
|
|
|
rparams.args || [],
|
|
|
|
rparams.kwargs || {}
|
2012-10-25 15:47:45 +00:00
|
|
|
];
|
|
|
|
} else {
|
|
|
|
fn = this.responses[url.url];
|
2013-07-31 16:34:15 +00:00
|
|
|
params = [{params: rparams}];
|
2012-10-25 15:47:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!fn) {
|
|
|
|
return $.Deferred().reject({}, 'failed',
|
|
|
|
_.str.sprintf("Url %s not found in mock responses, with arguments %s",
|
2013-07-31 16:34:15 +00:00
|
|
|
url.url, JSON.stringify(rparams))
|
2012-10-25 15:47:45 +00:00
|
|
|
).promise();
|
|
|
|
}
|
|
|
|
try {
|
2012-11-16 10:14:17 +00:00
|
|
|
return $.when(fn.apply(null, params)).then(function (result) {
|
2012-10-25 15:47:45 +00:00
|
|
|
// Wrap for RPC layer unwrapper thingy
|
2013-08-01 16:08:47 +00:00
|
|
|
return result;
|
2012-10-25 15:47:45 +00:00
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
// not sure why this looks like that
|
|
|
|
return $.Deferred().reject({}, 'failed', String(e));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
var StackProto = {
|
|
|
|
execute: function (fn) {
|
|
|
|
var args = [].slice.call(arguments, 1);
|
|
|
|
// Warning: here be dragons
|
|
|
|
var i = 0, setups = this.setups, teardowns = this.teardowns;
|
|
|
|
var d = $.Deferred();
|
|
|
|
|
|
|
|
var succeeded, failed;
|
|
|
|
var success = function () {
|
|
|
|
succeeded = _.toArray(arguments);
|
|
|
|
return teardown();
|
|
|
|
};
|
|
|
|
var failure = function () {
|
|
|
|
// save first failure
|
|
|
|
if (!failed) {
|
|
|
|
failed = _.toArray(arguments);
|
|
|
|
}
|
|
|
|
// chain onto next teardown
|
|
|
|
return teardown();
|
|
|
|
};
|
|
|
|
|
|
|
|
var setup = function () {
|
|
|
|
// if setup to execute
|
|
|
|
if (i < setups.length) {
|
|
|
|
var f = setups[i] || testing.noop;
|
|
|
|
$.when(f.apply(null, args)).then(function () {
|
|
|
|
++i;
|
|
|
|
setup();
|
|
|
|
}, failure);
|
|
|
|
} else {
|
2012-11-16 10:55:54 +00:00
|
|
|
$.when(fn.apply(null, args)).then(success, failure);
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
var teardown = function () {
|
|
|
|
// if teardown to execute
|
|
|
|
if (i > 0) {
|
|
|
|
var f = teardowns[--i] || testing.noop;
|
|
|
|
$.when(f.apply(null, args)).then(teardown, failure);
|
|
|
|
} else {
|
|
|
|
if (failed) {
|
|
|
|
d.reject.apply(d, failed);
|
|
|
|
} else if (succeeded) {
|
|
|
|
d.resolve.apply(d, succeeded);
|
|
|
|
} else {
|
|
|
|
throw new Error("Didn't succeed or fail?");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
setup();
|
|
|
|
|
|
|
|
return d;
|
|
|
|
},
|
|
|
|
push: function (setup, teardown) {
|
|
|
|
return _.extend(Object.create(StackProto), {
|
|
|
|
setups: this.setups.concat([setup]),
|
|
|
|
teardowns: this.teardowns.concat([teardown])
|
|
|
|
});
|
|
|
|
},
|
|
|
|
unshift: function (setup, teardown) {
|
|
|
|
return _.extend(Object.create(StackProto), {
|
|
|
|
setups: [setup].concat(this.setups),
|
|
|
|
teardowns: [teardown].concat(this.teardowns)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Function} [setup]
|
|
|
|
* @param {Function} [teardown]
|
|
|
|
* @return {*}
|
|
|
|
*/
|
|
|
|
testing.Stack = function (setup, teardown) {
|
|
|
|
return _.extend(Object.create(StackProto), {
|
|
|
|
setups: setup ? [setup] : [],
|
|
|
|
teardowns: teardown ? [teardown] : []
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2012-10-26 08:45:43 +00:00
|
|
|
testing.section = function (name, options, body) {
|
|
|
|
if (_.isFunction(options)) {
|
|
|
|
body = options;
|
|
|
|
options = {};
|
2012-10-25 15:47:45 +00:00
|
|
|
}
|
2012-10-26 08:45:43 +00:00
|
|
|
_.defaults(options, {
|
|
|
|
setup: testing.noop,
|
|
|
|
teardown: testing.noop
|
|
|
|
});
|
2012-10-25 15:47:45 +00:00
|
|
|
|
2014-04-28 18:24:51 +00:00
|
|
|
QUnit.module(name, {_oe: options});
|
2013-07-25 10:33:01 +00:00
|
|
|
body(testing['case']);
|
2012-10-25 15:47:45 +00:00
|
|
|
};
|
2013-07-25 10:33:01 +00:00
|
|
|
testing['case'] = function (name, options, callback) {
|
2012-10-25 15:47:45 +00:00
|
|
|
if (_.isFunction(options)) {
|
|
|
|
callback = options;
|
|
|
|
options = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
var module = testing.current_module;
|
|
|
|
var module_index = _.indexOf(testing.dependencies, module);
|
|
|
|
var module_deps = testing.dependencies.slice(
|
|
|
|
// If module not in deps (because only tests, no JS) -> indexOf
|
|
|
|
// returns -1 -> index becomes 0 -> replace with ``undefined`` so
|
|
|
|
// Array#slice returns a full copy
|
|
|
|
0, module_index + 1 || undefined);
|
2012-10-29 11:01:54 +00:00
|
|
|
|
|
|
|
// Serialize options for this precise test case
|
2013-08-01 09:12:39 +00:00
|
|
|
var env = QUnit.config.currentModuleTestEnvironment;
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
// section setup
|
|
|
|
// case setup
|
|
|
|
// test
|
|
|
|
// case teardown
|
|
|
|
// section teardown
|
|
|
|
var case_stack = testing.Stack()
|
|
|
|
.push(env._oe.setup, env._oe.teardown)
|
|
|
|
.push(options.setup, options.teardown);
|
|
|
|
var opts = _.defaults({}, options, env._oe);
|
2012-10-29 11:01:54 +00:00
|
|
|
|
2012-10-26 08:45:43 +00:00
|
|
|
QUnit.test(name, function () {
|
2013-07-26 13:18:05 +00:00
|
|
|
var instance = openerp;
|
2014-01-31 15:26:40 +00:00
|
|
|
init(module_deps);
|
2013-07-26 14:27:07 +00:00
|
|
|
instance.session = new instance.web.Session();
|
|
|
|
instance.session.uid = 42;
|
2012-10-26 08:45:43 +00:00
|
|
|
if (_.isNumber(opts.asserts)) {
|
|
|
|
expect(opts.asserts);
|
2012-10-25 15:47:45 +00:00
|
|
|
}
|
|
|
|
|
2012-10-26 08:45:43 +00:00
|
|
|
var $fixture = $('#qunit-fixture');
|
|
|
|
|
2012-10-25 15:47:45 +00:00
|
|
|
var mock, async = false;
|
2012-10-26 08:45:43 +00:00
|
|
|
switch (opts.rpc) {
|
2012-10-25 15:47:45 +00:00
|
|
|
case 'mock':
|
|
|
|
async = true;
|
|
|
|
testing.mockifyRPC(instance);
|
|
|
|
mock = function (spec, handler) {
|
|
|
|
instance.session.responses[spec] = handler;
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-10-29 11:01:54 +00:00
|
|
|
// Always execute tests asynchronously
|
2012-10-25 15:47:45 +00:00
|
|
|
stop();
|
2012-11-15 09:15:01 +00:00
|
|
|
var timeout;
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
case_stack.execute(function () {
|
2012-11-16 07:29:06 +00:00
|
|
|
var result = callback.apply(null, arguments);
|
2012-10-29 11:01:54 +00:00
|
|
|
if (!(result && _.isFunction(result.then))) {
|
|
|
|
if (async) {
|
|
|
|
ok(false, "asynchronous test cases must return a promise");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!_.isNumber(opts.asserts)) {
|
|
|
|
ok(false, "asynchronous test cases must specify the "
|
|
|
|
+ "number of assertions they expect");
|
|
|
|
}
|
2012-10-25 15:47:45 +00:00
|
|
|
}
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
|
|
|
|
return $.Deferred(function (d) {
|
|
|
|
$.when(result).then(function () {
|
2013-07-25 10:33:01 +00:00
|
|
|
d.resolve.apply(d, arguments);
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
}, function () {
|
|
|
|
d.reject.apply(d, arguments);
|
|
|
|
});
|
|
|
|
if (async || (result && result.then)) {
|
|
|
|
// async test can be either implicit async (rpc) or
|
|
|
|
// promise-returning
|
|
|
|
timeout = setTimeout(function () {
|
|
|
|
QUnit.config.semaphore = 1;
|
|
|
|
d.reject({message: "Test timed out"});
|
|
|
|
}, 2000);
|
|
|
|
}
|
2012-11-15 09:15:01 +00:00
|
|
|
});
|
[IMP] setup & teardown of test runner
simplify code and make setup & teardown processes more reliable
add testing.Stack tools which stacks promise-returning functions
around the actual promise-returning function to execute (the test case
itself).
testing.Stack returns an object with 3 methods, ``push([setup][,
teardown])``, ``unshift([setup][, teardown])`` and ``execute(fn,
*args)``. ``push`` and ``unshift`` create a new stack with the
provided setup and teardown added respectively at the top and bottom
of the stack.
``execute`` will walk the stack from bottom to top executing ``setup``
handlers (and waiting on their result), if all setup handlers execute
without failure the ``fn`` callback gets executed (and waited on) then
*all* ``teardown`` handlers are executed from top to bottom:
| setup
| setup
| setup
| setup
| fn
| teardown
| teardown
| teardown
V teardown
If a ``setup`` handler fails (the promise is rejected), teardowns will
start executing *from the previous level* (so the ``teardown``
matching the failed ``setup`` will *not* be run), but all
``teardowns`` below that will be run regardless, even if one fails the
next one will still be executed.
The stack will either ultimately return a promise rejection using the
*first* rejection it got (a rejection may be cascading, so the
rejection of a setup may also lead to or be linked to a teardown being
rejected later), or will return the resolution from ``fn``.
If ``execute`` is passed further arguments, those arguments will in
turn be forwarded to ``fn`` as well as all ``setup`` and ``teardown``
handlers.
bzr revid: xmo@openerp.com-20121116071712-zuld957icellezum
2012-11-16 07:17:12 +00:00
|
|
|
}, instance, $fixture, mock).always(function () {
|
|
|
|
if (timeout) { clearTimeout(timeout); }
|
2012-10-29 11:01:54 +00:00
|
|
|
start();
|
2012-10-30 08:15:25 +00:00
|
|
|
}).fail(function (error) {
|
|
|
|
if (options.fail_on_rejection === false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var message;
|
|
|
|
if (typeof error !== 'object'
|
|
|
|
|| typeof error.message !== 'string') {
|
|
|
|
message = JSON.stringify([].slice.apply(arguments));
|
|
|
|
} else {
|
|
|
|
message = error.message;
|
|
|
|
if (error.data && error.data.debug) {
|
|
|
|
message += '\n\n' + error.data.debug;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ok(false, message);
|
2012-10-29 11:01:54 +00:00
|
|
|
});
|
2012-10-25 15:47:45 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
})(openerp.testing);
|