browser_net_frame.js (7503B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 /** 7 * Tests for all expected requests when an iframe is loading a subdocument. 8 */ 9 10 const TOP_FILE_NAME = "html_frame-test-page.html"; 11 const SUB_FILE_NAME = "html_frame-subdocument.html"; 12 const TOP_URL = EXAMPLE_URL + TOP_FILE_NAME; 13 const SUB_URL = EXAMPLE_URL + SUB_FILE_NAME; 14 15 const EXPECTED_REQUESTS_TOP = [ 16 { 17 method: "GET", 18 url: TOP_URL, 19 causeType: "document", 20 causeUri: null, 21 stack: true, 22 }, 23 { 24 method: "GET", 25 url: EXAMPLE_URL + "stylesheet_request", 26 causeType: "stylesheet", 27 causeUri: TOP_URL, 28 stack: false, 29 }, 30 { 31 method: "GET", 32 url: EXAMPLE_URL + "img_request", 33 causeType: "img", 34 causeUri: TOP_URL, 35 stack: false, 36 }, 37 { 38 method: "GET", 39 url: EXAMPLE_URL + "xhr_request", 40 causeType: "xhr", 41 causeUri: TOP_URL, 42 stack: [{ fn: "performXhrRequest", file: TOP_FILE_NAME, line: 25 }], 43 }, 44 { 45 method: "GET", 46 url: EXAMPLE_URL + "fetch_request", 47 causeType: "fetch", 48 causeUri: TOP_URL, 49 stack: [{ fn: "performFetchRequest", file: TOP_FILE_NAME, line: 29 }], 50 }, 51 { 52 method: "GET", 53 url: EXAMPLE_URL + "promise_fetch_request", 54 causeType: "fetch", 55 causeUri: TOP_URL, 56 stack: [ 57 { fn: "performPromiseFetchRequest", file: TOP_FILE_NAME, line: 41 }, 58 { 59 fn: null, 60 file: TOP_FILE_NAME, 61 line: 40, 62 asyncCause: "promise callback", 63 }, 64 ], 65 }, 66 { 67 method: "GET", 68 url: EXAMPLE_URL + "timeout_fetch_request", 69 causeType: "fetch", 70 causeUri: TOP_URL, 71 stack: [ 72 { fn: "performTimeoutFetchRequest", file: TOP_FILE_NAME, line: 43 }, 73 { 74 fn: "performPromiseFetchRequest", 75 file: TOP_FILE_NAME, 76 line: 42, 77 asyncCause: "setTimeout handler", 78 }, 79 ], 80 }, 81 { 82 method: "POST", 83 url: EXAMPLE_URL + "beacon_request", 84 causeType: "beacon", 85 causeUri: TOP_URL, 86 stack: [{ fn: "performBeaconRequest", file: TOP_FILE_NAME, line: 33 }], 87 }, 88 ]; 89 90 const EXPECTED_REQUESTS_SUB = [ 91 { 92 method: "GET", 93 url: SUB_URL, 94 causeType: "subdocument", 95 causeUri: TOP_URL, 96 stack: false, 97 }, 98 { 99 method: "GET", 100 url: EXAMPLE_URL + "stylesheet_request", 101 causeType: "stylesheet", 102 causeUri: SUB_URL, 103 stack: false, 104 }, 105 { 106 method: "GET", 107 url: EXAMPLE_URL + "img_request", 108 causeType: "img", 109 causeUri: SUB_URL, 110 stack: false, 111 }, 112 { 113 method: "GET", 114 url: EXAMPLE_URL + "xhr_request", 115 causeType: "xhr", 116 causeUri: SUB_URL, 117 stack: [{ fn: "performXhrRequest", file: SUB_FILE_NAME, line: 24 }], 118 }, 119 { 120 method: "GET", 121 url: EXAMPLE_URL + "fetch_request", 122 causeType: "fetch", 123 causeUri: SUB_URL, 124 stack: [{ fn: "performFetchRequest", file: SUB_FILE_NAME, line: 28 }], 125 }, 126 { 127 method: "GET", 128 url: EXAMPLE_URL + "promise_fetch_request", 129 causeType: "fetch", 130 causeUri: SUB_URL, 131 stack: [ 132 { fn: "performPromiseFetchRequest", file: SUB_FILE_NAME, line: 40 }, 133 { 134 fn: null, 135 file: SUB_FILE_NAME, 136 line: 39, 137 asyncCause: "promise callback", 138 }, 139 ], 140 }, 141 { 142 method: "GET", 143 url: EXAMPLE_URL + "timeout_fetch_request", 144 causeType: "fetch", 145 causeUri: SUB_URL, 146 stack: [ 147 { fn: "performTimeoutFetchRequest", file: SUB_FILE_NAME, line: 42 }, 148 { 149 fn: "performPromiseFetchRequest", 150 file: SUB_FILE_NAME, 151 line: 41, 152 asyncCause: "setTimeout handler", 153 }, 154 ], 155 }, 156 { 157 method: "POST", 158 url: EXAMPLE_URL + "beacon_request", 159 causeType: "beacon", 160 causeUri: SUB_URL, 161 stack: [{ fn: "performBeaconRequest", file: SUB_FILE_NAME, line: 32 }], 162 }, 163 ]; 164 165 const REQUEST_COUNT = 166 EXPECTED_REQUESTS_TOP.length + EXPECTED_REQUESTS_SUB.length; 167 168 add_task(async function () { 169 // the initNetMonitor function clears the network request list after the 170 // page is loaded. That's why we first load a bogus page from SIMPLE_URL, 171 // and only then load the real thing from TOP_URL - we want to catch 172 // all the requests the page is making, not only the XHRs. 173 // We can't use about:blank here, because initNetMonitor checks that the 174 // page has actually made at least one request. 175 const { monitor } = await initNetMonitor(SIMPLE_URL, { requestCount: 1 }); 176 177 const { document, store, windowRequire, connector } = monitor.panelWin; 178 const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); 179 const { getDisplayedRequests, getSortedRequests } = windowRequire( 180 "devtools/client/netmonitor/src/selectors/index" 181 ); 182 183 store.dispatch(Actions.batchEnable(false)); 184 185 const wait = waitForNetworkEvents(monitor, REQUEST_COUNT); 186 await navigateTo(TOP_URL); 187 await wait; 188 189 is( 190 store.getState().requests.requests.length, 191 REQUEST_COUNT, 192 "All the page events should be recorded." 193 ); 194 195 // Fetch stack-trace data from the backend and wait till 196 // all packets are received. 197 const requests = getSortedRequests(store.getState()); 198 await Promise.all( 199 requests.map(requestItem => 200 connector.requestData(requestItem.id, "stackTrace") 201 ) 202 ); 203 204 // While there is a defined order for requests in each document separately, the requests 205 // from different documents may interleave in various ways that change per test run, so 206 // there is not a single order when considering all the requests together. 207 let currentTop = 0; 208 let currentSub = 0; 209 for (let i = 0; i < REQUEST_COUNT; i++) { 210 const requestItem = getSortedRequests(store.getState())[i]; 211 212 const itemUrl = requestItem.url; 213 const itemCauseUri = requestItem.cause.loadingDocumentUri; 214 let spec; 215 if (itemUrl == SUB_URL || itemCauseUri == SUB_URL) { 216 spec = EXPECTED_REQUESTS_SUB[currentSub++]; 217 } else { 218 spec = EXPECTED_REQUESTS_TOP[currentTop++]; 219 } 220 const { method, url, causeType, causeUri, stack } = spec; 221 222 await verifyRequestItemTarget( 223 document, 224 getDisplayedRequests(store.getState()), 225 requestItem, 226 method, 227 url, 228 { cause: { type: causeType, loadingDocumentUri: causeUri } } 229 ); 230 231 const { stacktrace } = requestItem; 232 const stackLen = stacktrace ? stacktrace.length : 0; 233 234 if (stack) { 235 ok(stacktrace, `Request #${i} has a stacktrace`); 236 Assert.greater( 237 stackLen, 238 0, 239 `Request #${i} (${causeType}) has a stacktrace with ${stackLen} items` 240 ); 241 242 // if "stack" is array, check the details about the top stack frames 243 if (Array.isArray(stack)) { 244 stack.forEach((frame, j) => { 245 is( 246 stacktrace[j].functionName, 247 frame.fn, 248 `Request #${i} has the correct function on JS stack frame #${j}` 249 ); 250 is( 251 stacktrace[j].filename.split("/").pop(), 252 frame.file, 253 `Request #${i} has the correct file on JS stack frame #${j}` 254 ); 255 is( 256 stacktrace[j].lineNumber, 257 frame.line, 258 `Request #${i} has the correct line number on JS stack frame #${j}` 259 ); 260 is( 261 stacktrace[j].asyncCause, 262 frame.asyncCause, 263 `Request #${i} has the correct async cause on JS stack frame #${j}` 264 ); 265 }); 266 } 267 } else { 268 is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`); 269 } 270 } 271 272 await teardown(monitor); 273 });