summaryrefslogtreecommitdiff
path: root/addons/web/static/test/testing.js
diff options
context:
space:
mode:
authorXavier Morel <xmo@openerp.com>2012-11-16 08:17:12 +0100
committerXavier Morel <xmo@openerp.com>2012-11-16 08:17:12 +0100
commita9645151b6f070d23d2f35810aee562c1354aba9 (patch)
tree04a4265b454d75291001a49ee4285b1faab63f92 /addons/web/static/test/testing.js
parent8e85f4e0bd0b1fbbf401686b85d7282f8991454d (diff)
[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
Diffstat (limited to 'addons/web/static/test/testing.js')
-rw-r--r--addons/web/static/test/testing.js253
1 files changed, 253 insertions, 0 deletions
diff --git a/addons/web/static/test/testing.js b/addons/web/static/test/testing.js
new file mode 100644
index 00000000000..919143ab533
--- /dev/null
+++ b/addons/web/static/test/testing.js
@@ -0,0 +1,253 @@
+openerp.testing.section('testing.stack', function (test) {
+ // I heard you like tests, so I put tests in your testing infrastructure,
+ // so you can test what you test
+ var reject = function () {
+ // utility function, rejects a success
+ var args = _.toArray(arguments);
+ return $.Deferred(function (d) {
+ d.reject.apply(d, ["unexpected success"].concat(args));
+ });
+ };
+ test('direct, value, success', {asserts: 1}, function () {
+ var s = openerp.testing.Stack();
+ return s.execute(function () {
+ return 42;
+ }).then(function (val) {
+ strictEqual(val, 42, "should return the handler value");
+ });
+ });
+ test('direct, deferred, success', {asserts: 1}, function () {
+ var s = openerp.testing.Stack();
+ return s.execute(function () {
+ return $.when(42);
+ }).then(function (val) {
+ strictEqual(val, 42, "should return the handler value")
+ });
+ });
+ test('direct, value, error', {asserts: 1}, function () {
+ var s = openerp.testing.Stack();
+ return s.execute(function () {
+ throw new Error("foo");
+ }).pipe(reject, function (f) {
+ strictEqual(f.message, "foo", "should reject with exception");
+ return $.when();
+ });
+ });
+ test('direct, deferred, failure', {asserts: 1}, function () {
+ var s = openerp.testing.Stack();
+ return s.execute(function () {
+ return $.Deferred(function (d) {
+ d.reject("failed");
+ });
+ }).pipe(reject, function (f) {
+ strictEqual(f, "failed", "should propagate failure");
+ return $.when();
+ });
+ });
+
+ test('successful setup', {asserts: 2}, function () {
+ var setup_done = false;
+ var s = openerp.testing.Stack();
+ return s.push(function () {
+ return $.Deferred(function (d) {
+ setTimeout(function () {
+ setup_done = true;
+ d.resolve(2);
+ }, 50);
+ });
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ ok(setup_done, "should have executed setup");
+ strictEqual(val, 42, "should return executed function value (not setup)");
+ });
+ });
+ test('successful teardown', {asserts: 2}, function () {
+ var teardown = false;
+ var s = openerp.testing.Stack();
+ return s.push(null, function () {
+ return $.Deferred(function (d) {
+ setTimeout(function () {
+ teardown = true;
+ d.resolve(2);
+ }, 50);
+ });
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ ok(teardown, "should have executed teardown");
+ strictEqual(val, 42, "should return executed function value (not setup)");
+ });
+ });
+ test('successful setup and teardown', {asserts: 3}, function () {
+ var setup = false, teardown = false;
+ var s = openerp.testing.Stack();
+ return s.push(function () {
+ return $.Deferred(function (d) {
+ setTimeout(function () {
+ setup = true;
+ d.resolve(2);
+ }, 50);
+ });
+ }, function () {
+ return $.Deferred(function (d) {
+ setTimeout(function () {
+ teardown = true;
+ d.resolve(2);
+ }, 50);
+ });
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ ok(setup, "should have executed setup");
+ ok(teardown, "should have executed teardown");
+ strictEqual(val, 42, "should return executed function value (not setup)");
+ });
+ });
+
+ test('multiple setups', {asserts: 2}, function () {
+ var setups = 0;
+ var s = openerp.testing.Stack();
+ return s.push(function () {
+ setups++;
+ }).push(function () {
+ setups++;
+ }).push(function () {
+ setups++;
+ }).push(function () {
+ setups++;
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ strictEqual(setups, 4, "should have executed all setups of stack");
+ strictEqual(val, 42);
+ });
+ });
+ test('multiple teardowns', {asserts: 2}, function () {
+ var teardowns = 0;
+ var s = openerp.testing.Stack();
+ return s.push(null, function () {
+ teardowns++;
+ }).push(null, function () {
+ teardowns++;
+ }).push(null, function () {
+ teardowns++;
+ }).push(null, function () {
+ teardowns++;
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ strictEqual(teardowns, 4, "should have executed all teardowns of stack");
+ strictEqual(val, 42);
+ });
+ });
+ test('holes in setups', {asserts: 2}, function () {
+ var setups = [];
+ var s = openerp.testing.Stack();
+ return s.push(function () {
+ setups.push(0);
+ }).push().push().push(function () {
+ setups.push(3);
+ }).push(function () {
+ setups.push(4);
+ }).push().push(function () {
+ setups.push(6);
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ deepEqual(setups, [0, 3, 4, 6],
+ "should have executed setups in correct order");
+ strictEqual(val, 42);
+ });
+ });
+ test('holes in teardowns', {asserts: 2}, function () {
+ var teardowns = [];
+ var s = openerp.testing.Stack();
+ return s.push(null, function () {
+ teardowns.push(0);
+ }).push().push().push(null, function () {
+ teardowns.push(3);
+ }).push(null, function () {
+ teardowns.push(4);
+ }).push().push(null, function () {
+ teardowns.push(6);
+ }).execute(function () {
+ return 42;
+ }).then(function (val) {
+ deepEqual(teardowns, [6, 4, 3, 0],
+ "should have executed teardowns in correct order");
+ strictEqual(val, 42);
+ });
+
+ });
+
+ test('failed setup', {asserts: 5}, function () {
+ var setup, teardown, teardown2, code;
+ return openerp.testing.Stack().push(function () {
+ setup = true;
+ }, function () {
+ teardown = true;
+ }).push(function () {
+ return $.Deferred().reject("Fail!");
+ }, function () {
+ teardown2 = true;
+ }).execute(function () {
+ code = true;
+ return 42;
+ }).pipe(reject, function (m) {
+ ok(setup, "should have executed first setup function");
+ ok(teardown, "should have executed first teardown function");
+ ok(!teardown2, "should not have executed second teardown function");
+ strictEqual(m, "Fail!", "should return setup failure message");
+ ok(!code, "should not have executed callback");
+ return $.when();
+ });
+ });
+ test('failed teardown', {asserts: 2}, function () {
+ var teardowns = 0;
+ return openerp.testing.Stack().push(null, function () {
+ teardowns++;
+ return $.Deferred().reject('Fail 1');
+ }).push(null, function () {
+ teardowns++;
+ }).push(null, function () {
+ teardowns++;
+ return $.Deferred().reject('Fail 3');
+ }).execute(function () {
+ return 42;
+ }).pipe(reject, function (m) {
+ strictEqual(teardowns, 3,
+ "should have tried executing all teardowns");
+ strictEqual(m, "Fail 3", "should return first failure message");
+ return $.when();
+ });
+ });
+ test('failed call + teardown', {asserts: 2}, function () {
+ var teardowns = 0;
+ return openerp.testing.Stack().push(null, function () {
+ teardowns++;
+ }).push(null, function () {
+ teardowns++;
+ return $.Deferred().reject('Fail 2');
+ }).execute(function () {
+ return $.Deferred().reject("code");
+ }).pipe(reject, function (m) {
+ strictEqual(teardowns, 2,
+ "should have tried executing all teardowns");
+ strictEqual(m, "code", "should return first failure message");
+ return $.when();
+ });
+ });
+
+ test('arguments passing', {asserts: 9}, function () {
+ var asserter = function (a, b, c) {
+ strictEqual(a, 1);
+ strictEqual(b, "foo");
+ deepEqual(c, {bar: "baz", qux: 42});
+ };
+
+ return openerp.testing.Stack()
+ .push(asserter, asserter)
+ .execute(asserter, 1, "foo", {bar: 'baz', qux: 42});
+ });
+});