tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_inspector_search-suggests-pseudo.js (5403B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 "use strict";
      4 
      5 // Test that the selector-search input proposes pseudo elements
      6 
      7 const TEST_URL = `<h1>Hello</h1>`;
      8 
      9 add_task(async function () {
     10  const { inspector } = await openInspectorForURL(
     11    "data:text/html;charset=utf-8," + encodeURI(TEST_URL)
     12  );
     13 
     14  const TESTS = [
     15    {
     16      input: ":",
     17      // we don't want to test the exact items that are suggested, as the test would fail
     18      // when new pseudo are added in the platform.
     19      // Only includes some items that should be suggested (`included`),
     20      // and some that should not be (`notIncluded`)
     21      suggestions: {
     22        included: [":active", ":empty", ":focus"],
     23        notIncluded: ["::selection", "::marker"],
     24      },
     25      inputAfterAcceptingSuggestion: ":active",
     26    },
     27    {
     28      // For now we don't support searching for pseudo element (Bug 1097991),
     29      // so the list should be empty
     30      input: "::",
     31      suggestions: {
     32        included: [],
     33      },
     34    },
     35    {
     36      input: "h1:",
     37      suggestions: {
     38        included: ["h1:active", "h1:empty", "h1:focus"],
     39        notIncluded: ["h1::selection", "h1::marker"],
     40      },
     41      inputAfterAcceptingSuggestion: "h1:active",
     42    },
     43    {
     44      input: "h1:not",
     45      suggestions: {
     46        included: ["h1:not("],
     47        notIncluded: ["h1:nth-child("],
     48      },
     49      inputAfterAcceptingSuggestion: "h1:not(",
     50    },
     51    {
     52      input: "h1:empty:",
     53      suggestions: {
     54        included: ["h1:empty:active", "h1:empty:empty", "h1:empty:focus"],
     55        notIncluded: ["h1::selection", "h1::marker"],
     56      },
     57      inputAfterAcceptingSuggestion: "h1:empty:active",
     58    },
     59    {
     60      input: "h1:empty:no",
     61      suggestions: {
     62        included: ["h1:empty:not("],
     63        notIncluded: ["h1:empty:nth-child("],
     64      },
     65      inputAfterAcceptingSuggestion: "h1:empty:not(",
     66    },
     67    {
     68      input: "body > h1:",
     69      suggestions: {
     70        included: ["body > h1:active", "body > h1:empty", "body > h1:focus"],
     71        notIncluded: ["body > h1::selection", "body > h1::marker"],
     72      },
     73      inputAfterAcceptingSuggestion: "body > h1:active",
     74    },
     75    {
     76      input: "body > h1:no",
     77      suggestions: {
     78        included: ["body > h1:not("],
     79        notIncluded: ["body > h1:nth-child("],
     80      },
     81      inputAfterAcceptingSuggestion: "body > h1:not(",
     82    },
     83  ];
     84 
     85  info("Focus the search box");
     86  await focusSearchBoxUsingShortcut(inspector.panelWin);
     87 
     88  const searchInputEl = inspector.panelWin.document.getElementById(
     89    "inspector-searchbox"
     90  );
     91  const { searchPopup } = inspector.searchSuggestions;
     92 
     93  for (const { input, suggestions, inputAfterAcceptingSuggestion } of TESTS) {
     94    info(`Checking suggestions for "${input}"`);
     95 
     96    const onPopupOpened = searchPopup.once("popup-opened");
     97    // the query for getting suggestions is not throttled and is fired for every char
     98    // being typed, so we avoid using EventUtils.sendString for the whole input to avoid
     99    // dealing with multiple events. Instead, put the value directly in the input, and only
    100    // type the last char.
    101    const onProcessingDone =
    102      inspector.searchSuggestions.once("processing-done");
    103    searchInputEl.value = input.substring(0, input.length - 1);
    104    EventUtils.sendChar(input.at(-1), inspector.panelWin);
    105    info("Wait for search query to complete");
    106    await onProcessingDone;
    107 
    108    const actualSuggestions = Array.from(
    109      searchPopup.list.querySelectorAll("li")
    110    ).map(li => li.textContent);
    111 
    112    if (!suggestions.included.length) {
    113      const res = await Promise.race([
    114        onPopupOpened,
    115        wait(1000).then(() => "TIMEOUT"),
    116      ]);
    117      is(res, "TIMEOUT", "popup did not open");
    118    } else {
    119      await onPopupOpened;
    120      ok(true, "suggestions popup opened");
    121    }
    122 
    123    for (const expectedLabel of suggestions.included) {
    124      ok(
    125        actualSuggestions.some(s => s === expectedLabel),
    126        `"${expectedLabel}" is in the list of suggestions for "${input}" (full list: ${JSON.stringify(actualSuggestions)})`
    127      );
    128    }
    129 
    130    for (const unexpectedLabel of suggestions.notIncluded || []) {
    131      ok(
    132        !actualSuggestions.some(s => s === unexpectedLabel),
    133        `"${unexpectedLabel}" is not in the list of suggestions for "${input}"`
    134      );
    135    }
    136 
    137    if (inputAfterAcceptingSuggestion) {
    138      info("Press tab to fill the search input with the first suggestion");
    139      const onSuggestionAccepted =
    140        inspector.searchSuggestions.once("processing-done");
    141      const onPopupClosed = searchPopup.once("popup-closed");
    142      EventUtils.synthesizeKey("VK_TAB", {}, inspector.panelWin);
    143      await onSuggestionAccepted;
    144      await onPopupClosed;
    145 
    146      is(
    147        searchInputEl.value,
    148        inputAfterAcceptingSuggestion,
    149        "input has expected value after accepting suggestion"
    150      );
    151    }
    152 
    153    info("Clear the input");
    154    const onSearchCleared = inspector.search.once("search-cleared");
    155    const onEmptySearchSuggestionProcessingDone =
    156      inspector.searchSuggestions.once("processing-done");
    157 
    158    // select the whole input and hit backspace to clear it
    159    searchInputEl.setSelectionRange(0, searchInputEl.value.length);
    160    EventUtils.synthesizeKey("VK_BACK_SPACE", {}, inspector.panelWin);
    161    await onSearchCleared;
    162    await onEmptySearchSuggestionProcessingDone;
    163  }
    164 });