browser_resources_unwatch_early.js (3819B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test that calling unwatchResources before watchResources could resolve still 7 // removes watcher entries correctly. 8 9 const ResourceCommand = require("resource://devtools/shared/commands/resource/resource-command.js"); 10 11 const TEST_URI = "data:text/html;charset=utf-8,"; 12 13 add_task(async function () { 14 const tab = await addTab(TEST_URI); 15 16 const { client, resourceCommand, targetCommand } = 17 await initResourceCommand(tab); 18 const { CONSOLE_MESSAGE, ROOT_NODE } = resourceCommand.TYPES; 19 20 info("Use console.log in the content page"); 21 await logInTab(tab, "msg-1"); 22 23 info("Call watchResources with various configurations"); 24 25 // Watcher 1 only watches for CONSOLE_MESSAGE. 26 // For this call site, unwatchResource will be called before onAvailable has 27 // resolved. 28 const messages1 = []; 29 const onAvailable1 = createMessageCallback(messages1); 30 const onWatcher1Ready = resourceCommand.watchResources([CONSOLE_MESSAGE], { 31 onAvailable: onAvailable1, 32 }); 33 resourceCommand.unwatchResources([CONSOLE_MESSAGE], { 34 onAvailable: onAvailable1, 35 }); 36 37 info( 38 "Calling unwatchResources for an already unregistered callback should be a no-op" 39 ); 40 // and more importantly, it should not throw 41 resourceCommand.unwatchResources([CONSOLE_MESSAGE], { 42 onAvailable: onAvailable1, 43 }); 44 45 // Watcher 2 watches for CONSOLE_MESSAGE & another resource (ROOT_NODE). 46 // Again unwatchResource will be called before onAvailable has resolved. 47 // But unwatchResource is only called for CONSOLE_MESSAGE, not for ROOT_NODE. 48 const messages2 = []; 49 const onAvailable2 = createMessageCallback(messages2); 50 const onWatcher2Ready = resourceCommand.watchResources( 51 [CONSOLE_MESSAGE, ROOT_NODE], 52 { 53 onAvailable: onAvailable2, 54 } 55 ); 56 resourceCommand.unwatchResources([CONSOLE_MESSAGE], { 57 onAvailable: onAvailable2, 58 }); 59 60 // Watcher 3 watches for CONSOLE_MESSAGE, but we will not call unwatchResource 61 // explicitly for it before the end of test. Used as a reference. 62 const messages3 = []; 63 const onAvailable3 = createMessageCallback(messages3); 64 const onWatcher3Ready = resourceCommand.watchResources([CONSOLE_MESSAGE], { 65 onAvailable: onAvailable3, 66 }); 67 68 info("Call unwatchResources for CONSOLE_MESSAGE on watcher 1 & 2"); 69 70 info("Wait for all watchers `watchResources` to resolve"); 71 await Promise.all([onWatcher1Ready, onWatcher2Ready, onWatcher3Ready]); 72 ok(!hasMessage(messages1, "msg-1"), "Watcher 1 did not receive msg-1"); 73 ok(!hasMessage(messages2, "msg-1"), "Watcher 2 did not receive msg-1"); 74 ok(hasMessage(messages3, "msg-1"), "Watcher 3 received msg-1"); 75 76 info("Log a new message"); 77 await logInTab(tab, "msg-2"); 78 79 info("Wait until watcher 3 received the new message"); 80 await waitUntil(() => hasMessage(messages3, "msg-2")); 81 82 ok(!hasMessage(messages1, "msg-2"), "Watcher 1 did not receive msg-2"); 83 ok(!hasMessage(messages2, "msg-2"), "Watcher 2 did not receive msg-2"); 84 85 targetCommand.destroy(); 86 await client.close(); 87 }); 88 89 function logInTab(tab, message) { 90 return ContentTask.spawn(tab.linkedBrowser, message, function (_message) { 91 content.console.log(_message); 92 }); 93 } 94 95 function hasMessage(messageResources, text) { 96 return messageResources.find(resource => resource.arguments[0] === text); 97 } 98 99 // All resource command callbacks share the same pattern here: they add all 100 // console message resources to a provided `messages` array. 101 function createMessageCallback(messages) { 102 const { CONSOLE_MESSAGE } = ResourceCommand.TYPES; 103 return async resources => { 104 for (const resource of resources) { 105 if (resource.resourceType === CONSOLE_MESSAGE) { 106 messages.push(resource); 107 } 108 } 109 }; 110 }