browser_dbg-features-breakable-positions.js (10244B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 "use strict"; 6 7 const testServer = createVersionizedHttpTestServer( 8 "../examples/sourcemaps-reload-uncompressed" 9 ); 10 const TEST_URL = testServer.urlFor("index.html"); 11 12 // getTokenFromPosition pauses 0.5s for each line, 13 // so this test is quite slow to complete 14 requestLongerTimeout(10); 15 16 /** 17 * Cover the breakpoints positions/columns: 18 * - assert that the UI displayed markers in CodeMirror next to each breakable columns, 19 * - assert the data in the reducers about the breakable columns. 20 * 21 * Note that it doesn't assert that the breakpoint can be hit. 22 * It only verify data integrity and the UI. 23 */ 24 add_task(async function testBreakableLinesOverReloads() { 25 const dbg = await initDebuggerWithAbsoluteURL( 26 TEST_URL, 27 "index.html", 28 "script.js", 29 "original.js" 30 ); 31 32 info("Assert breakable lines of the first html page load"); 33 await assertBreakablePositions(dbg, "index.html", 85, [ 34 { line: 16, columns: [6, 14] }, 35 { line: 17, columns: [] }, 36 { line: 21, columns: [12, 20, 48] }, 37 { line: 24, columns: [12, 20] }, 38 { line: 25, columns: [] }, 39 { line: 30, columns: [] }, 40 { line: 36, columns: [] }, 41 { line: 39, columns: [] }, 42 { line: 41, columns: [8, 18] }, 43 { line: 42, columns: [] }, 44 { line: 43, columns: [] }, 45 ]); 46 47 info("Pretty print first html page load and assert breakable lines"); 48 await togglePrettyPrint(dbg); 49 await assertBreakablePositions(dbg, "index.html:formatted", 96, [ 50 { line: 16, columns: [0, 8] }, 51 { line: 22, columns: [0, 8, 35] }, 52 { line: 27, columns: [0, 8] }, 53 { line: 28, columns: [] }, 54 { line: 36, columns: [] }, 55 { line: 48, columns: [] }, 56 { line: 50, columns: [2, 12] }, 57 { line: 53, columns: [] }, 58 ]); 59 await closeTab(dbg, "index.html:formatted"); 60 61 info("Assert breakable lines of the first original source file, original.js"); 62 // The length of original.js is longer than the test file 63 // because the sourcemap replaces the content of the original file 64 // and appends a few lines with a "WEBPACK FOOTER" comment 65 // All the appended lines are empty lines or comments, so none of them are breakable. 66 await assertBreakablePositions(dbg, "original.js", 15, [ 67 { line: 1, columns: [] }, 68 { line: 2, columns: [2, 9, 32] }, 69 { line: 3, columns: [] }, 70 { line: 5, columns: [] }, 71 { line: 8, columns: [2, 8] }, 72 { line: 9, columns: [2, 10] }, 73 { line: 10, columns: [] }, 74 ]); 75 76 info("Assert breakable lines of the simple first load of script.js"); 77 await assertBreakablePositions(dbg, "script.js", 9, [ 78 { line: 1, columns: [0, 8] }, 79 { line: 5, columns: [2, 10] }, 80 { line: 7, columns: [2, 9] }, 81 { line: 8, columns: [] }, 82 { line: 9, columns: [] }, 83 ]); 84 85 info("Pretty print first load of script.js and assert breakable lines"); 86 await togglePrettyPrint(dbg); 87 await assertBreakablePositions(dbg, "script.js:formatted", 8, [ 88 { line: 1, columns: [0, 8] }, 89 { line: 4, columns: [2, 10] }, 90 { line: 6, columns: [2, 9] }, 91 { line: 7, columns: [] }, 92 ]); 93 await closeTab(dbg, "script.js:formatted"); 94 95 info( 96 "Reload the page, wait for sources and assert that breakable lines get updated" 97 ); 98 testServer.switchToNextVersion(); 99 await reload(dbg, "index.html", "script.js", "original.js"); 100 101 info("Assert breakable lines of the more complex second load of script.js"); 102 await assertBreakablePositions(dbg, "script.js", 23, [ 103 { line: 2, columns: [0, 8] }, 104 { line: 13, columns: [4, 12] }, 105 { line: 14, columns: [] }, 106 { line: 15, columns: [] }, 107 { line: 16, columns: [] }, 108 { line: 17, columns: [] }, 109 { line: 18, columns: [2, 10] }, 110 { line: 19, columns: [] }, 111 { line: 20, columns: [] }, 112 { line: 21, columns: [] }, 113 { line: 22, columns: [] }, 114 { line: 23, columns: [] }, 115 ]); 116 117 info("Pretty print first load of script.js and assert breakable lines"); 118 await togglePrettyPrint(dbg); 119 await assertBreakablePositions(dbg, "script.js:formatted", 23, [ 120 { line: 2, columns: [0, 8] }, 121 { line: 13, columns: [4, 12] }, 122 { line: 14, columns: [] }, 123 { line: 15, columns: [] }, 124 { line: 16, columns: [] }, 125 { line: 17, columns: [] }, 126 { line: 18, columns: [2, 10] }, 127 { line: 19, columns: [] }, 128 { line: 20, columns: [] }, 129 { line: 21, columns: [] }, 130 { line: 22, columns: [] }, 131 ]); 132 await closeTab(dbg, "script.js:formatted"); 133 134 info("Assert breakable lines of the second html page load"); 135 await assertBreakablePositions(dbg, "index.html", 33, [ 136 { line: 25, columns: [6, 14] }, 137 { line: 27, columns: [] }, 138 ]); 139 140 info("Pretty print second html page load and assert breakable lines"); 141 await togglePrettyPrint(dbg); 142 await assertBreakablePositions(dbg, "index.html:formatted", 33, [ 143 { line: 25, columns: [0, 8] }, 144 ]); 145 await closeTab(dbg, "index.html:formatted"); 146 147 info("Assert breakable lines of the second orignal file"); 148 // See first assertion about original.js, 149 // the size of original.js doesn't match the size of the test file 150 await assertBreakablePositions(dbg, "original.js", 18, [ 151 { line: 1, columns: [] }, 152 { line: 2, columns: [2, 9, 32] }, 153 { line: 3, columns: [] }, 154 { line: 8, columns: [] }, 155 { line: 9, columns: [2, 8] }, 156 { line: 10, columns: [2, 10] }, 157 { line: 11, columns: [] }, 158 { line: 13, columns: [0, 8] }, 159 ]); 160 }); 161 162 async function assertBreakablePositions( 163 dbg, 164 file, 165 numberOfLines, 166 breakablePositions 167 ) { 168 await selectSource(dbg, file); 169 is( 170 getLineCount(dbg), 171 numberOfLines, 172 `We show the expected number of lines in CodeMirror for ${file}` 173 ); 174 for (let line = 1; line <= numberOfLines; line++) { 175 info(`Asserting line #${line}`); 176 const positions = breakablePositions.find( 177 position => position.line == line 178 ); 179 // If we don't have any position, only assert that the line isn't breakable 180 if (!positions) { 181 await assertLineIsBreakable(dbg, file, line, false); 182 continue; 183 } 184 const { columns } = positions; 185 // Otherwise, set a breakpoint on the line to ensure we force fetching the breakable columns per line 186 // (this is only fetch on-demand) 187 await addBreakpointViaGutter(dbg, line); 188 await assertBreakpoint(dbg, line); 189 const source = findSource(dbg, file); 190 191 // If there is no column breakpoint, skip all further assertions 192 // Last lines of inline script are reported as breakable lines and selectors reports 193 // one breakable column, but, we don't report any available column breakpoint for them. 194 if (!columns.length) { 195 // So, only ensure that there really is no marker on this line 196 const lineElement = await getTokenFromPosition(dbg, { line }); 197 const columnMarkers = lineElement.querySelectorAll(".column-breakpoint"); 198 is( 199 columnMarkers.length, 200 0, 201 `There is no breakable columns on line ${line}` 202 ); 203 await removeBreakpoint(dbg, source.id, line); 204 continue; 205 } 206 207 const selectorPositions = dbg.selectors.getBreakpointPositionsForSource( 208 source.id 209 ); 210 ok(selectorPositions, "Selector returned positions"); 211 const selectorPositionsForLine = selectorPositions[line]; 212 ok(selectorPositionsForLine, "Selector returned positions for the line"); 213 is( 214 selectorPositionsForLine.length, 215 columns.length, 216 "Selector has the expected number of breakable columns" 217 ); 218 for (const selPos of selectorPositionsForLine) { 219 is( 220 selPos.location.line, 221 line, 222 "Selector breakable column has the right line" 223 ); 224 ok( 225 columns.includes(selPos.location.column), 226 `Selector breakable column has an expected column (${ 227 selPos.location.column 228 } in ${JSON.stringify(columns)}) for line ${line}` 229 ); 230 is( 231 selPos.location.source.id, 232 source.id, 233 "Selector breakable column has the right source id" 234 ); 235 is( 236 selPos.location.source.url, 237 source.url, 238 "Selector breakable column has the right source url" 239 ); 240 } 241 242 const tokenElement = await getTokenFromPosition(dbg, { line }); 243 const lineElement = tokenElement.closest(".cm-line"); 244 // Those are the breakpoint chevron we click on to set a breakpoint on a given column 245 const columnMarkers = [ 246 ...lineElement.querySelectorAll(".column-breakpoint"), 247 ]; 248 is( 249 columnMarkers.length, 250 columns.length, 251 "Got the expeced number of column markers" 252 ); 253 254 // The first breakable column received the line breakpoint when calling addBreakpoint() 255 const firstColumn = columns[0]; 256 ok( 257 findColumnBreakpoint(dbg, file, line, firstColumn), 258 `The first column ${firstColumn} has a breakpoint automatically` 259 ); 260 261 for (const [index, column] of Object.entries(columns)) { 262 const columnMarkerIndex = Number(index); 263 // The first column breakpoint is shifted 264 if (columnMarkerIndex == 0) { 265 continue; 266 } 267 ok( 268 !findColumnBreakpoint(dbg, file, line, column), 269 `Before clicking on the marker, the column ${column} was not having a breakpoint` 270 ); 271 272 const onSetBreakpoint = waitForDispatch(dbg.store, "SET_BREAKPOINT"); 273 let marker = getColumnMarker(lineElement, columnMarkerIndex); 274 marker.click(); 275 await onSetBreakpoint; 276 ok( 277 findColumnBreakpoint(dbg, file, line, column), 278 `Was able to set column breakpoint for ${file} @ ${line}:${column}` 279 ); 280 281 const onRemoveBreakpoint = waitForDispatch( 282 dbg.store, 283 "REMOVE_BREAKPOINT" 284 ); 285 marker = getColumnMarker(lineElement, columnMarkerIndex); 286 marker.click(); 287 await onRemoveBreakpoint; 288 289 ok( 290 !findColumnBreakpoint(dbg, file, line, column), 291 `Removed the just-added column breakpoint` 292 ); 293 } 294 295 await removeBreakpoint(dbg, source.id, line); 296 } 297 } 298 299 function getColumnMarker(lineElement, index) { 300 return lineElement.querySelectorAll(".column-breakpoint")[index]; 301 }