Bug 1547821 - Sync 133 - Improve Quick Open performance r=jlast
authorSorin Davidoi <sorin.davidoi@protonmail.com>
Thu, 09 May 2019 16:09:47 +0000
changeset 532086 b744a5e29a890770389de37e94d1c2ffa305fc2b
parent 532085 78f94fc80dc1e114146d106b58667f2989d3b3b5
child 532087 28b74f2993a1d18951938785c3d8e612a10da80c
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlast
bugs1547821
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1547821 - Sync 133 - Improve Quick Open performance r=jlast Differential Revision: https://phabricator.services.mozilla.com/D30306
devtools/client/debugger/src/components/ProjectSearch.js
devtools/client/debugger/src/components/QuickOpenModal.js
devtools/client/debugger/src/components/shared/Popover.css
devtools/client/debugger/src/components/test/QuickOpenModal.spec.js
devtools/client/debugger/src/components/test/__snapshots__/QuickOpenModal.spec.js.snap
devtools/client/debugger/src/utils/quick-open.js
devtools/client/debugger/src/utils/result-list.js
devtools/client/debugger/test/mochitest/browser_dbg-quick-open.js
--- a/devtools/client/debugger/src/components/ProjectSearch.js
+++ b/devtools/client/debugger/src/components/ProjectSearch.js
@@ -172,20 +172,17 @@ export class ProjectSearch extends Compo
     }
   };
 
   onHistoryScroll = (query: string) => {
     this.setState({ inputValue: query });
   };
 
   onEnterPress = () => {
-    if (
-      !this.isProjectSearchEnabled() ||
-      !this.state.focusedItem
-    ) {
+    if (!this.isProjectSearchEnabled() || !this.state.focusedItem) {
       return;
     }
     if (this.state.focusedItem.type === "MATCH") {
       this.selectMatchItem(this.state.focusedItem);
     }
   };
 
   onFocus = (item: Item) => {
--- a/devtools/client/debugger/src/components/QuickOpenModal.js
+++ b/devtools/client/debugger/src/components/QuickOpenModal.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 import React, { Component } from "react";
 import { connect } from "../utils/connect";
 import fuzzyAldrin from "fuzzaldrin-plus";
 import { basename } from "../utils/path";
+import { throttle } from "lodash";
 
 import actions from "../actions";
 import {
   getDisplayedSourcesList,
   getQuickOpenEnabled,
   getQuickOpenQuery,
   getQuickOpenType,
   getSelectedSource,
@@ -41,17 +42,17 @@ import type { Source, Context } from "..
 import type { QuickOpenType } from "../reducers/quick-open";
 import type { Tab } from "../reducers/tabs";
 
 import "./QuickOpenModal.css";
 
 type Props = {
   cx: Context,
   enabled: boolean,
-  sources: Array<Object>,
+  displayedSources: Source[],
   selectedSource?: Source,
   selectedContentLoaded?: boolean,
   query: string,
   searchType: QuickOpenType,
   symbols: FormattedSymbolDeclarations,
   symbolsLoading: boolean,
   tabs: Tab[],
   shortcutsModalEnabled: boolean,
@@ -68,22 +69,26 @@ type State = {
 };
 
 type GotoLocationType = {
   sourceId?: string,
   line: number,
   column?: number
 };
 
+const updateResultsThrottle = 100;
 const maxResults = 100;
 
 function filter(values, query) {
+  const preparedQuery = fuzzyAldrin.prepareQuery(query);
+
   return fuzzyAldrin.filter(values, query, {
     key: "value",
-    maxResults: maxResults
+    maxResults: maxResults,
+    preparedQuery
   });
 }
 
 export class QuickOpenModal extends Component<Props, State> {
   constructor(props: Props) {
     super(props);
     this.state = { results: null, selectedIndex: 0 };
   }
@@ -126,17 +131,20 @@ export class QuickOpenModal extends Comp
     this.props.closeQuickOpen();
   };
 
   dropGoto = (query: string) => {
     return query.split(":")[0];
   };
 
   searchSources = (query: string) => {
-    const { sources } = this.props;
+    const { displayedSources, tabs } = this.props;
+    const tabUrls = new Set(tabs.map((tab: Tab) => tab.url));
+    const sources = formatSources(displayedSources, tabUrls);
+
     const results =
       query == "" ? sources : filter(sources, this.dropGoto(query));
     return this.setResults(results);
   };
 
   searchSymbols = (query: string) => {
     const {
       symbols: { functions }
@@ -157,26 +165,34 @@ export class QuickOpenModal extends Comp
     if (query == "?") {
       this.setResults(results);
     } else {
       this.setResults(filter(results, query.slice(1)));
     }
   };
 
   showTopSources = () => {
-    const { tabs, sources } = this.props;
+    const { displayedSources, tabs } = this.props;
+    const tabUrls = new Set(tabs.map((tab: Tab) => tab.url));
+
     if (tabs.length > 0) {
-      const tabUrls = tabs.map((tab: Tab) => tab.url);
-      this.setResults(sources.filter(source => tabUrls.includes(source.url)));
+      this.setResults(
+        formatSources(
+          displayedSources.filter(
+            source => !!source.url && tabUrls.has(source.url)
+          ),
+          tabUrls
+        )
+      );
     } else {
-      this.setResults(sources);
+      this.setResults(formatSources(displayedSources, tabUrls));
     }
   };
 
-  updateResults = (query: string) => {
+  updateResults = throttle((query: string) => {
     if (this.isGotoQuery()) {
       return;
     }
 
     if (query == "" && !this.isShortcutQuery()) {
       return this.showTopSources();
     }
 
@@ -184,17 +200,17 @@ export class QuickOpenModal extends Comp
       return this.searchSymbols(query);
     }
 
     if (this.isShortcutQuery()) {
       return this.searchShortcuts(query);
     }
 
     return this.searchSources(query);
-  };
+  }, updateResultsThrottle);
 
   setModifier = (item: QuickOpenResult) => {
     if (["@", "#", ":"].includes(item.id)) {
       this.props.setQuickOpenQuery(item.id);
     }
   };
 
   selectResultItem = (
@@ -426,30 +442,31 @@ export class QuickOpenModal extends Comp
     );
   }
 }
 
 /* istanbul ignore next: ignoring testing of redux connection stuff */
 function mapStateToProps(state) {
   const selectedSource = getSelectedSource(state);
   const displayedSources = getDisplayedSourcesList(state);
+  const tabs = getTabs(state);
 
   return {
     cx: getContext(state),
     enabled: getQuickOpenEnabled(state),
-    sources: formatSources(displayedSources, getTabs(state)),
+    displayedSources,
     selectedSource,
     selectedContentLoaded: selectedSource
       ? !!getSourceContent(state, selectedSource.id)
       : undefined,
     symbols: formatSymbols(getSymbols(state, selectedSource)),
     symbolsLoading: isSymbolsLoading(state, selectedSource),
     query: getQuickOpenQuery(state),
     searchType: getQuickOpenType(state),
-    tabs: getTabs(state)
+    tabs
   };
 }
 
 /* istanbul ignore next: ignoring testing of redux connection stuff */
 export default connect(
   mapStateToProps,
   {
     selectSpecificLocation: actions.selectSpecificLocation,
--- a/devtools/client/debugger/src/components/shared/Popover.css
+++ b/devtools/client/debugger/src/components/shared/Popover.css
@@ -27,9 +27,9 @@
 }
 
 .popover:not(.orientation-right) .preview-popup {
   margin-left: -55px;
 }
 
 .popover .add-to-expression-bar {
   margin-left: -55px;
-}
\ No newline at end of file
+}
--- a/devtools/client/debugger/src/components/test/QuickOpenModal.spec.js
+++ b/devtools/client/debugger/src/components/test/QuickOpenModal.spec.js
@@ -1,31 +1,37 @@
 /* eslint max-nested-callbacks: ["error", 4] */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import React from "react";
+import lodash from "lodash";
+
 import { shallow, mount } from "enzyme";
 import { QuickOpenModal } from "../QuickOpenModal";
 import { mockcx } from "../../utils/test-mockup";
 
 jest.mock("fuzzaldrin-plus");
+jest.unmock("lodash");
 
 import { filter } from "fuzzaldrin-plus";
 
+// $FlowIgnore
+lodash.throttle = jest.fn(fn => fn);
+
 function generateModal(propOverrides, renderType = "shallow") {
   const props = {
     cx: mockcx,
     enabled: false,
     query: "",
     searchType: "sources",
-    sources: [],
+    displayedSources: [],
     tabs: [],
     selectSpecificLocation: jest.fn(),
     setQuickOpenQuery: jest.fn(),
     highlightLineRange: jest.fn(),
     clearHighlightLineRange: jest.fn(),
     closeQuickOpen: jest.fn(),
     shortcutsModalEnabled: false,
     symbols: { functions: [] },
@@ -108,22 +114,34 @@ describe("QuickOpenModal", () => {
     expect(props.toggleShortcutsModal).toHaveBeenCalled();
   });
 
   test("shows top sources", () => {
     const { wrapper } = generateModal(
       {
         enabled: true,
         query: "",
-        sources: [{ url: "mozilla.com" }],
+        displayedSources: [
+          // $FlowIgnore
+          { url: "mozilla.com", relativeUrl: true }
+        ],
         tabs: [generateTab("mozilla.com")]
       },
       "shallow"
     );
-    expect(wrapper.state("results")).toEqual([{ url: "mozilla.com" }]);
+    expect(wrapper.state("results")).toEqual([
+      {
+        id: undefined,
+        icon: "tab result-item-icon",
+        subtitle: "true",
+        title: "mozilla.com",
+        url: "mozilla.com",
+        value: "true"
+      }
+    ]);
   });
 
   describe("shows loading", () => {
     it("loads with function type search", () => {
       const { wrapper } = generateModal(
         {
           enabled: true,
           query: "",
--- a/devtools/client/debugger/src/components/test/__snapshots__/QuickOpenModal.spec.js.snap
+++ b/devtools/client/debugger/src/components/test/__snapshots__/QuickOpenModal.spec.js.snap
@@ -4,25 +4,25 @@ exports[`QuickOpenModal Basic render wit
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query="@"
   searchType="functions"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
       "variables": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
@@ -135,25 +135,25 @@ exports[`QuickOpenModal Basic render wit
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query="#"
   searchType="variables"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
       "variables": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
@@ -250,25 +250,25 @@ exports[`QuickOpenModal Basic render wit
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=""
   searchType="sources"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -415,25 +415,25 @@ exports[`QuickOpenModal Simple goto sear
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=":abc"
   searchType="goto"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
       "variables": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
@@ -535,25 +535,25 @@ exports[`QuickOpenModal showErrorEmoji f
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query="dasdasdas"
   searchType="sources"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -697,25 +697,25 @@ exports[`QuickOpenModal showErrorEmoji f
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=":2222"
   searchType="goto"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -816,25 +816,25 @@ exports[`QuickOpenModal showErrorEmoji f
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=""
   searchType=""
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -946,25 +946,25 @@ exports[`QuickOpenModal showErrorEmoji t
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=":22k22"
   searchType="goto"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -1065,25 +1065,25 @@ exports[`QuickOpenModal showErrorEmoji t
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query="test"
   searchType=""
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -1212,25 +1212,25 @@ exports[`QuickOpenModal updateResults on
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={false}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=""
   searchType="sources"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
@@ -1242,25 +1242,25 @@ exports[`QuickOpenModal updateResults on
 <QuickOpenModal
   clearHighlightLineRange={[MockFunction]}
   closeQuickOpen={[MockFunction]}
   cx={
     Object {
       "navigateCounter": 0,
     }
   }
+  displayedSources={Array []}
   enabled={true}
   highlightLineRange={[MockFunction]}
   isOriginal={false}
   query=""
   searchType="sources"
   selectSpecificLocation={[MockFunction]}
   setQuickOpenQuery={[MockFunction]}
   shortcutsModalEnabled={false}
-  sources={Array []}
   symbols={
     Object {
       "functions": Array [],
     }
   }
   symbolsLoading={false}
   tabs={Array []}
   thread="FakeThread"
--- a/devtools/client/debugger/src/utils/quick-open.js
+++ b/devtools/client/debugger/src/utils/quick-open.js
@@ -10,17 +10,17 @@ import {
   getFilename,
   getSourceClassnames,
   getSourceQueryString
 } from "./source";
 
 import type { Location as BabelLocation } from "@babel/types";
 import type { Symbols } from "../reducers/ast";
 import type { QuickOpenType } from "../reducers/quick-open";
-import type { TabList } from "../reducers/tabs";
+import type { Tab } from "../reducers/tabs";
 import type { Source } from "../types";
 import type {
   SymbolDeclaration,
   IdentifierDeclaration
 } from "../workers/parser";
 
 export const MODIFIERS = {
   "@": "functions",
@@ -54,28 +54,31 @@ export function parseLineColumn(query: s
   if (!isNaN(lineNumber)) {
     return {
       line: lineNumber,
       ...(!isNaN(columnNumber) ? { column: columnNumber } : null)
     };
   }
 }
 
-export function formatSourcesForList(source: Source, tabs: TabList) {
+export function formatSourcesForList(
+  source: Source,
+  tabUrls: Set<$PropertyType<Tab, "url">>
+) {
   const title = getFilename(source);
   const relativeUrlWithQuery = `${source.relativeUrl}${getSourceQueryString(
     source
   ) || ""}`;
   const subtitle = endTruncateStr(relativeUrlWithQuery, 100);
   const value = relativeUrlWithQuery;
   return {
     value,
     title,
     subtitle,
-    icon: tabs.some(tab => tab.url == source.url)
+    icon: tabUrls.has(source.url)
       ? "tab result-item-icon"
       : classnames(getSourceClassnames(source), "result-item-icon"),
     id: source.id,
     url: source.url
   };
 }
 
 export type QuickOpenResult = {|
@@ -133,15 +136,15 @@ export function formatShortcutResults():
       title: `: ${L10N.getStr("gotoLineModal.placeholder")}`,
       id: ":"
     }
   ];
 }
 
 export function formatSources(
   sources: Source[],
-  tabs: TabList
+  tabUrls: Set<$PropertyType<Tab, "url">>
 ): Array<QuickOpenResult> {
   return sources
     .filter(source => !isPretty(source))
-    .filter(({ relativeUrl }) => !!relativeUrl)
-    .map(source => formatSourcesForList(source, tabs));
+    .filter(source => !!source.relativeUrl && !isPretty(source))
+    .map(source => formatSourcesForList(source, tabUrls));
 }
--- a/devtools/client/debugger/src/utils/result-list.js
+++ b/devtools/client/debugger/src/utils/result-list.js
@@ -37,17 +37,23 @@ export function scrollList(
 
 function chromeScrollList(elem: Element, index: number): void {
   const resultsEl: any = elem.parentNode;
 
   if (!resultsEl || resultsEl.children.length === 0) {
     return;
   }
 
-  const resultsHeight: number = resultsEl.clientHeight;
-  const itemHeight: number = resultsEl.children[0].clientHeight;
-  const numVisible: number = resultsHeight / itemHeight;
-  const positionsToScroll: number = index - numVisible + 1;
-  const itemOffset: number = resultsHeight % itemHeight;
-  const scroll: number = positionsToScroll * (itemHeight + 2) + itemOffset;
+  // Avoid expensive DOM computations (reading clientHeight)
+  // https://nolanlawson.com/2018/09/25/accurately-measuring-layout-on-the-web/
+  requestAnimationFrame(() => {
+    setTimeout(() => {
+      const resultsHeight: number = resultsEl.clientHeight;
+      const itemHeight: number = resultsEl.children[0].clientHeight;
+      const numVisible: number = resultsHeight / itemHeight;
+      const positionsToScroll: number = index - numVisible + 1;
+      const itemOffset: number = resultsHeight % itemHeight;
+      const scroll: number = positionsToScroll * (itemHeight + 2) + itemOffset;
 
-  resultsEl.scrollTop = Math.max(0, scroll);
+      resultsEl.scrollTop = Math.max(0, scroll);
+    });
+  });
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg-quick-open.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg-quick-open.js
@@ -35,20 +35,22 @@ async function waitToClose(dbg) {
   pressKey(dbg, "Escape");
   return new Promise(r => setTimeout(r, 200));
 }
 
 function resultCount(dbg) {
   return findAllElements(dbg, "resultItems").length;
 }
 
-function quickOpen(dbg, query, shortcut = "quickOpen") {
+async function quickOpen(dbg, query, shortcut = "quickOpen") {
   pressKey(dbg, shortcut);
   assertEnabled(dbg);
   query !== "" && type(dbg, query);
+
+  await waitForTime(150);
 }
 
 function findResultEl(dbg, index = 1) {
   return waitForElementWithSelector(dbg, `.result-item:nth-child(${index})`);
 }
 
 async function assertResultIsTab(dbg, index) {
   const el = await findResultEl(dbg, index);
@@ -58,67 +60,68 @@ async function assertResultIsTab(dbg, in
   );
 }
 
 // Testing quick open
 add_task(async function() {
   const dbg = await initDebugger("doc-script-switching.html");
 
   info("test opening and closing");
-  quickOpen(dbg, "");
+  await quickOpen(dbg, "");
   pressKey(dbg, "Escape");
   assertDisabled(dbg);
 
   info("Testing the number of results for source search");
-  quickOpen(dbg, "sw");
+  await quickOpen(dbg, "sw");
   is(resultCount(dbg), 2, "two file results");
   pressKey(dbg, "Escape");
 
   info("Testing source search and check to see if source is selected");
   await waitForSource(dbg, "switching-01");
-  quickOpen(dbg, "sw1");
+  await quickOpen(dbg, "sw1");
   is(resultCount(dbg), 1, "one file results");
   pressKey(dbg, "Enter");
   await waitForSelectedSource(dbg, "switching-01");
 
   info("Test that results show tab icons");
-  quickOpen(dbg, "sw1");
+  await quickOpen(dbg, "sw1");
   await assertResultIsTab(dbg, 1);
   pressKey(dbg, "Tab");
 
   info(
     "Testing arrow keys in source search and check to see if source is selected"
   );
-  quickOpen(dbg, "sw2");
+  await quickOpen(dbg, "sw2");
   is(resultCount(dbg), 1, "one file results");
   pressKey(dbg, "Down");
   pressKey(dbg, "Enter");
   await waitForSelectedSource(dbg, "switching-02");
 
   info("Testing tab closes the search");
-  quickOpen(dbg, "sw");
+  await quickOpen(dbg, "sw");
   pressKey(dbg, "Tab");
   assertDisabled(dbg);
 
   info("Testing function search");
-  quickOpen(dbg, "", "quickOpenFunc");
+  await quickOpen(dbg, "", "quickOpenFunc");
   is(resultCount(dbg), 2, "two function results");
 
   type(dbg, "@x");
+  await waitForTime(150);
   is(resultCount(dbg), 0, "no functions with 'x' in name");
 
   pressKey(dbg, "Escape");
   assertDisabled(dbg);
 
   info("Testing goto line:column");
   assertLine(dbg, 0);
   assertColumn(dbg, null);
-  quickOpen(dbg, ":7:12");
+  await quickOpen(dbg, ":7:12");
   pressKey(dbg, "Enter");
   assertLine(dbg, 7);
   assertColumn(dbg, 12);
 
   info("Testing gotoSource");
-  quickOpen(dbg, "sw1:5");
+  await quickOpen(dbg, "sw1:5");
   pressKey(dbg, "Enter");
   await waitForSelectedSource(dbg, "switching-01");
   assertLine(dbg, 5);
 });