browser_dbg-editor-scroll.js (9714B)
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 // Tests that the editor keeps proper scroll position per document 6 // while also moving to the correct location upon pause/breakpoint selection 7 8 "use strict"; 9 10 // This test runs too slowly on linux debug. I'd like to figure out 11 // which is the slowest part of this and make it run faster, but to 12 // fix a frequent failure allow a longer timeout. 13 requestLongerTimeout(2); 14 15 /** 16 * Test some simple usecases where the editor should scroll to the paused location 17 * and remember the previously scrolled location when switching between two distinct sources. 18 */ 19 add_task(async function testScrollingOnPauseAndSourceSwitching() { 20 const dbg = await initDebugger( 21 "doc-editor-scroll.html", 22 "scroll.js", 23 "long.js" 24 ); 25 26 // Set the initial breakpoint. 27 await selectSource(dbg, "scroll.js"); 28 await addBreakpoint(dbg, "scroll.js", 26); 29 30 info("Open long file, scroll down to line below the fold"); 31 await selectSource(dbg, "long.js"); 32 33 // Make sure we have a real scroll event emitted. 34 // scrollEditorIntoView will bail out after 500ms but here we need to 35 // guarantee the scroll event was processed by CodeMirror, because this is 36 // when the viewport location gets saved. 37 const ensureScroll = waitForScrolling(dbg, { useTimeoutFallback: false }); 38 39 await scrollEditorIntoView(dbg, 25, 0); 40 ok(isScrolledPositionVisible(dbg, 25), "Scroll position is visible"); 41 42 info("Wait for the codemirror scroll event"); 43 await ensureScroll; 44 45 info("Ensure vertical scroll is the same after switching documents"); 46 let onScrolled = waitForScrolling(dbg); 47 await selectSource(dbg, "scroll.js"); 48 // Wait for any codemirror editor scroll that can happen 49 await onScrolled; 50 ok(isScrolledPositionVisible(dbg, 1), "Scrolled to the top of the editor"); 51 52 onScrolled = waitForScrolling(dbg); 53 await selectSource(dbg, "long.js"); 54 await onScrolled; 55 ok(isScrolledPositionVisible(dbg, 25), "Scroll position is visible"); 56 57 info("Trigger a pause, click on a frame, ensure the right line is selected"); 58 onScrolled = waitForScrolling(dbg); 59 invokeInTab("line26"); 60 await waitForPaused(dbg); 61 await onScrolled; 62 63 ok( 64 isScrolledPositionVisible(dbg, 26), 65 "Frame scrolled down to correct location" 66 ); 67 68 info("Navigating while paused, goes to the correct location"); 69 onScrolled = waitForScrolling(dbg); 70 await selectSource(dbg, "long.js"); 71 await onScrolled; 72 ok(isScrolledPositionVisible(dbg, 25), "Scroll position is visible"); 73 74 info("Open new source, ensure it's at 0 scroll"); 75 onScrolled = waitForScrolling(dbg); 76 await selectSource(dbg, "frames.js"); 77 await onScrolled; 78 ok(isScrolledPositionVisible(dbg, 1), "Scrolled to the top of the editor"); 79 }); 80 81 /** 82 * Some extensive test against Editor's isPositionVisible implementation. 83 * 84 * Assert precisely which lines are considered visible or hidden by this method, 85 * while ensuring that the editor scrolls to the pause location in some edgecases. 86 * For example, when the line is partially visible at the end of the viewport. 87 */ 88 add_task(async function testIsPositionVisible() { 89 // Ensure having the default fixed height, as it can impact the number of displayed lines 90 await pushPref("devtools.toolbox.footer.height", 250); 91 92 // Also set a precise size for side panels, as it can impact the number of displayed columns 93 await pushPref("devtools.debugger.start-panel-size", 300); 94 await pushPref("devtools.debugger.end-panel-size", 300); 95 96 // Strengthen the test by ensuring we always use the same Firefox window size. 97 // Note that the inner size is the important one as that's the final space available for DevTools. 98 // The outer size will be different based on OS/Environment. 99 const expectedWidth = 1280; 100 const expectedHeight = 1040; 101 if ( 102 window.innerWidth != expectedWidth || 103 window.innerHeight != expectedHeight 104 ) { 105 info("Resize the top level window to match the expected size"); 106 const onResize = once(window, "resize"); 107 const deltaW = window.outerWidth - window.innerWidth; 108 const deltaH = window.outerHeight - window.innerHeight; 109 const originalWidth = window.outerWidth; 110 const originalHeight = window.outerHeight; 111 window.resizeTo(expectedWidth + deltaW, expectedHeight + deltaH); 112 await onResize; 113 registerCleanupFunction(() => { 114 window.resizeTo(originalWidth, originalHeight); 115 }); 116 } 117 is(window.innerWidth, expectedWidth); 118 119 const dbg = await initDebugger( 120 "doc-editor-scroll.html", 121 "scroll.js", 122 "long.js" 123 ); 124 125 await selectSource(dbg, "scroll.js"); 126 const editor = getCMEditor(dbg); 127 128 // All the following methods lookup for first/last visible position in the current viewport. 129 // Also note that the element at the returned position may only be partially visible. 130 function getFirstVisibleLine() { 131 const { x, y } = editor.codeMirror.dom.getBoundingClientRect(); 132 // Add a pixel as we may be on the edge of the previous line which is hidden 133 const pos = editor.codeMirror.posAtCoords({ x, y: y + 1 }); 134 return editor.codeMirror.state.doc.lineAt(pos).number; 135 } 136 function getLastVisibleLine() { 137 const { x, y, height } = editor.codeMirror.dom.getBoundingClientRect(); 138 const pos = editor.codeMirror.posAtCoords({ x, y: y + height }); 139 return editor.codeMirror.state.doc.lineAt(pos).number; 140 } 141 const lastLine = getLastVisibleLine(); 142 143 is( 144 lastLine, 145 11, 146 "The last line is the 11th. (it may change if you resize the default browser window height)" 147 ); 148 ok(isScrolledPositionVisible(dbg, 1), "First line is visible"); 149 ok( 150 isScrolledPositionVisible(dbg, lastLine - 1), 151 "The line before the last one is visible" 152 ); 153 ok( 154 !isScrolledPositionVisible(dbg, lastLine), 155 "Last line is partially visible and considered hidden" 156 ); 157 ok( 158 !isScrolledPositionVisible(dbg, lastLine + 1), 159 "The line after the last is hidden" 160 ); 161 162 info( 163 "Set a breakpoint and pause on the last fully visible line, it should not scroll" 164 ); 165 await addBreakpoint(dbg, "scroll.js", lastLine - 1); 166 invokeInTab("line" + (lastLine - 1)); 167 await waitForPaused(dbg); 168 169 ok( 170 !isScrolledPositionVisible(dbg, lastLine), 171 "Last line, which is partially visible, is still hidden" 172 ); 173 174 await resume(dbg); 175 176 info( 177 "Set a breakpoint on the last partially visible line, it should scroll that line in the middle of the viewport" 178 ); 179 await addBreakpoint(dbg, "scroll.js", lastLine); 180 invokeInTab("line" + lastLine); 181 await waitForPaused(dbg); 182 183 const newLastLine = getLastVisibleLine(); 184 is(newLastLine, 16, "The new last line is the 16th"); 185 ok( 186 !isScrolledPositionVisible(dbg, newLastLine), 187 "The new Last line is still partially visible and considered hidden" 188 ); 189 ok( 190 isScrolledPositionVisible(dbg, newLastLine - 1), 191 "The line before is reported as visible" 192 ); 193 const firstLine = getFirstVisibleLine(); 194 is(firstLine, 6); 195 ok( 196 isScrolledPositionVisible(dbg, firstLine + 1), 197 "The next line of the new first line is visible" 198 ); 199 ok( 200 !isScrolledPositionVisible(dbg, firstLine - 1), 201 "The line before the new first line is hidden" 202 ); 203 204 await resume(dbg); 205 206 info( 207 "Set a breakpoint far from the current position, it should also scroll and display the paused line in the middle of the viewport" 208 ); 209 await addBreakpoint(dbg, "scroll.js", 50); 210 invokeInTab("line50"); 211 await waitForPaused(dbg); 212 213 info("Wait for the paused line marker to be visible"); 214 await waitForElementWithSelector(dbg, ".cm-content .paused-line"); 215 216 const newLastLine2 = getLastVisibleLine(); 217 is(newLastLine2, 55); 218 /*ok( 219 !isScrolledPositionVisible(dbg, newLastLine2), 220 "The new last line is partially visible and considered as hidden" 221 );*/ 222 ok( 223 isScrolledPositionVisible(dbg, newLastLine2 - 1), 224 "The line before is visible" 225 ); 226 const firstLine2 = getFirstVisibleLine(); 227 is(firstLine2, 45); 228 ok( 229 isScrolledPositionVisible(dbg, firstLine2 + 1), 230 "The next line of the new first line is visible" 231 ); 232 ok( 233 !isScrolledPositionVisible(dbg, firstLine2 - 1), 234 "The line before the new first line is hidden" 235 ); 236 237 await resume(dbg); 238 }); 239 240 add_task(async function testColumnBreakpointsLimitAfterVerticalScroll() { 241 // Keep the layout consistent 242 await pushPref("devtools.debugger.end-panel-size", 300); 243 await pushPref("devtools.debugger.ui.editor-wrapping", true); 244 245 const dbg = await initDebugger( 246 "doc-large-sources.html", 247 "codemirror-bundle.js" 248 ); 249 250 info("Select the minified bundle and add a breakpoint"); 251 await selectSource(dbg, "codemirror-bundle.js"); 252 await addBreakpoint(dbg, "codemirror-bundle.js", 1); 253 254 let columnBreakpointMarkers = await waitForAllElements( 255 dbg, 256 "columnBreakpoints" 257 ); 258 259 is( 260 columnBreakpointMarkers.length, 261 100, 262 "We have the expected limit of column breakpoint markers on the minified source" 263 ); 264 265 info("Scroll to the bottom of the file"); 266 await scrollEditorIntoView(dbg, 1); 267 268 columnBreakpointMarkers = findAllElements(dbg, "columnBreakpoints"); 269 is( 270 columnBreakpointMarkers.length, 271 0, 272 "There are no column breakpoint markers as the source has vertically scrolled the viewport over the limit" 273 ); 274 275 info("Scroll back to the top of the file"); 276 await scrollEditorIntoView(dbg, 0); 277 278 columnBreakpointMarkers = await waitForAllElements(dbg, "columnBreakpoints"); 279 is( 280 columnBreakpointMarkers.length, 281 100, 282 "We still have the expected limit of column breakpoint markers on the minified source" 283 ); 284 });