gecko/toolkit/devtools/tests/unit/test_async-utils.js

160 lines
3.9 KiB
JavaScript

/* -*- Mode: js; js-indent-level: 2; -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test async-utils.js
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
// |const| will not work because
// it will make the Promise object immutable before assigning.
// Using Object.defineProperty() instead.
Object.defineProperty(this, "Promise", {
value: Cu.import("resource://gre/modules/Promise.jsm", {}).Promise,
writable: false, configurable: false
});
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils");
function run_test() {
do_test_pending();
Task.spawn(function*() {
for (let helper of [async, asyncOnce]) {
yield test_async_args(helper);
yield test_async_return(helper);
yield test_async_throw(helper);
}
yield test_async_once();
yield test_async_invoke();
do_test_finished();
}).then(null, error => {
do_throw(error);
});
}
// Test that arguments are correctly passed through to the async function.
function test_async_args(async) {
let obj = {
method: async(function*(a, b) {
do_check_eq(this, obj);
do_check_eq(a, "foo");
do_check_eq(b, "bar");
})
};
return obj.method("foo", "bar");
}
// Test that the return value from the async function is resolution value of
// the promise.
function test_async_return(async) {
let obj = {
method: async(function*(a, b) {
return a + b;
})
};
return obj.method("foo", "bar").then(ret => {
do_check_eq(ret, "foobar");
});
}
// Test that the throwing from an async function rejects the promise.
function test_async_throw(async) {
let obj = {
method: async(function*() {
throw "boom";
})
};
return obj.method().then(null, error => {
do_check_eq(error, "boom");
});
}
// Test that asyncOnce only runs the async function once per instance and
// returns the same promise for that instance.
function test_async_once() {
let counter = 0;
function Foo() {}
Foo.prototype = {
ran: false,
method: asyncOnce(function*() {
yield Promise.resolve();
if (this.ran) {
do_throw("asyncOnce function unexpectedly ran twice on the same object");
}
this.ran = true;
return counter++;
})
};
let foo1 = new Foo();
let foo2 = new Foo();
let p1 = foo1.method();
let p2 = foo2.method();
do_check_neq(p1, p2);
let p3 = foo1.method();
do_check_eq(p1, p3);
do_check_false(foo1.ran);
let p4 = foo2.method();
do_check_eq(p2, p4);
do_check_false(foo2.ran);
return p1.then(ret => {
do_check_true(foo1.ran);
do_check_eq(ret, 0);
return p2;
}).then(ret => {
do_check_true(foo2.ran);
do_check_eq(ret, 1);
});
}
// Test invoke and call.
function test_async_invoke() {
return Task.spawn(function*() {
function func(a, b, expectedThis, callback) {
"use strict";
do_check_eq(a, "foo");
do_check_eq(b, "bar");
do_check_eq(this, expectedThis);
callback(a + b);
}
// Test call.
let callResult = yield promiseCall(func, "foo", "bar", undefined);
do_check_eq(callResult, "foobar");
// Test invoke.
let obj = { method: func };
let invokeResult = yield promiseInvoke(obj, obj.method, "foo", "bar", obj);
do_check_eq(invokeResult, "foobar");
// Test passing multiple values to the callback.
function multipleResults(callback) {
callback("foo", "bar");
}
let results = yield promiseCall(multipleResults);
do_check_eq(results.length, 2);
do_check_eq(results[0], "foo");
do_check_eq(results[1], "bar");
// Test throwing from the function.
function thrower() {
throw "boom";
}
yield promiseCall(thrower).then(null, error => {
do_check_eq(error, "boom");
});
});
}