subordinate-frame.sub.html (3933B)
1 <!doctype html> 2 <meta charset="utf-8"> 3 <html> 4 <head> 5 <!--- Allow injected scripts to use functions in fledge-util.sub.js ---> 6 <base href=".."> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testdriver.js"></script> 9 <script src="/resources/testdriver-vendor.js"></script> 10 <script src="/common/utils.js"></script> 11 <script src="resources/fledge-util.sub.js"></script> 12 </head> 13 <body> 14 <script> 15 16 // This can be used for either iframes or top-level windows. 17 // If there is an opener, this is a top-level window, so 18 // send messages to the opener. Otherwise, this is an iframe, 19 // so send messages to the parent. 20 let message_dest = window.opener; 21 if (!message_dest) 22 message_dest = window.parent; 23 24 // In order to use some WPT test fixture features in another frame 25 // (particularly, testdriver), we need to set the test context for the test 26 // driver. This is main window driving the test. 27 // 28 // To find that window, follow both parent and opener links to very end; 29 // keeping in mind that top-level windows' parent fields loop back to 30 // themselves. 31 let main_test_window = window; 32 while (true) { 33 if (main_test_window.opener) { 34 main_test_window = main_test_window.opener; 35 } else if (main_test_window.parent !== main_test_window) { 36 main_test_window = main_test_window.parent; 37 } else { 38 break; 39 } 40 } 41 42 test_driver.set_test_context(main_test_window); 43 44 // Fake Test class that only supports adding cleanup callbacks, 45 // primarily to leave interest groups once the test is complete. 46 function Test() { 47 this.cleanup_callbacks = []; 48 } 49 50 // Registers a cleanup method with Test. 51 Test.prototype.add_cleanup = function(callback) { 52 this.cleanup_callbacks.push(callback); 53 }; 54 55 // Runs all previously registered cleanup methods, waiting for 56 // them all to complete. 57 Test.prototype.do_cleanup = async function() { 58 while (this.cleanup_callbacks.length > 0) { 59 await this.cleanup_callbacks[0](); 60 this.cleanup_callbacks = this.cleanup_callbacks.slice(1); 61 } 62 }; 63 64 // Create a bogus test instance that tracks cleanup callbacks. The 65 // main frame managing the test is expected to post a message 66 // to run test_instance.do_cleanup() and wait for it to complete 67 // before destroying the frame. 68 let test_instance = new Test(); 69 70 // Register a message event listener that listens for events with data 71 // in the format {messageUuid: <uuid>, script: <script>}, and when such 72 // a message is received, tries to eval the script and then returns a 73 // message in the format: 74 // {messageUuid: <uuid>, result: <result>, returnValue: <returnValue>} 75 // 76 // On success, <result> is "success", while on failure, it's an error 77 // message. <script> is interpreted as a possibly asynchronous function 78 // body. Exceptions are caught and their stringified value is returned 79 // as <result>. <returnValue> is a value returned to the caller of 80 // the function that sent the message. It's up to the received script 81 // to set it, if a return value is needed. 82 // 83 // "messageUuid" serves to allow the listener to make sure the message 84 // is intended for it. 85 window.addEventListener('message', async function(event) { 86 // If not a message for this listener, do nothing. 87 if (!event.data.messageUuid) 88 return; 89 let message = {result: 'unexpected'}; 90 try { 91 let param = event.data.param; 92 message = await eval( 93 `(async () => { 94 ${event.data.script}; 95 return {result: 'success'}; 96 })()`); 97 } catch (e) { 98 message.result = e.toString(); 99 } 100 message.messageUuid = event.data.messageUuid; 101 102 message_dest.postMessage(message, '*'); 103 }); 104 105 // Inform "message_dest" that the frame has finished loading. 106 message_dest.postMessage( 107 {messageUuid: '{{GET[uuid]}}', result: 'load complete'}, 108 '*'); 109 </script> 110 </body> 111 </html>