|
1 /* -*- Mode: js; js-indent-level: 2; -*- */ |
|
2 /* Any copyright is dedicated to the Public Domain. |
|
3 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
4 |
|
5 // Test async-utils.js |
|
6 |
|
7 const {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); |
|
8 // |const| will not work because |
|
9 // it will make the Promise object immutable before assigning. |
|
10 // Using Object.defineProperty() instead. |
|
11 Object.defineProperty(this, "Promise", { |
|
12 value: Cu.import("resource://gre/modules/Promise.jsm", {}).Promise, |
|
13 writable: false, configurable: false |
|
14 }); |
|
15 const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; |
|
16 const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils"); |
|
17 |
|
18 function run_test() { |
|
19 do_test_pending(); |
|
20 Task.spawn(function*() { |
|
21 for (let helper of [async, asyncOnce]) { |
|
22 yield test_async_args(helper); |
|
23 yield test_async_return(helper); |
|
24 yield test_async_throw(helper); |
|
25 } |
|
26 yield test_async_once(); |
|
27 yield test_async_invoke(); |
|
28 do_test_finished(); |
|
29 }).then(null, error => { |
|
30 do_throw(error); |
|
31 }); |
|
32 } |
|
33 |
|
34 // Test that arguments are correctly passed through to the async function. |
|
35 function test_async_args(async) { |
|
36 let obj = { |
|
37 method: async(function*(a, b) { |
|
38 do_check_eq(this, obj); |
|
39 do_check_eq(a, "foo"); |
|
40 do_check_eq(b, "bar"); |
|
41 }) |
|
42 }; |
|
43 |
|
44 return obj.method("foo", "bar"); |
|
45 } |
|
46 |
|
47 // Test that the return value from the async function is resolution value of |
|
48 // the promise. |
|
49 function test_async_return(async) { |
|
50 let obj = { |
|
51 method: async(function*(a, b) { |
|
52 return a + b; |
|
53 }) |
|
54 }; |
|
55 |
|
56 return obj.method("foo", "bar").then(ret => { |
|
57 do_check_eq(ret, "foobar"); |
|
58 }); |
|
59 } |
|
60 |
|
61 // Test that the throwing from an async function rejects the promise. |
|
62 function test_async_throw(async) { |
|
63 let obj = { |
|
64 method: async(function*() { |
|
65 throw "boom"; |
|
66 }) |
|
67 }; |
|
68 |
|
69 return obj.method().then(null, error => { |
|
70 do_check_eq(error, "boom"); |
|
71 }); |
|
72 } |
|
73 |
|
74 // Test that asyncOnce only runs the async function once per instance and |
|
75 // returns the same promise for that instance. |
|
76 function test_async_once() { |
|
77 let counter = 0; |
|
78 |
|
79 function Foo() {} |
|
80 Foo.prototype = { |
|
81 ran: false, |
|
82 method: asyncOnce(function*() { |
|
83 yield Promise.resolve(); |
|
84 if (this.ran) { |
|
85 do_throw("asyncOnce function unexpectedly ran twice on the same object"); |
|
86 } |
|
87 this.ran = true; |
|
88 return counter++; |
|
89 }) |
|
90 }; |
|
91 |
|
92 let foo1 = new Foo(); |
|
93 let foo2 = new Foo(); |
|
94 let p1 = foo1.method(); |
|
95 let p2 = foo2.method(); |
|
96 |
|
97 do_check_neq(p1, p2); |
|
98 |
|
99 let p3 = foo1.method(); |
|
100 do_check_eq(p1, p3); |
|
101 do_check_false(foo1.ran); |
|
102 |
|
103 let p4 = foo2.method(); |
|
104 do_check_eq(p2, p4); |
|
105 do_check_false(foo2.ran); |
|
106 |
|
107 return p1.then(ret => { |
|
108 do_check_true(foo1.ran); |
|
109 do_check_eq(ret, 0); |
|
110 return p2; |
|
111 }).then(ret => { |
|
112 do_check_true(foo2.ran); |
|
113 do_check_eq(ret, 1); |
|
114 }); |
|
115 } |
|
116 |
|
117 // Test invoke and call. |
|
118 function test_async_invoke() { |
|
119 return Task.spawn(function*() { |
|
120 function func(a, b, expectedThis, callback) { |
|
121 "use strict"; |
|
122 do_check_eq(a, "foo"); |
|
123 do_check_eq(b, "bar"); |
|
124 do_check_eq(this, expectedThis); |
|
125 callback(a + b); |
|
126 } |
|
127 |
|
128 // Test call. |
|
129 let callResult = yield promiseCall(func, "foo", "bar", undefined); |
|
130 do_check_eq(callResult, "foobar"); |
|
131 |
|
132 |
|
133 // Test invoke. |
|
134 let obj = { method: func }; |
|
135 let invokeResult = yield promiseInvoke(obj, obj.method, "foo", "bar", obj); |
|
136 do_check_eq(invokeResult, "foobar"); |
|
137 |
|
138 |
|
139 // Test passing multiple values to the callback. |
|
140 function multipleResults(callback) { |
|
141 callback("foo", "bar"); |
|
142 } |
|
143 |
|
144 let results = yield promiseCall(multipleResults); |
|
145 do_check_eq(results.length, 2); |
|
146 do_check_eq(results[0], "foo"); |
|
147 do_check_eq(results[1], "bar"); |
|
148 |
|
149 |
|
150 // Test throwing from the function. |
|
151 function thrower() { |
|
152 throw "boom"; |
|
153 } |
|
154 |
|
155 yield promiseCall(thrower).then(null, error => { |
|
156 do_check_eq(error, "boom"); |
|
157 }); |
|
158 }); |
|
159 } |