| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 var pass = chrome.test.callbackPass; |
| 6 var fail = chrome.test.callbackFail; |
| 7 var assertEq = chrome.test.assertEq; |
| 8 var assertTrue = chrome.test.assertTrue; |
| 9 var relativePath = '/extensions/api_test/executescript/frame_id/frames.html'; |
| 10 var testOrigin = 'http://a.com:PORT'; |
| 11 var testUrl = 'http://a.com:PORT' + relativePath; |
| 12 |
| 13 var tabId; |
| 14 |
| 15 // Frame ID of every frame in this test, and the patterns of the frame URLs. |
| 16 // Frame IDs are lazily initialized (and constant thereafter). |
| 17 // All patterns are mutually exclusive. |
| 18 |
| 19 // Main frame. |
| 20 var ID_FRAME_TOP = 0; |
| 21 var R_FRAME_TOP = /frames\.html/; |
| 22 // Frame with (same-origin) about:srcdoc. |
| 23 var ID_FRAME_SRCDOC; |
| 24 var R_FRAME_SRCDOC = /about:srcdoc/; |
| 25 // Frame with (unique-origin) sandboxed about:blank. |
| 26 var ID_FRAME_UNREACHABLE; |
| 27 var R_FRAME_UNREACHABLE = /about:blank/; |
| 28 // Frame with same-origin page. |
| 29 var ID_FRAME_SECOND; |
| 30 var R_FRAME_SECOND = /frame\.html/; |
| 31 // Same-origin child frame of |frame_second|. |
| 32 var ID_FRAME_THIRD; |
| 33 var R_FRAME_THIRD = /nested\.html/; |
| 34 // Frame for which the extension does not have the right permissions. |
| 35 var ID_FRAME_NOPERMISSION; |
| 36 var R_FRAME_NOPERMISSION = /empty\.html/; |
| 37 |
| 38 function matchesAny(urls, regex) { |
| 39 return urls.some(function(url) { return regex.test(url); }); |
| 40 } |
| 41 |
| 42 var gCssCounter = 0; |
| 43 |
| 44 // Calls chrome.tabs.insertCSS and invokes the callback with a list of affected |
| 45 // URLs. This function assumes that the tab identified by |tabId| exists, and |
| 46 // that |injectDetails| is a valid argument for insertCSS. |
| 47 function insertCSS(tabId, injectDetails, callback) { |
| 48 var marker = (++gCssCounter) + 'px'; |
| 49 injectDetails.code = 'body { min-width: ' + marker + ';}'; |
| 50 chrome.tabs.insertCSS(tabId, injectDetails, function() { |
| 51 chrome.test.assertNoLastError(); |
| 52 chrome.tabs.executeScript( |
| 53 tabId, { |
| 54 code: '[getComputedStyle(document.body).minWidth, document.URL];', |
| 55 allFrames: true, |
| 56 matchAboutBlank: true |
| 57 }, |
| 58 function(results) { |
| 59 chrome.test.assertNoLastError(); |
| 60 results = getAffectedUrls(results); |
| 61 callback(results); |
| 62 }); |
| 63 }); |
| 64 |
| 65 // Selects the results from the frames whose CSS was changed by the insertCSS |
| 66 // call, and returns the URLs of these frames. |
| 67 function getAffectedUrls(results) { |
| 68 return results.filter(function(result) { |
| 69 return result && result[0] === marker; |
| 70 }).map(function(result) { |
| 71 return result[1]; // "document.URL" |
| 72 }); |
| 73 } |
| 74 } |
| 75 |
| 76 chrome.test.getConfig(function(config) { |
| 77 testOrigin = testOrigin.replace(/PORT/, config.testServer.port); |
| 78 testUrl = testUrl.replace(/PORT/, config.testServer.port); |
| 79 chrome.tabs.onUpdated.addListener(function(_, changeInfo, tab) { |
| 80 if (changeInfo.status != 'complete' || tab.id !== tabId) { |
| 81 return; |
| 82 } |
| 83 |
| 84 chrome.webNavigation.getAllFrames({tabId: tabId}, function(frames) { |
| 85 function getFrameId(urlRegex) { |
| 86 var filtered = |
| 87 frames.filter(function(frame) { return urlRegex.test(frame.url); }); |
| 88 // Sanity check. |
| 89 chrome.test.assertEq(1, filtered.length); |
| 90 chrome.test.assertTrue(filtered[0].frameId > 0); |
| 91 return filtered[0].frameId; |
| 92 } |
| 93 |
| 94 ID_FRAME_SRCDOC = getFrameId(R_FRAME_SRCDOC); |
| 95 ID_FRAME_UNREACHABLE = getFrameId(R_FRAME_UNREACHABLE); |
| 96 ID_FRAME_SECOND = getFrameId(R_FRAME_SECOND); |
| 97 ID_FRAME_THIRD = getFrameId(R_FRAME_THIRD); |
| 98 ID_FRAME_NOPERMISSION = getFrameId(R_FRAME_NOPERMISSION); |
| 99 |
| 100 runTests(config); |
| 101 }); |
| 102 }); |
| 103 |
| 104 chrome.tabs.create({url: testUrl}, function(tab) { tabId = tab.id; }); |
| 105 }); |
| 106 |
| 107 function runTests(config) { |
| 108 // All of the following tests set the frameId parameter in the injection |
| 109 // details. |
| 110 chrome.test.runTests([ |
| 111 function executeScriptInTopFrame() { |
| 112 chrome.tabs.executeScript( |
| 113 tabId, {frameId: 0, code: 'document.URL'}, pass(function(results) { |
| 114 assertEq(1, results.length); |
| 115 assertTrue(matchesAny(results, R_FRAME_TOP)); |
| 116 })); |
| 117 }, |
| 118 |
| 119 function executeScriptInTopFrameIncludingAllFrames() { |
| 120 chrome.tabs.executeScript( |
| 121 tabId, { |
| 122 frameId: 0, |
| 123 matchAboutBlank: true, |
| 124 allFrames: true, |
| 125 code: 'document.URL' |
| 126 }, |
| 127 pass(function(results) { |
| 128 assertEq(4, results.length); |
| 129 assertTrue(matchesAny(results, R_FRAME_TOP)); |
| 130 assertTrue(matchesAny(results, R_FRAME_SRCDOC)); |
| 131 assertTrue(matchesAny(results, R_FRAME_SECOND)); |
| 132 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 133 })); |
| 134 }, |
| 135 |
| 136 function executeScriptInSrcdocFrame() { |
| 137 chrome.tabs.executeScript( |
| 138 tabId, { |
| 139 frameId: ID_FRAME_SRCDOC, |
| 140 matchAboutBlank: true, |
| 141 code: 'document.URL' |
| 142 }, |
| 143 pass(function(results) { |
| 144 assertEq(1, results.length); |
| 145 assertTrue(matchesAny(results, R_FRAME_SRCDOC)); |
| 146 })); |
| 147 }, |
| 148 |
| 149 function executeScriptInSrcdocFrameWithoutMatchAboutBlank() { |
| 150 // TODO(robwu): Why is the origin serialized as "about:blank" instead of |
| 151 // "about:srcdoc"? |
| 152 chrome.tabs.executeScript( |
| 153 tabId, {frameId: ID_FRAME_SRCDOC, code: 'document.URL'}, |
| 154 fail( |
| 155 'Cannot access "about:blank" at origin "' + testOrigin + '". ' + |
| 156 'Extension must have permission to access the frame\'s origin, ' + |
| 157 'and matchAboutBlank must be true.')); |
| 158 }, |
| 159 |
| 160 function executeScriptInSrcdocFrameIncludingAllFrames() { |
| 161 chrome.tabs.executeScript( |
| 162 tabId, { |
| 163 frameId: ID_FRAME_SRCDOC, |
| 164 matchAboutBlank: true, |
| 165 allFrames: true, |
| 166 code: 'document.URL' |
| 167 }, |
| 168 pass(function(results) { |
| 169 assertEq(1, results.length); |
| 170 assertTrue(matchesAny(results, R_FRAME_SRCDOC)); |
| 171 })); |
| 172 }, |
| 173 |
| 174 function executeScriptInSandboxedFrame() { |
| 175 chrome.tabs.executeScript( |
| 176 tabId, { |
| 177 frameId: ID_FRAME_UNREACHABLE, |
| 178 matchAboutBlank: true, |
| 179 code: 'document.URL' |
| 180 }, |
| 181 fail( |
| 182 'Cannot access "about:blank" at origin "null". Extension must ' + |
| 183 'have permission to access the frame\'s origin, and ' + |
| 184 'matchAboutBlank must be true.')); |
| 185 }, |
| 186 |
| 187 function executeScriptInSubFrame() { |
| 188 chrome.tabs.executeScript( |
| 189 tabId, {frameId: ID_FRAME_SECOND, code: 'document.URL'}, |
| 190 pass(function(results) { |
| 191 assertEq(1, results.length); |
| 192 assertTrue(matchesAny(results, R_FRAME_SECOND)); |
| 193 })); |
| 194 }, |
| 195 |
| 196 function executeScriptInSubFrameIncludingAllFrames() { |
| 197 chrome.tabs.executeScript( |
| 198 tabId, |
| 199 {frameId: ID_FRAME_SECOND, allFrames: true, code: 'document.URL'}, |
| 200 pass(function(results) { |
| 201 assertEq(2, results.length); |
| 202 assertTrue(matchesAny(results, R_FRAME_SECOND)); |
| 203 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 204 })); |
| 205 }, |
| 206 |
| 207 function executeScriptInNestedFrame() { |
| 208 chrome.tabs.executeScript( |
| 209 tabId, {frameId: ID_FRAME_THIRD, code: 'document.URL'}, |
| 210 pass(function(results) { |
| 211 assertEq(1, results.length); |
| 212 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 213 })); |
| 214 }, |
| 215 |
| 216 function executeScriptInNestedFrameIncludingAllFrames() { |
| 217 chrome.tabs.executeScript( |
| 218 tabId, |
| 219 {frameId: ID_FRAME_THIRD, allFrames: true, code: 'document.URL'}, |
| 220 pass(function(results) { |
| 221 assertEq(1, results.length); |
| 222 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 223 })); |
| 224 }, |
| 225 |
| 226 function executeScriptInFrameWithoutPermission() { |
| 227 chrome.tabs.executeScript( |
| 228 tabId, {frameId: ID_FRAME_NOPERMISSION, code: 'document.URL'}, |
| 229 fail( |
| 230 'Cannot access contents of url "http://c.com:' + |
| 231 config.testServer.port + '/empty.html". Extension manifest ' + |
| 232 'must request permission to access this host.')); |
| 233 }, |
| 234 |
| 235 function executeScriptWithNonExistentFrameId() { |
| 236 chrome.tabs.executeScript( |
| 237 tabId, {frameId: 999999999, code: 'document.URL'}, |
| 238 fail('No frame with id 999999999 in tab ' + tabId + '.')); |
| 239 }, |
| 240 |
| 241 function executeScriptWithNegativeFrameId() { |
| 242 try { |
| 243 chrome.tabs.executeScript( |
| 244 tabId, {frameId: -1, code: 'document.URL'}, function() { |
| 245 chrome.test.fail( |
| 246 'executeScript should never have been executed!'); |
| 247 }); |
| 248 } catch (e) { |
| 249 assertEq( |
| 250 'Invalid value for argument 2. Property \'frameId\': ' + |
| 251 'Value must not be less than 0.', |
| 252 e.message); |
| 253 chrome.test.succeed(); |
| 254 } |
| 255 }, |
| 256 |
| 257 function insertCSSInTopFrame() { |
| 258 insertCSS(tabId, {frameId: 0}, pass(function(results) { |
| 259 assertEq(1, results.length); |
| 260 assertTrue(matchesAny(results, R_FRAME_TOP)); |
| 261 })); |
| 262 }, |
| 263 |
| 264 function insertCSSInTopFrameIncludingAllFrames() { |
| 265 insertCSS( |
| 266 tabId, {frameId: 0, matchAboutBlank: true, allFrames: true}, |
| 267 pass(function(results) { |
| 268 assertEq(4, results.length); |
| 269 assertTrue(matchesAny(results, R_FRAME_TOP)); |
| 270 assertTrue(matchesAny(results, R_FRAME_SRCDOC)); |
| 271 assertTrue(matchesAny(results, R_FRAME_SECOND)); |
| 272 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 273 })); |
| 274 }, |
| 275 |
| 276 function insertCSSInSrcdocFrame() { |
| 277 insertCSS( |
| 278 tabId, {frameId: ID_FRAME_SRCDOC, matchAboutBlank: true}, |
| 279 pass(function(results) { |
| 280 assertEq(1, results.length); |
| 281 assertTrue(matchesAny(results, R_FRAME_SRCDOC)); |
| 282 })); |
| 283 }, |
| 284 |
| 285 function insertCSSInSrcdocFrameWithoutMatchAboutBlank() { |
| 286 // TODO(robwu): Why is the origin serialized as "about:blank" instead of |
| 287 // "about:srcdoc"? |
| 288 chrome.tabs.insertCSS( |
| 289 tabId, {frameId: ID_FRAME_SRCDOC, code: 'body{color:red;}'}, |
| 290 fail( |
| 291 'Cannot access "about:blank" at origin "' + testOrigin + '". ' + |
| 292 'Extension must have permission to access the frame\'s origin, ' + |
| 293 'and matchAboutBlank must be true.')); |
| 294 }, |
| 295 |
| 296 function insertCSSInSrcdocFrameIncludingAllFrames() { |
| 297 insertCSS( |
| 298 tabId, |
| 299 {frameId: ID_FRAME_SRCDOC, matchAboutBlank: true, allFrames: true}, |
| 300 pass(function(results) { |
| 301 assertEq(1, results.length); |
| 302 assertTrue(matchesAny(results, R_FRAME_SRCDOC)); |
| 303 })); |
| 304 }, |
| 305 |
| 306 function insertCSSInSandboxedFrame() { |
| 307 chrome.tabs.insertCSS( |
| 308 tabId, { |
| 309 frameId: ID_FRAME_UNREACHABLE, |
| 310 matchAboutBlank: true, |
| 311 code: 'body{color:red}' |
| 312 }, |
| 313 fail( |
| 314 'Cannot access "about:blank" at origin "null". Extension must ' + |
| 315 'have permission to access the frame\'s origin, and ' + |
| 316 'matchAboutBlank must be true.')); |
| 317 }, |
| 318 |
| 319 function insertCSSInSubFrame() { |
| 320 insertCSS(tabId, {frameId: ID_FRAME_SECOND}, pass(function(results) { |
| 321 assertEq(1, results.length); |
| 322 assertTrue(matchesAny(results, R_FRAME_SECOND)); |
| 323 })); |
| 324 }, |
| 325 |
| 326 function insertCSSInSubFrameIncludingAllFrames() { |
| 327 insertCSS( |
| 328 tabId, {frameId: ID_FRAME_SECOND, allFrames: true}, |
| 329 pass(function(results) { |
| 330 assertEq(2, results.length); |
| 331 assertTrue(matchesAny(results, R_FRAME_SECOND)); |
| 332 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 333 })); |
| 334 }, |
| 335 |
| 336 function insertCSSInNestedFrame() { |
| 337 insertCSS(tabId, {frameId: ID_FRAME_THIRD}, pass(function(results) { |
| 338 assertEq(1, results.length); |
| 339 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 340 })); |
| 341 }, |
| 342 |
| 343 function insertCSSInNestedFrameIncludingAllFrames() { |
| 344 insertCSS( |
| 345 tabId, {frameId: ID_FRAME_THIRD, allFrames: true}, |
| 346 pass(function(results) { |
| 347 assertEq(1, results.length); |
| 348 assertTrue(matchesAny(results, R_FRAME_THIRD)); |
| 349 })); |
| 350 }, |
| 351 |
| 352 function insertCSSInFrameWithoutPermission() { |
| 353 chrome.tabs.insertCSS( |
| 354 tabId, {frameId: ID_FRAME_NOPERMISSION, code: 'body{color:red}'}, |
| 355 fail( |
| 356 'Cannot access contents of url "http://c.com:' + |
| 357 config.testServer.port + '/empty.html". Extension manifest ' + |
| 358 'must request permission to access this host.')); |
| 359 }, |
| 360 |
| 361 function insertCSSWithNonExistentFrameId() { |
| 362 chrome.tabs.insertCSS( |
| 363 tabId, {frameId: 999999999, code: 'body{color:red}'}, |
| 364 fail('No frame with id 999999999 in tab ' + tabId + '.')); |
| 365 }, |
| 366 |
| 367 function insertCSSWithNegativeFrameId() { |
| 368 try { |
| 369 chrome.tabs.insertCSS( |
| 370 tabId, {frameId: -1, code: 'body{color:red}'}, function() { |
| 371 chrome.test.fail('insertCSS should never have been executed!'); |
| 372 }); |
| 373 } catch (e) { |
| 374 assertEq( |
| 375 'Invalid value for argument 2. Property \'frameId\': ' + |
| 376 'Value must not be less than 0.', |
| 377 e.message); |
| 378 chrome.test.succeed(); |
| 379 } |
| 380 }, |
| 381 |
| 382 ]); |
| 383 } |
| OLD | NEW |