tor-browser

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

test_jsterm_autocomplete.html (25914B)


      1 <!DOCTYPE HTML>
      2 <html lang="en">
      3 <head>
      4  <meta charset="utf8">
      5  <title>Test for JavaScript terminal functionality</title>
      6  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      7  <script type="text/javascript" src="common.js"></script>
      8  <!-- Any copyright is dedicated to the Public Domain.
      9     - http://creativecommons.org/publicdomain/zero/1.0/ -->
     10 </head>
     11 <body>
     12 <p>Test for JavaScript terminal autocomplete functionality</p>
     13 
     14 <script class="testbody" type="text/javascript">
     15  "use strict";
     16 
     17  SimpleTest.waitForExplicitFinish();
     18  const {
     19    MAX_AUTOCOMPLETE_ATTEMPTS,
     20    MAX_AUTOCOMPLETIONS
     21  } = require("devtools/shared/webconsole/js-property-provider");
     22  const RESERVED_JS_KEYWORDS = require("devtools/shared/webconsole/reserved-js-words");
     23 
     24 
     25  addEventListener("load", startTest);
     26 
     27  async function startTest() {
     28    // First run the tests with a tab as a target.
     29    let {state} = await attachConsoleToTab(["PageError"]);
     30    await performTests({state, isWorker: false});
     31 
     32    // Then run the tests with a worker as a target.
     33    state = (await attachConsoleToWorker(["PageError"])).state;
     34    await performTests({state, isWorker: true});
     35 
     36    SimpleTest.finish();
     37  }
     38 
     39  async function performTests({state, isWorker}) {
     40    // Set up the global variables needed to test autocompletion in the target.
     41    const script = `
     42      // This is for workers so autocomplete acts the same
     43      if (!this.window) {
     44        window = this;
     45      }
     46 
     47      window.foobarObject = Object.create(null);
     48      window.foobarObject.foo = 1;
     49      window.foobarObject.foobar = 2;
     50      window.foobarObject.foobaz = 3;
     51      window.foobarObject.omg = 4;
     52      window.foobarObject.omgfoo = 5;
     53      window.foobarObject.strfoo = "foobarz";
     54      window.foobarObject.omgstr = "foobarz" +
     55        (new Array(${DevToolsServer.LONG_STRING_LENGTH})).join("abb");
     56      window.largeObject1 = Object.create(null);
     57      for (let i = 0; i < ${MAX_AUTOCOMPLETE_ATTEMPTS + 1}; i++) {
     58        window.largeObject1['a' + i] = i;
     59      }
     60 
     61      window.largeObject2 = Object.create(null);
     62      for (let i = 0; i < ${MAX_AUTOCOMPLETIONS * 2}; i++) {
     63        window.largeObject2['a' + i] = i;
     64      }
     65 
     66      window.proxy1 = new Proxy({foo: 1}, {
     67        getPrototypeOf() { throw new Error() }
     68      });
     69      window.proxy2 = new Proxy(Object.create(Object.create(null, {foo:{}})), {
     70        ownKeys() { throw new Error() }
     71      });
     72      window.emojiObject = Object.create(null);
     73      window.emojiObject["😎"] = "😎";
     74 
     75      window.insensitiveTestCase = Object.create(null, Object.getOwnPropertyDescriptors({
     76        PROP: "",
     77        Prop: "",
     78        prop: "",
     79        PRÖP: "",
     80        pröp: "",
     81      }));
     82 
     83      window.elementAccessTestCase = Object.create(null, Object.getOwnPropertyDescriptors({
     84        bar: "",
     85        BAR: "",
     86        dataTest: "",
     87        "data-test": "",
     88        'da"ta"test': "",
     89        'da\`ta\`test': "",
     90        "da'ta'test": "",
     91      }));
     92 
     93      window.varify = true;
     94 
     95      var Cu_Sandbox = Cu ? Cu.Sandbox : null;
     96    `;
     97    await evaluateExpression(state.webConsoleFront, script);
     98 
     99    const tests = [
    100      doAutocomplete1,
    101      doAutocomplete2,
    102      doAutocomplete3,
    103      doAutocomplete4,
    104      doAutocompleteLarge1,
    105      doAutocompleteLarge2,
    106      doAutocompleteProxyThrowsPrototype,
    107      doAutocompleteProxyThrowsOwnKeys,
    108      doAutocompleteDotSurroundedBySpaces,
    109      doAutocompleteAfterOr,
    110      doInsensitiveAutocomplete,
    111      doElementAccessAutocomplete,
    112      doAutocompleteAfterOperator,
    113      dontAutocompleteAfterDeclaration,
    114      doKeywordsAutocomplete,
    115      dontAutocomplete,
    116    ];
    117 
    118    if (!isWorker) {
    119      // `Cu` is not defined in workers, then we can't test `Cu.Sandbox`
    120      tests.push(doAutocompleteSandbox);
    121      // Some cases are handled in worker context because we can't use parser.js.
    122      // See Bug 1507181.
    123      tests.push(
    124        doAutocompleteArray,
    125        doAutocompleteString,
    126        doAutocompleteCommands,
    127        doAutocompleteBracketSurroundedBySpaces,
    128      );
    129    }
    130 
    131    for (const test of tests) {
    132      await test(state.webConsoleFront);
    133    }
    134 
    135    // Null out proxy1 and proxy2: the proxy handlers use scripted functions
    136    // that can keep the debugger sandbox alive longer than necessary via their
    137    // environment chain (due to the webconsole helper functions defined there).
    138    await evaluateExpression(state.webConsoleFront, `this.proxy1 = null; this.proxy2 = null;`);
    139 
    140    await closeDebugger(state);
    141  }
    142 
    143  async function doAutocomplete1(webConsoleFront) {
    144    info("test autocomplete for 'window.foo'");
    145    const response = await webConsoleFront.autocomplete("window.foo");
    146    const matches = response.matches;
    147 
    148    is(response.matchProp, "foo", "matchProp");
    149    is(matches.length, 1, "matches.length");
    150    is(matches[0], "foobarObject", "matches[0]");
    151  }
    152 
    153  async function doAutocomplete2(webConsoleFront) {
    154    info("test autocomplete for 'window.foobarObject.'");
    155    const response = await webConsoleFront.autocomplete("window.foobarObject.");
    156    const matches = response.matches;
    157 
    158    ok(!response.matchProp, "matchProp");
    159    is(matches.length, 7, "matches.length");
    160    checkObject(matches,
    161      ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
    162  }
    163 
    164  async function doAutocomplete3(webConsoleFront) {
    165    // Check that completion suggestions are offered inside the string.
    166    info("test autocomplete for 'dump(window.foobarObject.)'");
    167    const response = await webConsoleFront.autocomplete("dump(window.foobarObject.)", 25);
    168    const matches = response.matches;
    169 
    170    ok(!response.matchProp, "matchProp");
    171    is(matches.length, 7, "matches.length");
    172    checkObject(matches,
    173      ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
    174  }
    175 
    176  async function doAutocomplete4(webConsoleFront) {
    177    // Check that completion requests can have no suggestions.
    178    info("test autocomplete for 'dump(window.foobarObject.)'");
    179    const response = await webConsoleFront.autocomplete("dump(window.foobarObject.)");
    180    ok(!response.matchProp, "matchProp");
    181    is(response.matches, null, "matches is null");
    182  }
    183 
    184  async function doAutocompleteLarge1(webConsoleFront) {
    185    // Check that completion requests with too large objects will
    186    // have no suggestions.
    187    info("test autocomplete for 'window.largeObject1.'");
    188    const response = await webConsoleFront.autocomplete("window.largeObject1.");
    189    ok(!response.matchProp, "matchProp");
    190    info (response.matches.join("|"));
    191    is(response.matches.length, 0, "Bailed out with too many properties");
    192  }
    193 
    194  async function doAutocompleteLarge2(webConsoleFront) {
    195    // Check that completion requests with pretty large objects will
    196    // have MAX_AUTOCOMPLETIONS suggestions
    197    info("test autocomplete for 'window.largeObject2.'");
    198    const response = await webConsoleFront.autocomplete("window.largeObject2.");
    199    ok(!response.matchProp, "matchProp");
    200    is(response.matches.length, MAX_AUTOCOMPLETIONS, "matches.length is MAX_AUTOCOMPLETIONS");
    201  }
    202 
    203  async function doAutocompleteProxyThrowsPrototype(webConsoleFront) {
    204    // Check that completion provides own properties even if [[GetPrototypeOf]] throws.
    205    info("test autocomplete for 'window.proxy1.'");
    206    const response = await webConsoleFront.autocomplete("window.proxy1.");
    207    ok(!response.matchProp, "matchProp");
    208    is(response.matches.length, 14, "matches.length");
    209    ok(response.matches.includes("foo"), "matches has own property for proxy with throwing getPrototypeOf trap");
    210  }
    211 
    212  async function doAutocompleteProxyThrowsOwnKeys(webConsoleFront) {
    213    // Check that completion provides inherited properties even if [[OwnPropertyKeys]] throws.
    214    info("test autocomplete for 'window.proxy2.'");
    215    const response = await webConsoleFront.autocomplete("window.proxy2.");
    216    ok(!response.matchProp, "matchProp");
    217    is(response.matches.length, 1, "matches.length");
    218    checkObject(response.matches, ["foo"]);
    219  }
    220 
    221  async function doAutocompleteSandbox(webConsoleFront) {
    222    // Check that completion provides inherited properties even if [[OwnPropertyKeys]] throws.
    223    info("test autocomplete for 'Cu_Sandbox.'");
    224    const response = await webConsoleFront.autocomplete("Cu_Sandbox.");
    225    ok(!response.matchProp, "matchProp");
    226    const keys = Object.getOwnPropertyNames(Object.prototype).sort();
    227    is(response.matches.length, keys.length, "matches.length");
    228    // checkObject(response.matches, keys);
    229    is(response.matches.join(" - "), keys.join(" - "));
    230  }
    231 
    232  async function doAutocompleteArray(webConsoleFront) {
    233    info("test autocomplete for [1,2,3]");
    234    const response = await webConsoleFront.autocomplete("[1,2,3].");
    235    let {matches} = response;
    236 
    237    ok(!!matches.length, "There are completion results for the array");
    238    ok(matches.includes("length") && matches.includes("filter"),
    239      "Array autocomplete contains expected results");
    240 
    241    info("test autocomplete for '[] . '");
    242    matches = (await webConsoleFront.autocomplete("[] . ")).matches;
    243    ok(matches.length > 1);
    244    ok(matches.includes("length") && matches.includes("filter"),
    245      "Array autocomplete contains expected results");
    246    ok(!matches.includes("copy"), "Array autocomplete does not contain helpers");
    247 
    248    info("test autocomplete for '[1,2,3]['");
    249    matches = (await webConsoleFront.autocomplete("[1,2,3][")).matches;
    250    ok(matches.length > 1);
    251    ok(matches.includes('"length"') && matches.includes('"filter"'),
    252      "Array autocomplete contains expected results, surrounded by quotes");
    253 
    254    info("test autocomplete for '[1,2,3]['");
    255    matches = (await webConsoleFront.autocomplete("[1,2,3]['")).matches;
    256    ok(matches.length > 1);
    257    ok(matches.includes("'length'") && matches.includes("'filter'"),
    258      "Array autocomplete contains expected results, surrounded by quotes");
    259 
    260    info("test autocomplete for '[1,2,3][l");
    261    matches = (await webConsoleFront.autocomplete("[1,2,3][l")).matches;
    262    ok(matches.length >= 1);
    263    ok(matches.includes('"length"'),
    264      "Array autocomplete contains expected results, surrounded by quotes");
    265 
    266    info("test autocomplete for '[1,2,3]['l");
    267    matches = (await webConsoleFront.autocomplete("[1,2,3]['l")).matches;
    268    ok(matches.length >= 1);
    269    ok(matches.includes("'length'"),
    270      "Array autocomplete contains expected results, surrounded by quotes");
    271  }
    272 
    273  async function doAutocompleteString(webConsoleFront) {
    274    info(`test autocomplete for "foo".`);
    275    const response = await webConsoleFront.autocomplete(`"foo".`);
    276    let {matches} = response;
    277 
    278    ok(!!matches.length, "There are completion results for the string");
    279    ok(matches.includes("substr") && matches.includes("trim"),
    280      "String autocomplete contains expected results");
    281 
    282    info("test autocomplete for `foo`[");
    283    matches = (await webConsoleFront.autocomplete("`foo`[")).matches;
    284    ok(matches.length > 1, "autocomplete string with bracket works");
    285    ok(matches.includes('"substr"') && matches.includes('"trim"'),
    286      "String autocomplete contains expected results, surrounded by quotes");
    287  }
    288 
    289  async function doAutocompleteDotSurroundedBySpaces(webConsoleFront) {
    290    info("test autocomplete for 'window.foobarObject\n  .'");
    291    let {matches} = await webConsoleFront.autocomplete("window.foobarObject\n  .");
    292    is(matches.length, 7);
    293    checkObject(matches,
    294      ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
    295 
    296    info("test autocomplete for 'window.foobarObject\n  .o'");
    297    matches = (await webConsoleFront.autocomplete("window.foobarObject\n  .o")).matches;
    298    is(matches.length, 3);
    299    checkObject(matches, ["omg", "omgfoo", "omgstr"]);
    300 
    301    info("test autocomplete for 'window.foobarObject\n  .\n  s'");
    302    matches = (await webConsoleFront.autocomplete("window.foobarObject\n  .\n  s")).matches;
    303    is(matches.length, 1);
    304    checkObject(matches, ["strfoo"]);
    305 
    306    info("test autocomplete for 'window.foobarObject\n  .  '");
    307    matches = (await webConsoleFront.autocomplete("window.foobarObject\n  .  ")).matches;
    308    is(matches.length, 7);
    309    checkObject(matches,
    310      ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
    311 
    312    matches =
    313      (await webConsoleFront.autocomplete("window.foobarObject.  foo ; window.foo")).matches;
    314    is(matches.length, 1);
    315    checkObject(matches, ["foobarObject"]);
    316  }
    317 
    318  async function doAutocompleteBracketSurroundedBySpaces(webConsoleFront) {
    319    const wrap = (arr, quote = `"`) => arr.map(x => `${quote}${x}${quote}`);
    320    let matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n  [")
    321    is(matches.length, 7);
    322    checkObject(matches,
    323      wrap(["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]));
    324 
    325    matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n  ['o")
    326    is(matches.length, 3);
    327    checkObject(matches, wrap(["omg", "omgfoo", "omgstr"], "'"));
    328 
    329    matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n  [\n  s");
    330    is(matches.length, 1);
    331    checkObject(matches, [`"strfoo"`]);
    332 
    333    matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n  [  ");
    334    is(matches.length, 7);
    335    checkObject(matches,
    336      wrap(["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]));
    337 
    338    matches = await getAutocompleteMatches(webConsoleFront, "window.emojiObject  [   '");
    339    is(matches.length, 1);
    340    checkObject(matches, [`'😎'`]);
    341  }
    342 
    343  async function doAutocompleteAfterOr(webConsoleFront) {
    344    info("test autocomplete for 'true || foo'");
    345    const {matches} = await webConsoleFront.autocomplete("true || foobar");
    346    is(matches.length, 1, "autocomplete returns expected results");
    347    is(matches.join("-"), "foobarObject");
    348  }
    349 
    350  async function doInsensitiveAutocomplete(webConsoleFront) {
    351    info("test autocomplete for 'window.insensitiveTestCase.'");
    352    let {matches} = await webConsoleFront.autocomplete("window.insensitiveTestCase.");
    353    is(matches.join("-"), "prop-pröp-Prop-PROP-PRÖP",
    354      "autocomplete returns the expected items, in the expected order");
    355 
    356    info("test autocomplete for 'window.insensitiveTestCase.p'");
    357    matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.p")).matches;
    358    is(matches.join("-"), "prop-pröp-Prop-PROP-PRÖP",
    359      "autocomplete is case-insensitive when first letter is lowercased");
    360 
    361    info("test autocomplete for 'window.insensitiveTestCase.pRoP'");
    362    matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.pRoP")).matches;
    363    is(matches.join("-"), "prop-Prop-PROP",
    364      "autocomplete is case-insensitive when first letter is lowercased");
    365 
    366    info("test autocomplete for 'window.insensitiveTestCase.P'");
    367    matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.P")).matches;
    368    is(matches.join("-"), "Prop-PROP-PRÖP",
    369      "autocomplete is case-sensitive when first letter is uppercased");
    370 
    371    info("test autocomplete for 'window.insensitiveTestCase.PROP'");
    372    matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.PROP")).matches;
    373    is(matches.join("-"), "PROP",
    374      "autocomplete is case-sensitive when first letter is uppercased");
    375 
    376    info("test autocomplete for 'window.insensitiveTestCase.prö'");
    377    matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.prö")).matches;
    378    is(matches.join("-"), "pröp-PRÖP", "expected result with lowercase diacritic");
    379 
    380    info("test autocomplete for 'window.insensitiveTestCase.PRÖ'");
    381    matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.PRÖ")).matches;
    382    is(matches.join("-"), "PRÖP", "expected result with uppercase diacritic");
    383  }
    384 
    385  async function doElementAccessAutocomplete(webConsoleFront) {
    386    info("test autocomplete for 'window.elementAccessTestCase['");
    387    let res = (await webConsoleFront.autocomplete("window.elementAccessTestCase["));
    388    is(
    389      res.matches.join("|"),
    390      `"bar"|"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"|"BAR"`,
    391      "autocomplete returns the expected items, wrapped in quotes");
    392    is(res.isElementAccess, true);
    393 
    394    info("test autocomplete for 'window.elementAccessTestCase[d'");
    395    res = await webConsoleFront.autocomplete("window.elementAccessTestCase[d");
    396    is(
    397      res.matches.join("|"),
    398      `"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"`,
    399      "autocomplete returns the expected filtered items");
    400    is(res.isElementAccess, true);
    401 
    402    info(`test autocomplete for 'window.elementAccessTestCase["d'`);
    403    res = await webConsoleFront.autocomplete(`window.elementAccessTestCase["d`);
    404    is(
    405      res.matches.join("|"),
    406      `"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"`,
    407      "autocomplete returns the expected items, wrapped in quotes");
    408    is(res.isElementAccess, true);
    409 
    410    info(`test autocomplete for 'window.elementAccessTestCase["data-`);
    411    res = await webConsoleFront.autocomplete(`window.elementAccessTestCase["data-`);
    412    is(res.matches.join("|"), `"data-test"`,
    413      "autocomplete returns the expected items, wrapped in quotes");
    414    is(res.isElementAccess, true);
    415 
    416    info(`test autocomplete for 'window.elementAccessTestCase['d'`);
    417    res = await webConsoleFront.autocomplete(`window.elementAccessTestCase['d`);
    418    is(
    419      res.matches.join("|"),
    420      `'da"ta"test'|'da\\'ta\\'test'|'da\`ta\`test'|'data-test'|'dataTest'`,
    421      "autocomplete returns the expected items, wrapped in the same quotes the user entered");
    422    is(res.isElementAccess, true);
    423 
    424    info("test autocomplete for 'window.elementAccessTestCase[`d'");
    425    res = await webConsoleFront.autocomplete("window.elementAccessTestCase[`d");
    426    is(
    427      res.matches.join("|"),
    428      "`da'ta'test`|`da\"ta\"test`|`da\\`ta\\`test`|`data-test`|`dataTest`",
    429      "autocomplete returns the expected items, wrapped in the same quotes the user entered");
    430    is(res.isElementAccess, true);
    431 
    432    info(`test autocomplete for '['`);
    433    res = await webConsoleFront.autocomplete(`[`);
    434    is(res.matches, null, "it does not return anything");
    435 
    436    info(`test autocomplete for '[1,2,3'`);
    437    res = await webConsoleFront.autocomplete(`[1,2,3`);
    438    is(res.matches, null, "it does not return anything");
    439 
    440    info(`test autocomplete for '["'`);
    441    res = await webConsoleFront.autocomplete(`["`);
    442    is(res.matches, null, "it does not return anything");
    443 
    444    info(`test autocomplete for '[;'`);
    445    res = await webConsoleFront.autocomplete(`[;`);
    446    is(res.matches, null, "it does not return anything");
    447  }
    448 
    449  async function doAutocompleteCommands(webConsoleFront) {
    450    info("test autocomplete for 'c'");
    451    let matches = (await webConsoleFront.autocomplete("c")).matches;
    452    ok(matches.includes("clear"), "commands are returned");
    453 
    454    info("test autocomplete for 's'");
    455    matches = (await webConsoleFront.autocomplete("s")).matches;
    456    is(matches.includes("screenshot"), false, "screenshot is not returned");
    457 
    458    info("test autocomplete for ':s'");
    459    matches = (await webConsoleFront.autocomplete(":s")).matches;
    460    is(matches.includes(":screenshot"), true, "screenshot is returned");
    461 
    462    info("test autocomplete for 'window.c'");
    463    matches = (await webConsoleFront.autocomplete("window.c")).matches;
    464    ok(!matches.includes("clear"), "commands are not returned");
    465 
    466    info("test autocomplete for 'window[c'");
    467    matches = (await webConsoleFront.autocomplete("window[c")).matches;
    468    ok(!matches.includes("clear"), "commands are not returned");
    469 
    470    info(`test autocomplete for 'window["c'`);
    471    matches = (await webConsoleFront.autocomplete(`window["c`)).matches;
    472    ok(!matches.includes("clear"), "commands are not returned");
    473 
    474    info(`test autocomplete for 'window["c'`);
    475    matches = (await webConsoleFront.autocomplete(`window["c`)).matches;
    476    ok(!matches.includes("clear"), "commands are not returned");
    477 
    478    info(`test autocomplete for 'window[";c'`);
    479    matches = (await webConsoleFront.autocomplete(`window[";c`)).matches;
    480    ok(!matches.includes("clear"), "commands are not returned");
    481 
    482    info(`test autocomplete for 'window[;c'`);
    483    matches = (await webConsoleFront.autocomplete(`window[;c`)).matches;
    484    ok(!matches.includes("clear"), "commands are not returned");
    485  }
    486 
    487  async function doAutocompleteAfterOperator(webConsoleFront) {
    488    const inputs = [
    489      "true;foob",
    490      "true,foob",
    491      "({key:foob",
    492      "a=foob",
    493      "if(a<foob",
    494      "if(a>foob",
    495      "1+foob",
    496      "1-foob",
    497      "++foob",
    498      "--foob",
    499      "1*foob",
    500      "2**foob",
    501      "1/foob",
    502      "1%foob",
    503      "1|foob",
    504      "1&foob",
    505      "1^foob",
    506      "~foob",
    507      "1<<foob",
    508      "1>>foob",
    509      "1>>>foob",
    510      "false||foob",
    511      "false&&foob",
    512      "x=true?foob",
    513      "x=false?1:foob",
    514      "!foob",
    515      "false??foob",
    516    ];
    517 
    518    for (const input of inputs) {
    519      info(`test autocomplete for "${input}"`);
    520      const matches = (await webConsoleFront.autocomplete(input)).matches;
    521      ok(matches.includes("foobarObject"), `Expected autocomplete result for ${input}"`);
    522    }
    523  }
    524 
    525  async function dontAutocompleteAfterDeclaration(webConsoleFront) {
    526    info("test autocomplete for 'var win'");
    527    let matches = (await webConsoleFront.autocomplete("var win")).matches;
    528    is(matches, null, "no autocompletion on a var declaration");
    529 
    530    info("test autocomplete for 'const win'");
    531    matches = (await webConsoleFront.autocomplete("const win")).matches;
    532    is(matches, null, "no autocompletion on a const declaration");
    533 
    534    info("test autocomplete for 'let win'");
    535    matches = (await webConsoleFront.autocomplete("let win")).matches;
    536    is(matches, null, "no autocompletion on a let declaration");
    537 
    538    info("test autocomplete for 'function win'");
    539    matches = (await webConsoleFront.autocomplete("function win")).matches;
    540    is(matches, null, "no autocompletion on a function declaration");
    541 
    542    info("test autocomplete for 'class win'");
    543    matches = (await webConsoleFront.autocomplete("class win")).matches;
    544    is(matches, null, "no autocompletion on a class declaration");
    545 
    546    info("test autocomplete for 'using win'");
    547    matches = (await webConsoleFront.autocomplete("using win")).matches;
    548    is(matches, null, `no autocompletion on a "using" declaration`);
    549 
    550    info("test autocomplete for 'const win = win'");
    551    matches = (await webConsoleFront.autocomplete("const win = win")).matches;
    552    ok(matches.includes("window"), "autocompletion still happens after the `=` sign");
    553 
    554    info("test autocomplete for 'in var'");
    555    matches = (await webConsoleFront.autocomplete("in var")).matches;
    556    ok(matches.includes("varify"),
    557      "autocompletion still happens with a property name starting with 'var'");
    558 }
    559 
    560 async function doKeywordsAutocomplete(webConsoleFront) {
    561  info("test autocomplete for 'va'");
    562  let matches = (await webConsoleFront.autocomplete("va")).matches;
    563  ok(matches.includes("var"), `"var" keyword is returned`);
    564 
    565  info("test autocomplete for 'le'");
    566  matches = (await webConsoleFront.autocomplete("le")).matches;
    567  ok(matches.includes("let"), `"let" keyword is returned`);
    568 
    569  info("test autocomplete for 'co'");
    570  matches = (await webConsoleFront.autocomplete("co")).matches;
    571  ok(matches.includes("const"), `"const" keyword is returned`);
    572 
    573  info("test autocomplete for 'cl'");
    574  matches = (await webConsoleFront.autocomplete("cl")).matches;
    575  ok(matches.includes("class"), `"class" keyword is returned`);
    576 
    577  info("test autocomplete for 'us'");
    578  matches = (await webConsoleFront.autocomplete("us")).matches;
    579  ok(matches.includes("using"), `"using" keyword is returned`);
    580 
    581  info("test autocomplete for 'func'");
    582  matches = (await webConsoleFront.autocomplete("func")).matches;
    583  ok(matches.includes("function"), "keywords are returned");
    584 
    585  info("test autocomplete for ':func'");
    586  matches = (await webConsoleFront.autocomplete(":func")).matches;
    587  is(!matches.includes("function"), true,
    588    "'function' is not returned when prefixed with ':'");
    589 
    590  info("test autocomplete for 'window.func'");
    591  matches = (await webConsoleFront.autocomplete("window.func")).matches;
    592  ok(!matches.includes("function"),
    593    "'function' is not returned when doing a property access");
    594 
    595  info("test autocomplete for 'window[func'");
    596  matches = (await webConsoleFront.autocomplete("window[func")).matches;
    597  ok(!matches.includes("function"),
    598    "'function' is not returned when doing an element access");
    599  }
    600 
    601  async function dontAutocomplete(webConsoleFront) {
    602    const inputs = [
    603      "",
    604      "       ",
    605      "\n",
    606      "\n  ",
    607      "  \n  ",
    608      "  \n",
    609      "true;",
    610      "true,",
    611      "({key:",
    612      "a=",
    613      "if(a<",
    614      "if(a>",
    615      "1+",
    616      "1-",
    617      "++",
    618      "--",
    619      "1*",
    620      "2**",
    621      "1/",
    622      "1%",
    623      "1|",
    624      "1&",
    625      "1^",
    626      "~",
    627      "1<<",
    628      "1>>",
    629      "1>>>",
    630      "false||",
    631      "false&&",
    632      "x=true?",
    633      "x=false?1:",
    634      "!",
    635      ...RESERVED_JS_KEYWORDS.map(keyword => `${keyword} `),
    636      ...RESERVED_JS_KEYWORDS.map(keyword => `${keyword}  `),
    637    ];
    638    for (const input of inputs) {
    639      info(`test autocomplete for "${input}"`);
    640      const matches = (await webConsoleFront.autocomplete(input)).matches;
    641      is(matches, null, `No autocomplete result for ${input}"`);
    642    }
    643  }
    644 
    645  async function getAutocompleteMatches(webConsoleFront, input) {
    646    info(`test autocomplete for "${input}"`);
    647    const res = (await webConsoleFront.autocomplete(input));
    648    return res.matches;
    649  }
    650 
    651  async function evaluateExpression(consoleFront, expression) {
    652    const onEvaluationResult = consoleFront.once("evaluationResult");
    653    await consoleFront.evaluateJSAsync({ text: expression });
    654    return onEvaluationResult;
    655  }
    656 
    657 </script>
    658 </body>
    659 </html>