browser_dbg-project-search.js (8617B)
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 // Testing various project search features 6 7 "use strict"; 8 9 requestLongerTimeout(3); 10 11 add_task(async function testProjectSearchCloseOnNavigation() { 12 const dbg = await initDebugger( 13 "doc-script-switching.html", 14 "script-switching-01.js" 15 ); 16 17 await selectSource(dbg, "script-switching-01.js"); 18 19 await openProjectSearch(dbg); 20 21 ok( 22 !findElement(dbg, "projectSearchRefreshButton"), 23 "The refresh button is only visible after having done a search" 24 ); 25 26 await doProjectSearch(dbg, "function", 2); 27 28 is(getExpandedResultsCount(dbg), 6); 29 30 is(dbg.selectors.getActiveSearch(), "project"); 31 32 const refreshButton = findElement(dbg, "projectSearchRefreshButton"); 33 ok( 34 refreshButton, 35 "Refresh button is visible right after search is completed" 36 ); 37 ok( 38 !refreshButton.classList.contains("highlight"), 39 "Refresh button is *not* highlighted by default" 40 ); 41 42 await navigate(dbg, "doc-scripts.html"); 43 44 // Project search is still visible after navigation 45 is(dbg.selectors.getActiveSearch(), "project"); 46 // With same search results 47 is(getExpandedResultsCount(dbg), 6); 48 49 ok( 50 refreshButton.classList.contains("highlight"), 51 "Refresh button is highlighted after navigation" 52 ); 53 54 info("Try to open a discarded source"); 55 await clickElement(dbg, "fileMatch"); 56 57 info("Wait for the warning popup to be visible"); 58 // We are waiting for the popup to be added... 59 await waitFor(() => dbg.win.document.querySelector(".unavailable-source")); 60 // ...and verify that the popup is made visible. 61 await waitFor(() => dbg.win.document.querySelector(".tooltip-shown")); 62 info("Retry to open the discard source, this should hide the popup"); 63 await clickElement(dbg, "fileMatch"); 64 info("Wait for the popup to be hidden"); 65 // Note that .unavailable-source won't be removed from the DOM 66 await waitFor(() => !dbg.win.document.querySelector(".tooltip-visible")); 67 68 info("Refresh results against the new page"); 69 refreshButton.click(); 70 71 // Wait for the search to be updated against the new page 72 await waitForSearchResults(dbg, 5); 73 is(getExpandedResultsCount(dbg), 39); 74 ok( 75 !refreshButton.classList.contains("highlight"), 76 "Refresh button is no longer highlighted after refreshing the search" 77 ); 78 }); 79 80 add_task(async function testSimpleProjectSearch() { 81 // Start with side panel collapsed so we can assert that the project search keyboard 82 // shortcut will open it. 83 await pushPref("devtools.debugger.start-panel-collapsed", true); 84 85 const dbg = await initDebugger( 86 "doc-script-switching.html", 87 "script-switching-01.js" 88 ); 89 90 await openProjectSearch(dbg); 91 92 ok( 93 !!findElementWithSelector(dbg, ".project-text-search"), 94 "Project search is visible" 95 ); 96 97 const searchTerm = "first"; 98 await doProjectSearch(dbg, searchTerm, 1); 99 100 const queryMatch = findElement(dbg, "fileMatch").querySelector( 101 ".query-match" 102 ); 103 is( 104 queryMatch.innerText, 105 searchTerm, 106 "The highlighted text matches the search term" 107 ); 108 109 info("Select a result match to open the location in the source"); 110 await clickElement(dbg, "fileMatch"); 111 await waitForSelectedSource(dbg, "script-switching-01.js"); 112 113 info("Close start sidebar"); 114 const startPanelToggleButtonEl = findElementWithSelector( 115 dbg, 116 ".toggle-button.start" 117 ); 118 startPanelToggleButtonEl.click(); 119 await waitFor(() => startPanelToggleButtonEl.classList.contains("collapsed")); 120 121 info("Try to open project search again"); 122 await openProjectSearch(dbg); 123 ok( 124 !!findElementWithSelector(dbg, ".project-text-search"), 125 "Project search is visible" 126 ); 127 }); 128 129 add_task(async function testMatchesForRegexSearches() { 130 const dbg = await initDebugger("doc-react.html", "App.js"); 131 await openProjectSearch(dbg); 132 133 type(dbg, "import .* from 'react'"); 134 await clickElement(dbg, "projectSearchModifiersRegexMatch"); 135 136 await waitForSearchResults(dbg, 2); 137 138 const queryMatch = findAllElements(dbg, "fileMatch")[1].querySelector( 139 ".query-match" 140 ); 141 142 is( 143 queryMatch.innerText, 144 "import React, { Component } from 'react'", 145 "The highlighted text matches the search term" 146 ); 147 148 // Turn off the regex modifier so does not break tests below 149 await clickElement(dbg, "projectSearchModifiersRegexMatch"); 150 }); 151 152 // Test expanding search results to reveal the search matches. 153 add_task(async function testExpandSearchResultsToShowMatches() { 154 const dbg = await initDebugger("doc-react.html", "App.js"); 155 156 await openProjectSearch(dbg); 157 await doProjectSearch(dbg, "we", 19); 158 159 is(getExpandedResultsCount(dbg), 159); 160 161 const collapsedNodes = findAllElements(dbg, "projectSearchCollapsed"); 162 is(collapsedNodes.length, 1); 163 164 collapsedNodes[0].click(); 165 166 is(getExpandedResultsCount(dbg), 367); 167 }); 168 169 add_task(async function testSearchModifiers() { 170 const dbg = await initDebugger("doc-react.html", "App.js"); 171 172 await openProjectSearch(dbg); 173 174 await assertProjectSearchModifier( 175 dbg, 176 "projectSearchModifiersCaseSensitive", 177 "FIELDS", 178 "case sensitive", 179 { resultWithModifierOn: 0, resultWithModifierOff: 2 } 180 ); 181 await assertProjectSearchModifier( 182 dbg, 183 "projectSearchModifiersRegexMatch", 184 `\\*`, 185 "regex match", 186 { resultWithModifierOn: 12, resultWithModifierOff: 0 } 187 ); 188 await assertProjectSearchModifier( 189 dbg, 190 "projectSearchModifiersWholeWordMatch", 191 "so", 192 "whole word match", 193 { resultWithModifierOn: 6, resultWithModifierOff: 16 } 194 ); 195 }); 196 197 add_task(async function testSearchExcludePatterns() { 198 const dbg = await initDebugger("doc-react.html", "App.js"); 199 200 info("Search across all files"); 201 await openProjectSearch(dbg); 202 let fileResults = await doProjectSearch(dbg, "console", 5); 203 204 let resultsFromNodeModules = [...fileResults].filter(result => 205 result.innerText.includes("node_modules") 206 ); 207 208 is( 209 resultsFromNodeModules.length, 210 3, 211 "3 results were found from node_modules" 212 ); 213 214 info("Excludes search results based on multiple search patterns"); 215 216 await clickElement(dbg, "excludePatternsInput"); 217 type(dbg, "App.js, main.js"); 218 pressKey(dbg, "Enter"); 219 220 fileResults = await waitForSearchResults(dbg, 3); 221 222 const resultsFromAppJS = [...fileResults].filter(result => 223 result.innerText.includes("App.js") 224 ); 225 226 is(resultsFromAppJS.length, 0, "None of the results is from the App.js file"); 227 228 const resultsFromMainJS = [...fileResults].filter(result => 229 result.innerText.includes("main.js") 230 ); 231 232 is( 233 resultsFromMainJS.length, 234 0, 235 "None of the results is from the main.js file" 236 ); 237 238 info("Excludes search results from node modules files"); 239 240 await clearElement(dbg, "excludePatternsInput"); 241 type(dbg, "**/node_modules/**"); 242 pressKey(dbg, "Enter"); 243 244 fileResults = await waitForSearchResults(dbg, 2); 245 246 resultsFromNodeModules = [...fileResults].filter(result => 247 result.innerText.includes("node_modules") 248 ); 249 250 is( 251 resultsFromNodeModules.length, 252 0, 253 "None of the results is from the node modules files" 254 ); 255 256 info("Assert that the exclude pattern is persisted across reloads"); 257 await reloadBrowser(); 258 await openProjectSearch(dbg); 259 260 const excludePatternsInputElement = await waitForElement( 261 dbg, 262 "excludePatternsInput" 263 ); 264 265 is( 266 excludePatternsInputElement.value, 267 "**/node_modules/**", 268 "The exclude pattern for node modules is persisted accross reloads" 269 ); 270 271 // Clear the fields so that it does not impact on the subsequent tests 272 await clearElement(dbg, "projectSearchSearchInput"); 273 await clearElement(dbg, "excludePatternsInput"); 274 pressKey(dbg, "Enter"); 275 }); 276 277 async function assertProjectSearchModifier( 278 dbg, 279 searchModifierBtn, 280 searchTerm, 281 title, 282 expected 283 ) { 284 info(`Assert ${title} search modifier`); 285 286 type(dbg, searchTerm); 287 info(`Turn on the ${title} search modifier option`); 288 await clickElement(dbg, searchModifierBtn); 289 let results = await waitForSearchResults(dbg, expected.resultWithModifierOn); 290 is( 291 results.length, 292 expected.resultWithModifierOn, 293 `${results.length} results where found` 294 ); 295 296 info(`Turn off the ${title} search modifier`); 297 await clickElement(dbg, searchModifierBtn); 298 299 results = await waitForSearchResults(dbg, expected.resultWithModifierOff); 300 is( 301 results.length, 302 expected.resultWithModifierOff, 303 `${results.length} results where found` 304 ); 305 await clearElement(dbg, "projectSearchSearchInput"); 306 }