OLD | NEW |
1 // Helper method that waits for a {success: <boolean>, result: any} reply on | 1 // Helper method that waits for a {success: <boolean>, result: any} reply on |
2 // a port and returns a promise that resolves (if success is true) or rejects | 2 // a port and returns a promise that resolves (if success is true) or rejects |
3 // the promise with the value of the result attribute. | 3 // the promise with the value of the result attribute. |
4 function reply_as_promise(t, port) { | 4 function reply_as_promise(t, port) { |
5 return new Promise(function(resolve, reject) { | 5 return new Promise(function(resolve, reject) { |
6 var got_reply = false; | 6 var got_reply = false; |
7 port.onmessage = t.step_func(function(event) { | 7 port.onmessage = t.step_func(function(event) { |
8 assert_false(got_reply); | 8 assert_false(got_reply); |
9 assert_true('success' in event.data); | 9 assert_true('success' in event.data); |
10 assert_true('result' in event.data); | 10 assert_true('result' in event.data); |
11 got_reply = true; | 11 got_reply = true; |
12 if (event.data.success) | 12 if (event.data.success) |
13 resolve(event.data.result); | 13 resolve(event.data.result); |
14 else | 14 else |
15 reject(event.data.result); | 15 reject(event.data.result); |
16 }); | 16 }); |
17 }); | 17 }); |
18 } | 18 } |
19 | 19 |
20 // Method that behaves similarly to navigator.connect, but the actual connect | 20 // Method that behaves similarly to navigator.services.connect, but the actual |
21 // call is made from a cross origin iframe. | 21 // connect call is made from a cross origin iframe. Also the returned port is a |
22 function cross_origin_connect(t, service) { | 22 // MessagePort instead of a ServicePort, but with targetURL, name and data |
| 23 // attributes set. |
| 24 function cross_origin_connect(t, service, options) { |
23 // |service| could be a relative URL, but for this to work from the iframe it | 25 // |service| could be a relative URL, but for this to work from the iframe it |
24 // needs an absolute URL. | 26 // needs an absolute URL. |
25 var target_url = new URL(service, location.origin + base_path()); | 27 var target_url = new URL(service, location.origin + base_path()); |
26 return with_iframe( | 28 return with_iframe( |
27 cross_origin + base_path() + 'resources/connect-helper.html') | 29 cross_origin + base_path() + 'resources/connect-helper.html') |
28 .then(function(iframe) { | 30 .then(function(iframe) { |
29 var channel = new MessageChannel(); | 31 var channel = new MessageChannel(); |
30 iframe.contentWindow.postMessage( | 32 iframe.contentWindow.postMessage( |
31 {connect: target_url.href, port: channel.port2}, '*', [channel.port2])
; | 33 {connect: target_url.href, port: channel.port2, options: options}, '*'
, [channel.port2]); |
32 return reply_as_promise(t, channel.port1); | 34 return reply_as_promise(t, channel.port1); |
33 }); | 35 }) |
| 36 .then(function(result) { |
| 37 var port = result.port; |
| 38 port.targetURL = result.targetURL; |
| 39 port.name = result.name; |
| 40 port.data = result.data; |
| 41 return port; |
| 42 }); |
34 } | 43 } |
35 | 44 |
36 // Method that behaves similarly to navigator.connect, but the actual connect | 45 // Method that behaves similarly to navigator.connect, but the actual connect |
37 // call is made from a worker. | 46 // call is made from a worker. Also the returned port is a MessagePort instead |
38 function connect_from_worker(t, service) { | 47 // of a ServicePort, but with targetURL, name and data attributes set. |
| 48 function connect_from_worker(t, service, options) { |
39 // |service| is a relative URL, but for this to work from the worker it needs | 49 // |service| is a relative URL, but for this to work from the worker it needs |
40 // an absolute URL. | 50 // an absolute URL. |
41 var target_url = location.origin + base_path() + service; | 51 var target_url = location.origin + base_path() + service; |
42 var worker = new Worker('resources/connect-helper.js'); | 52 var worker = new Worker('resources/connect-helper.js'); |
43 var channel = new MessageChannel(); | 53 var channel = new MessageChannel(); |
44 worker.postMessage | 54 worker.postMessage |
45 ({connect: target_url, port: channel.port2}, [channel.port2]); | 55 ({connect: target_url, port: channel.port2, options: options}, [channel.port
2]); |
46 return reply_as_promise(t, channel.port1); | 56 return reply_as_promise(t, channel.port1) |
47 } | 57 .then(function(result) { |
48 | 58 var port = result.port; |
49 // Similar to Promise.race, except that returned promise only rejects if all | 59 port.targetURL = result.targetURL; |
50 // passed promises reject. Used temporarily to support both old and new client | 60 port.name = result.name; |
51 // side APIs. | 61 port.data = result.data; |
52 function first_to_resolve(promises) { | 62 return port; |
53 return new Promise(function(resolve, reject) { | 63 }); |
54 var remaining = promises.length; | |
55 var resolved = false; | |
56 for (var i = 0; i < promises.length; ++i) { | |
57 Promise.resolve(promises[i]) | |
58 .then(function(result) { | |
59 if (!resolved) { | |
60 resolve(result); | |
61 resolved = true; | |
62 } | |
63 }) | |
64 .catch(function(result) { | |
65 remaining--; | |
66 if (remaining === 0) { | |
67 reject(result); | |
68 } | |
69 }); | |
70 } | |
71 }); | |
72 } | 64 } |
73 | 65 |
74 // Takes (a promise resolving to) a ServicePort instance, and returns a Promise | 66 // Takes (a promise resolving to) a ServicePort instance, and returns a Promise |
75 // that resolves to a MessagePort wrapping that ServicePort. Used to support | 67 // that resolves to a MessagePort wrapping that ServicePort. Used to simplify |
76 // both old and new APIs at the same time. | 68 // testing code and to allow forwarding a connection from a cross origin iframe |
| 69 // or worker to the main test runner. |
77 function wrap_in_port(maybe_port) { | 70 function wrap_in_port(maybe_port) { |
78 return Promise.resolve(maybe_port).then( | 71 return Promise.resolve(maybe_port).then( |
79 function(port) { | 72 function(port) { |
80 var channel = new MessageChannel(); | 73 var channel = new MessageChannel(); |
81 channel.port2.onmessage = function(event) { | 74 channel.port2.onmessage = function(event) { |
82 port.postMessage(event.data, event.ports); | 75 port.postMessage(event.data, event.ports); |
83 }; | 76 }; |
84 // Should use addEventListener and check source of event, but source isn't | 77 // Should use addEventListener and check source of event, but source isn't |
85 // set yet, so for now just assume only one wrapped port is used at a time
. | 78 // set yet, so for now just assume only one wrapped port is used at a time
. |
86 navigator.services.onmessage = function(event) { | 79 navigator.services.onmessage = function(event) { |
87 channel.port2.postMessage(event.data, event.ports); | 80 channel.port2.postMessage(event.data, event.ports); |
88 }; | 81 }; |
| 82 channel.port1.targetURL = port.targetURL; |
| 83 channel.port1.name = port.name; |
| 84 channel.port1.data = port.data; |
89 return channel.port1; | 85 return channel.port1; |
90 } | 86 } |
91 ); | 87 ); |
92 } | 88 } |
93 | 89 |
94 var promise_tests = Promise.resolve(); | 90 var promise_tests = Promise.resolve(); |
95 // Helper function to run promise tests one after the other. | 91 // Helper function to run promise tests one after the other. |
96 // TODO(ortuno): Remove once https://github.com/w3c/testharness.js/pull/115/file
s | 92 // TODO(ortuno): Remove once https://github.com/w3c/testharness.js/pull/115/file
s |
97 // gets through. | 93 // gets through. |
98 function sequential_promise_test(func, name) { | 94 function sequential_promise_test(func, name) { |
99 var test = async_test(name); | 95 var test = async_test(name); |
100 promise_tests = promise_tests.then(function() { | 96 promise_tests = promise_tests.then(function() { |
101 return test.step(func, test, test); | 97 return test.step(func, test, test); |
102 }).then(function() { | 98 }).then(function() { |
103 test.done(); | 99 test.done(); |
104 }).catch(test.step_func(function(value) { | 100 }).catch(test.step_func(function(value) { |
105 // step_func catches the error again so the error doesn't propagate. | 101 // step_func catches the error again so the error doesn't propagate. |
106 throw value; | 102 throw value; |
107 })); | 103 })); |
108 } | 104 } |
OLD | NEW |