browser_resources_css_messages.js (7096B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test the ResourceCommand API around CSS_MESSAGE 7 // Reproduces the CSS message assertions from devtools/shared/webconsole/test/chrome/test_page_errors.html 8 9 const { MESSAGE_CATEGORY } = require("resource://devtools/shared/constants.js"); 10 11 // Create a simple server so we have a nice sourceName in the resources packets. 12 const httpServer = createTestHTTPServer(); 13 httpServer.registerPathHandler(`/test_css_messages.html`, (req, res) => { 14 res.setStatusLine(req.httpVersion, 200, "OK"); 15 res.setHeader("Content-Type", "text/html"); 16 res.write(`<meta charset=utf8> 17 <style> 18 html { 19 body { 20 color: bloup; 21 } 22 } 23 </style>Test CSS Messages`); 24 }); 25 26 const TEST_URI = `http://localhost:${httpServer.identity.primaryPort}/test_css_messages.html`; 27 28 add_task(async function () { 29 await testWatchingCssMessages(); 30 await testWatchingCachedCssMessages(); 31 }); 32 33 async function testWatchingCssMessages() { 34 // Disable the preloaded process as it creates processes intermittently 35 // which forces the emission of RDP requests we aren't correctly waiting for. 36 await pushPref("dom.ipc.processPrelaunch.enabled", false); 37 38 // Open a test tab 39 const tab = await addTab(TEST_URI); 40 41 const { client, resourceCommand, targetCommand } = 42 await initResourceCommand(tab); 43 44 const receivedMessages = []; 45 const { onAvailable, onAllMessagesReceived } = setupOnAvailableFunction( 46 targetCommand, 47 receivedMessages, 48 false 49 ); 50 await resourceCommand.watchResources([resourceCommand.TYPES.CSS_MESSAGE], { 51 onAvailable, 52 }); 53 54 info( 55 "Now log CSS warning *after* the call to ResourceCommand.watchResources and after " + 56 "having received the existing message" 57 ); 58 // We need to wait for the first CSS Warning as it is not a cached message; when we 59 // start watching, the `cssErrorReportingEnabled` is checked on the target docShell, and 60 // if it is false, we re-parse the stylesheets to get the messages. 61 await BrowserTestUtils.waitForCondition(() => receivedMessages.length === 1); 62 63 info("Trigger a CSS Warning"); 64 triggerCSSWarning(tab); 65 66 info("Waiting for all expected CSS messages to be received"); 67 await onAllMessagesReceived; 68 ok(true, "All the expected CSS messages were received"); 69 70 Services.console.reset(); 71 targetCommand.destroy(); 72 await client.close(); 73 } 74 75 async function testWatchingCachedCssMessages() { 76 // Disable the preloaded process as it creates processes intermittently 77 // which forces the emission of RDP requests we aren't correctly waiting for. 78 await pushPref("dom.ipc.processPrelaunch.enabled", false); 79 80 // Open a test tab 81 const tab = await addTab(TEST_URI); 82 83 // By default, the CSS Parser does not emit warnings at all, for performance matter. 84 // Since we actually want the Parser to emit those messages _before_ we start listening 85 // for CSS messages, we need to set the cssErrorReportingEnabled flag on the docShell. 86 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () { 87 content.docShell.cssErrorReportingEnabled = true; 88 ChromeUtils.clearResourceCache({ 89 types: ["stylesheet"], 90 }); 91 }); 92 93 // Setting the docShell flag only indicates to the Parser that from now on, it should 94 // emit warnings. But it does not automatically emit warnings for the existing CSS 95 // errors in the stylesheets. So here we reload the tab, which will make the Parser 96 // parse the stylesheets again, this time emitting warnings. 97 await reloadBrowser(); 98 // and trigger more CSS warnings 99 await triggerCSSWarning(tab); 100 101 // At this point, all messages should be in the ConsoleService cache, and we can begin 102 // to watch and check that we do retrieve those messages. 103 const { client, resourceCommand, targetCommand } = 104 await initResourceCommand(tab); 105 106 const receivedMessages = []; 107 const { onAvailable } = setupOnAvailableFunction( 108 targetCommand, 109 receivedMessages, 110 true 111 ); 112 await resourceCommand.watchResources([resourceCommand.TYPES.CSS_MESSAGE], { 113 onAvailable, 114 }); 115 is(receivedMessages.length, 3, "Cached messages were retrieved as expected"); 116 117 Services.console.reset(); 118 targetCommand.destroy(); 119 await client.close(); 120 } 121 122 function setupOnAvailableFunction( 123 targetCommand, 124 receivedMessages, 125 isAlreadyExistingResource 126 ) { 127 // timeStamp are the result of a number in microsecond divided by 1000. 128 // so we can't expect a precise number of decimals, or even if there would 129 // be decimals at all. 130 const FRACTIONAL_NUMBER_REGEX = /^\d+(\.\d{1,3})?$/; 131 132 // The expected messages are the CSS warnings: 133 // - one for the rule in the style element 134 // - two for the JS modified style we're doing in the test. 135 const expectedMessages = [ 136 { 137 pageError: { 138 errorMessage: /Expected color but found ‘bloup’/, 139 sourceName: /test_css_messages/, 140 category: MESSAGE_CATEGORY.CSS_PARSER, 141 timeStamp: FRACTIONAL_NUMBER_REGEX, 142 error: false, 143 warning: true, 144 }, 145 cssSelectors: ":is(html) body", 146 isAlreadyExistingResource, 147 }, 148 { 149 pageError: { 150 errorMessage: /Error in parsing value for ‘width’/, 151 sourceName: /test_css_messages/, 152 category: MESSAGE_CATEGORY.CSS_PARSER, 153 timeStamp: FRACTIONAL_NUMBER_REGEX, 154 error: false, 155 warning: true, 156 }, 157 isAlreadyExistingResource, 158 }, 159 { 160 pageError: { 161 errorMessage: /Error in parsing value for ‘height’/, 162 sourceName: /test_css_messages/, 163 category: MESSAGE_CATEGORY.CSS_PARSER, 164 timeStamp: FRACTIONAL_NUMBER_REGEX, 165 error: false, 166 warning: true, 167 }, 168 isAlreadyExistingResource, 169 }, 170 ]; 171 172 let done; 173 const onAllMessagesReceived = new Promise(resolve => (done = resolve)); 174 const onAvailable = resources => { 175 for (const resource of resources) { 176 const { pageError } = resource; 177 178 is( 179 resource.targetFront, 180 targetCommand.targetFront, 181 "The targetFront property is the expected one" 182 ); 183 184 if (!pageError.sourceName.includes("test_css_messages")) { 185 info(`Ignore error from unknown source: "${pageError.sourceName}"`); 186 continue; 187 } 188 189 const index = receivedMessages.length; 190 receivedMessages.push(resource); 191 192 info( 193 `checking received css message #${index}: ${pageError.errorMessage}` 194 ); 195 ok(pageError, "The resource has a pageError attribute"); 196 checkObject(resource, expectedMessages[index]); 197 198 if (receivedMessages.length == expectedMessages.length) { 199 done(); 200 } 201 } 202 }; 203 return { onAvailable, onAllMessagesReceived }; 204 } 205 206 /** 207 * Sets invalid values for width and height on the document's body style attribute. 208 */ 209 function triggerCSSWarning(tab) { 210 return ContentTask.spawn(tab.linkedBrowser, null, function frameScript() { 211 content.document.body.style.width = "red"; 212 content.document.body.style.height = "blue"; 213 }); 214 }