summaryrefslogtreecommitdiffstats
path: root/devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html')
-rw-r--r--devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html635
1 files changed, 635 insertions, 0 deletions
diff --git a/devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html b/devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html
new file mode 100644
index 0000000000..bbc9aeb6fc
--- /dev/null
+++ b/devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html
@@ -0,0 +1,635 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+ <meta charset="utf8">
+ <title>Test for JavaScript terminal functionality</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="common.js"></script>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<p>Test for JavaScript terminal autocomplete functionality</p>
+
+<script class="testbody" type="text/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+ const {
+ MAX_AUTOCOMPLETE_ATTEMPTS,
+ MAX_AUTOCOMPLETIONS
+ } = require("devtools/shared/webconsole/js-property-provider");
+ const RESERVED_JS_KEYWORDS = require("devtools/shared/webconsole/reserved-js-words");
+
+
+ addEventListener("load", startTest);
+
+ async function startTest() {
+ // First run the tests with a tab as a target.
+ let {state} = await attachConsoleToTab(["PageError"]);
+ await performTests({state, isWorker: false});
+
+ // Then run the tests with a worker as a target.
+ state = (await attachConsoleToWorker(["PageError"])).state;
+ await performTests({state, isWorker: true});
+
+ SimpleTest.finish();
+ }
+
+ async function performTests({state, isWorker}) {
+ // Set up the global variables needed to test autocompletion in the target.
+ const script = `
+ // This is for workers so autocomplete acts the same
+ if (!this.window) {
+ window = this;
+ }
+
+ window.foobarObject = Object.create(null);
+ window.foobarObject.foo = 1;
+ window.foobarObject.foobar = 2;
+ window.foobarObject.foobaz = 3;
+ window.foobarObject.omg = 4;
+ window.foobarObject.omgfoo = 5;
+ window.foobarObject.strfoo = "foobarz";
+ window.foobarObject.omgstr = "foobarz" +
+ (new Array(${DevToolsServer.LONG_STRING_LENGTH})).join("abb");
+ window.largeObject1 = Object.create(null);
+ for (let i = 0; i < ${MAX_AUTOCOMPLETE_ATTEMPTS + 1}; i++) {
+ window.largeObject1['a' + i] = i;
+ }
+
+ window.largeObject2 = Object.create(null);
+ for (let i = 0; i < ${MAX_AUTOCOMPLETIONS * 2}; i++) {
+ window.largeObject2['a' + i] = i;
+ }
+
+ window.proxy1 = new Proxy({foo: 1}, {
+ getPrototypeOf() { throw new Error() }
+ });
+ window.proxy2 = new Proxy(Object.create(Object.create(null, {foo:{}})), {
+ ownKeys() { throw new Error() }
+ });
+ window.emojiObject = Object.create(null);
+ window.emojiObject["😎"] = "😎";
+
+ window.insensitiveTestCase = Object.create(null, Object.getOwnPropertyDescriptors({
+ PROP: "",
+ Prop: "",
+ prop: "",
+ PRÖP: "",
+ pröp: "",
+ }));
+
+ window.elementAccessTestCase = Object.create(null, Object.getOwnPropertyDescriptors({
+ bar: "",
+ BAR: "",
+ dataTest: "",
+ "data-test": "",
+ 'da"ta"test': "",
+ 'da\`ta\`test': "",
+ "da'ta'test": "",
+ }));
+
+ window.varify = true;
+
+ var Cu_Sandbox = Cu ? Cu.Sandbox : null;
+ `;
+ await evaluateExpression(state.webConsoleFront, script);
+
+ const tests = [
+ doAutocomplete1,
+ doAutocomplete2,
+ doAutocomplete3,
+ doAutocomplete4,
+ doAutocompleteLarge1,
+ doAutocompleteLarge2,
+ doAutocompleteProxyThrowsPrototype,
+ doAutocompleteProxyThrowsOwnKeys,
+ doAutocompleteDotSurroundedBySpaces,
+ doAutocompleteAfterOr,
+ doInsensitiveAutocomplete,
+ doElementAccessAutocomplete,
+ doAutocompleteAfterOperator,
+ dontAutocompleteAfterDeclaration,
+ doKeywordsAutocomplete,
+ dontAutocomplete,
+ ];
+
+ if (!isWorker) {
+ // `Cu` is not defined in workers, then we can't test `Cu.Sandbox`
+ tests.push(doAutocompleteSandbox);
+ // Some cases are handled in worker context because we can't use parser.js.
+ // See Bug 1507181.
+ tests.push(
+ doAutocompleteArray,
+ doAutocompleteString,
+ doAutocompleteCommands,
+ doAutocompleteBracketSurroundedBySpaces,
+ );
+ }
+
+ for (const test of tests) {
+ await test(state.webConsoleFront);
+ }
+
+ // Null out proxy1 and proxy2: the proxy handlers use scripted functions
+ // that can keep the debugger sandbox alive longer than necessary via their
+ // environment chain (due to the webconsole helper functions defined there).
+ await evaluateExpression(state.webConsoleFront, `this.proxy1 = null; this.proxy2 = null;`);
+
+ await closeDebugger(state);
+ }
+
+ async function doAutocomplete1(webConsoleFront) {
+ info("test autocomplete for 'window.foo'");
+ const response = await webConsoleFront.autocomplete("window.foo");
+ const matches = response.matches;
+
+ is(response.matchProp, "foo", "matchProp");
+ is(matches.length, 1, "matches.length");
+ is(matches[0], "foobarObject", "matches[0]");
+ }
+
+ async function doAutocomplete2(webConsoleFront) {
+ info("test autocomplete for 'window.foobarObject.'");
+ const response = await webConsoleFront.autocomplete("window.foobarObject.");
+ const matches = response.matches;
+
+ ok(!response.matchProp, "matchProp");
+ is(matches.length, 7, "matches.length");
+ checkObject(matches,
+ ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
+ }
+
+ async function doAutocomplete3(webConsoleFront) {
+ // Check that completion suggestions are offered inside the string.
+ info("test autocomplete for 'dump(window.foobarObject.)'");
+ const response = await webConsoleFront.autocomplete("dump(window.foobarObject.)", 25);
+ const matches = response.matches;
+
+ ok(!response.matchProp, "matchProp");
+ is(matches.length, 7, "matches.length");
+ checkObject(matches,
+ ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
+ }
+
+ async function doAutocomplete4(webConsoleFront) {
+ // Check that completion requests can have no suggestions.
+ info("test autocomplete for 'dump(window.foobarObject.)'");
+ const response = await webConsoleFront.autocomplete("dump(window.foobarObject.)");
+ ok(!response.matchProp, "matchProp");
+ is(response.matches, null, "matches is null");
+ }
+
+ async function doAutocompleteLarge1(webConsoleFront) {
+ // Check that completion requests with too large objects will
+ // have no suggestions.
+ info("test autocomplete for 'window.largeObject1.'");
+ const response = await webConsoleFront.autocomplete("window.largeObject1.");
+ ok(!response.matchProp, "matchProp");
+ info (response.matches.join("|"));
+ is(response.matches.length, 0, "Bailed out with too many properties");
+ }
+
+ async function doAutocompleteLarge2(webConsoleFront) {
+ // Check that completion requests with pretty large objects will
+ // have MAX_AUTOCOMPLETIONS suggestions
+ info("test autocomplete for 'window.largeObject2.'");
+ const response = await webConsoleFront.autocomplete("window.largeObject2.");
+ ok(!response.matchProp, "matchProp");
+ is(response.matches.length, MAX_AUTOCOMPLETIONS, "matches.length is MAX_AUTOCOMPLETIONS");
+ }
+
+ async function doAutocompleteProxyThrowsPrototype(webConsoleFront) {
+ // Check that completion provides own properties even if [[GetPrototypeOf]] throws.
+ info("test autocomplete for 'window.proxy1.'");
+ const response = await webConsoleFront.autocomplete("window.proxy1.");
+ ok(!response.matchProp, "matchProp");
+ is(response.matches.length, 14, "matches.length");
+ ok(response.matches.includes("foo"), "matches has own property for proxy with throwing getPrototypeOf trap");
+ }
+
+ async function doAutocompleteProxyThrowsOwnKeys(webConsoleFront) {
+ // Check that completion provides inherited properties even if [[OwnPropertyKeys]] throws.
+ info("test autocomplete for 'window.proxy2.'");
+ const response = await webConsoleFront.autocomplete("window.proxy2.");
+ ok(!response.matchProp, "matchProp");
+ is(response.matches.length, 1, "matches.length");
+ checkObject(response.matches, ["foo"]);
+ }
+
+ async function doAutocompleteSandbox(webConsoleFront) {
+ // Check that completion provides inherited properties even if [[OwnPropertyKeys]] throws.
+ info("test autocomplete for 'Cu_Sandbox.'");
+ const response = await webConsoleFront.autocomplete("Cu_Sandbox.");
+ ok(!response.matchProp, "matchProp");
+ const keys = Object.getOwnPropertyNames(Object.prototype).sort();
+ is(response.matches.length, keys.length, "matches.length");
+ // checkObject(response.matches, keys);
+ is(response.matches.join(" - "), keys.join(" - "));
+ }
+
+ async function doAutocompleteArray(webConsoleFront) {
+ info("test autocomplete for [1,2,3]");
+ const response = await webConsoleFront.autocomplete("[1,2,3].");
+ let {matches} = response;
+
+ ok(!!matches.length, "There are completion results for the array");
+ ok(matches.includes("length") && matches.includes("filter"),
+ "Array autocomplete contains expected results");
+
+ info("test autocomplete for '[] . '");
+ matches = (await webConsoleFront.autocomplete("[] . ")).matches;
+ ok(matches.length > 1);
+ ok(matches.includes("length") && matches.includes("filter"),
+ "Array autocomplete contains expected results");
+ ok(!matches.includes("copy"), "Array autocomplete does not contain helpers");
+
+ info("test autocomplete for '[1,2,3]['");
+ matches = (await webConsoleFront.autocomplete("[1,2,3][")).matches;
+ ok(matches.length > 1);
+ ok(matches.includes('"length"') && matches.includes('"filter"'),
+ "Array autocomplete contains expected results, surrounded by quotes");
+
+ info("test autocomplete for '[1,2,3]['");
+ matches = (await webConsoleFront.autocomplete("[1,2,3]['")).matches;
+ ok(matches.length > 1);
+ ok(matches.includes("'length'") && matches.includes("'filter'"),
+ "Array autocomplete contains expected results, surrounded by quotes");
+
+ info("test autocomplete for '[1,2,3][l");
+ matches = (await webConsoleFront.autocomplete("[1,2,3][l")).matches;
+ ok(matches.length >= 1);
+ ok(matches.includes('"length"'),
+ "Array autocomplete contains expected results, surrounded by quotes");
+
+ info("test autocomplete for '[1,2,3]['l");
+ matches = (await webConsoleFront.autocomplete("[1,2,3]['l")).matches;
+ ok(matches.length >= 1);
+ ok(matches.includes("'length'"),
+ "Array autocomplete contains expected results, surrounded by quotes");
+ }
+
+ async function doAutocompleteString(webConsoleFront) {
+ info(`test autocomplete for "foo".`);
+ const response = await webConsoleFront.autocomplete(`"foo".`);
+ let {matches} = response;
+
+ ok(!!matches.length, "There are completion results for the string");
+ ok(matches.includes("substr") && matches.includes("trim"),
+ "String autocomplete contains expected results");
+
+ info("test autocomplete for `foo`[");
+ matches = (await webConsoleFront.autocomplete("`foo`[")).matches;
+ ok(matches.length > 1, "autocomplete string with bracket works");
+ ok(matches.includes('"substr"') && matches.includes('"trim"'),
+ "String autocomplete contains expected results, surrounded by quotes");
+ }
+
+ async function doAutocompleteDotSurroundedBySpaces(webConsoleFront) {
+ info("test autocomplete for 'window.foobarObject\n .'");
+ let {matches} = await webConsoleFront.autocomplete("window.foobarObject\n .");
+ is(matches.length, 7);
+ checkObject(matches,
+ ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
+
+ info("test autocomplete for 'window.foobarObject\n .o'");
+ matches = (await webConsoleFront.autocomplete("window.foobarObject\n .o")).matches;
+ is(matches.length, 3);
+ checkObject(matches, ["omg", "omgfoo", "omgstr"]);
+
+ info("test autocomplete for 'window.foobarObject\n .\n s'");
+ matches = (await webConsoleFront.autocomplete("window.foobarObject\n .\n s")).matches;
+ is(matches.length, 1);
+ checkObject(matches, ["strfoo"]);
+
+ info("test autocomplete for 'window.foobarObject\n . '");
+ matches = (await webConsoleFront.autocomplete("window.foobarObject\n . ")).matches;
+ is(matches.length, 7);
+ checkObject(matches,
+ ["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]);
+
+ matches =
+ (await webConsoleFront.autocomplete("window.foobarObject. foo ; window.foo")).matches;
+ is(matches.length, 1);
+ checkObject(matches, ["foobarObject"]);
+ }
+
+ async function doAutocompleteBracketSurroundedBySpaces(webConsoleFront) {
+ const wrap = (arr, quote = `"`) => arr.map(x => `${quote}${x}${quote}`);
+ let matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n [")
+ is(matches.length, 7);
+ checkObject(matches,
+ wrap(["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]));
+
+ matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n ['o")
+ is(matches.length, 3);
+ checkObject(matches, wrap(["omg", "omgfoo", "omgstr"], "'"));
+
+ matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n [\n s");
+ is(matches.length, 1);
+ checkObject(matches, [`"strfoo"`]);
+
+ matches = await getAutocompleteMatches(webConsoleFront, "window.foobarObject\n [ ");
+ is(matches.length, 7);
+ checkObject(matches,
+ wrap(["foo", "foobar", "foobaz", "omg", "omgfoo", "omgstr", "strfoo"]));
+
+ matches = await getAutocompleteMatches(webConsoleFront, "window.emojiObject [ '");
+ is(matches.length, 1);
+ checkObject(matches, [`'😎'`]);
+ }
+
+ async function doAutocompleteAfterOr(webConsoleFront) {
+ info("test autocomplete for 'true || foo'");
+ const {matches} = await webConsoleFront.autocomplete("true || foobar");
+ is(matches.length, 1, "autocomplete returns expected results");
+ is(matches.join("-"), "foobarObject");
+ }
+
+ async function doInsensitiveAutocomplete(webConsoleFront) {
+ info("test autocomplete for 'window.insensitiveTestCase.'");
+ let {matches} = await webConsoleFront.autocomplete("window.insensitiveTestCase.");
+ is(matches.join("-"), "prop-pröp-Prop-PROP-PRÖP",
+ "autocomplete returns the expected items, in the expected order");
+
+ info("test autocomplete for 'window.insensitiveTestCase.p'");
+ matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.p")).matches;
+ is(matches.join("-"), "prop-pröp-Prop-PROP-PRÖP",
+ "autocomplete is case-insensitive when first letter is lowercased");
+
+ info("test autocomplete for 'window.insensitiveTestCase.pRoP'");
+ matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.pRoP")).matches;
+ is(matches.join("-"), "prop-Prop-PROP",
+ "autocomplete is case-insensitive when first letter is lowercased");
+
+ info("test autocomplete for 'window.insensitiveTestCase.P'");
+ matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.P")).matches;
+ is(matches.join("-"), "Prop-PROP-PRÖP",
+ "autocomplete is case-sensitive when first letter is uppercased");
+
+ info("test autocomplete for 'window.insensitiveTestCase.PROP'");
+ matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.PROP")).matches;
+ is(matches.join("-"), "PROP",
+ "autocomplete is case-sensitive when first letter is uppercased");
+
+ info("test autocomplete for 'window.insensitiveTestCase.prö'");
+ matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.prö")).matches;
+ is(matches.join("-"), "pröp-PRÖP", "expected result with lowercase diacritic");
+
+ info("test autocomplete for 'window.insensitiveTestCase.PRÖ'");
+ matches = (await webConsoleFront.autocomplete("window.insensitiveTestCase.PRÖ")).matches;
+ is(matches.join("-"), "PRÖP", "expected result with uppercase diacritic");
+ }
+
+ async function doElementAccessAutocomplete(webConsoleFront) {
+ info("test autocomplete for 'window.elementAccessTestCase['");
+ let res = (await webConsoleFront.autocomplete("window.elementAccessTestCase["));
+ is(
+ res.matches.join("|"),
+ `"bar"|"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"|"BAR"`,
+ "autocomplete returns the expected items, wrapped in quotes");
+ is(res.isElementAccess, true);
+
+ info("test autocomplete for 'window.elementAccessTestCase[d'");
+ res = await webConsoleFront.autocomplete("window.elementAccessTestCase[d");
+ is(
+ res.matches.join("|"),
+ `"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"`,
+ "autocomplete returns the expected filtered items");
+ is(res.isElementAccess, true);
+
+ info(`test autocomplete for 'window.elementAccessTestCase["d'`);
+ res = await webConsoleFront.autocomplete(`window.elementAccessTestCase["d`);
+ is(
+ res.matches.join("|"),
+ `"da'ta'test"|"da\\"ta\\"test"|"da\`ta\`test"|"data-test"|"dataTest"`,
+ "autocomplete returns the expected items, wrapped in quotes");
+ is(res.isElementAccess, true);
+
+ info(`test autocomplete for 'window.elementAccessTestCase["data-`);
+ res = await webConsoleFront.autocomplete(`window.elementAccessTestCase["data-`);
+ is(res.matches.join("|"), `"data-test"`,
+ "autocomplete returns the expected items, wrapped in quotes");
+ is(res.isElementAccess, true);
+
+ info(`test autocomplete for 'window.elementAccessTestCase['d'`);
+ res = await webConsoleFront.autocomplete(`window.elementAccessTestCase['d`);
+ is(
+ res.matches.join("|"),
+ `'da"ta"test'|'da\\'ta\\'test'|'da\`ta\`test'|'data-test'|'dataTest'`,
+ "autocomplete returns the expected items, wrapped in the same quotes the user entered");
+ is(res.isElementAccess, true);
+
+ info("test autocomplete for 'window.elementAccessTestCase[`d'");
+ res = await webConsoleFront.autocomplete("window.elementAccessTestCase[`d");
+ is(
+ res.matches.join("|"),
+ "`da'ta'test`|`da\"ta\"test`|`da\\`ta\\`test`|`data-test`|`dataTest`",
+ "autocomplete returns the expected items, wrapped in the same quotes the user entered");
+ is(res.isElementAccess, true);
+
+ info(`test autocomplete for '['`);
+ res = await webConsoleFront.autocomplete(`[`);
+ is(res.matches, null, "it does not return anything");
+
+ info(`test autocomplete for '[1,2,3'`);
+ res = await webConsoleFront.autocomplete(`[1,2,3`);
+ is(res.matches, null, "it does not return anything");
+
+ info(`test autocomplete for '["'`);
+ res = await webConsoleFront.autocomplete(`["`);
+ is(res.matches, null, "it does not return anything");
+
+ info(`test autocomplete for '[;'`);
+ res = await webConsoleFront.autocomplete(`[;`);
+ is(res.matches, null, "it does not return anything");
+ }
+
+ async function doAutocompleteCommands(webConsoleFront) {
+ info("test autocomplete for 'c'");
+ let matches = (await webConsoleFront.autocomplete("c")).matches;
+ ok(matches.includes("clear"), "commands are returned");
+
+ info("test autocomplete for 's'");
+ matches = (await webConsoleFront.autocomplete("s")).matches;
+ is(matches.includes("screenshot"), false, "screenshot is not returned");
+
+ info("test autocomplete for ':s'");
+ matches = (await webConsoleFront.autocomplete(":s")).matches;
+ is(matches.includes(":screenshot"), true, "screenshot is returned");
+
+ info("test autocomplete for 'window.c'");
+ matches = (await webConsoleFront.autocomplete("window.c")).matches;
+ ok(!matches.includes("clear"), "commands are not returned");
+
+ info("test autocomplete for 'window[c'");
+ matches = (await webConsoleFront.autocomplete("window[c")).matches;
+ ok(!matches.includes("clear"), "commands are not returned");
+
+ info(`test autocomplete for 'window["c'`);
+ matches = (await webConsoleFront.autocomplete(`window["c`)).matches;
+ ok(!matches.includes("clear"), "commands are not returned");
+
+ info(`test autocomplete for 'window["c'`);
+ matches = (await webConsoleFront.autocomplete(`window["c`)).matches;
+ ok(!matches.includes("clear"), "commands are not returned");
+
+ info(`test autocomplete for 'window[";c'`);
+ matches = (await webConsoleFront.autocomplete(`window[";c`)).matches;
+ ok(!matches.includes("clear"), "commands are not returned");
+
+ info(`test autocomplete for 'window[;c'`);
+ matches = (await webConsoleFront.autocomplete(`window[;c`)).matches;
+ ok(!matches.includes("clear"), "commands are not returned");
+ }
+
+ async function doAutocompleteAfterOperator(webConsoleFront) {
+ const inputs = [
+ "true;foob",
+ "true,foob",
+ "({key:foob",
+ "a=foob",
+ "if(a<foob",
+ "if(a>foob",
+ "1+foob",
+ "1-foob",
+ "++foob",
+ "--foob",
+ "1*foob",
+ "2**foob",
+ "1/foob",
+ "1%foob",
+ "1|foob",
+ "1&foob",
+ "1^foob",
+ "~foob",
+ "1<<foob",
+ "1>>foob",
+ "1>>>foob",
+ "false||foob",
+ "false&&foob",
+ "x=true?foob",
+ "x=false?1:foob",
+ "!foob",
+ "false??foob",
+ ];
+
+ for (const input of inputs) {
+ info(`test autocomplete for "${input}"`);
+ const matches = (await webConsoleFront.autocomplete(input)).matches;
+ ok(matches.includes("foobarObject"), `Expected autocomplete result for ${input}"`);
+ }
+ }
+
+ async function dontAutocompleteAfterDeclaration(webConsoleFront) {
+ info("test autocomplete for 'var win'");
+ let matches = (await webConsoleFront.autocomplete("var win")).matches;
+ is(matches, null, "no autocompletion on a var declaration");
+
+ info("test autocomplete for 'const win'");
+ matches = (await webConsoleFront.autocomplete("const win")).matches;
+ is(matches, null, "no autocompletion on a const declaration");
+
+ info("test autocomplete for 'let win'");
+ matches = (await webConsoleFront.autocomplete("let win")).matches;
+ is(matches, null, "no autocompletion on a let declaration");
+
+ info("test autocomplete for 'function win'");
+ matches = (await webConsoleFront.autocomplete("function win")).matches;
+ is(matches, null, "no autocompletion on a function declaration");
+
+ info("test autocomplete for 'class win'");
+ matches = (await webConsoleFront.autocomplete("class win")).matches;
+ is(matches, null, "no autocompletion on a class declaration");
+
+ info("test autocomplete for 'const win = win'");
+ matches = (await webConsoleFront.autocomplete("const win = win")).matches;
+ ok(matches.includes("window"), "autocompletion still happens after the `=` sign");
+
+ info("test autocomplete for 'in var'");
+ matches = (await webConsoleFront.autocomplete("in var")).matches;
+ ok(matches.includes("varify"),
+ "autocompletion still happens with a property name starting with 'var'");
+}
+
+async function doKeywordsAutocomplete(webConsoleFront) {
+ info("test autocomplete for 'func'");
+ let matches = (await webConsoleFront.autocomplete("func")).matches;
+ ok(matches.includes("function"), "keywords are returned");
+
+ info("test autocomplete for ':func'");
+ matches = (await webConsoleFront.autocomplete(":func")).matches;
+ is(!matches.includes("function"), true,
+ "'function' is not returned when prefixed with ':'");
+
+ info("test autocomplete for 'window.func'");
+ matches = (await webConsoleFront.autocomplete("window.func")).matches;
+ ok(!matches.includes("function"),
+ "'function' is not returned when doing a property access");
+
+ info("test autocomplete for 'window[func'");
+ matches = (await webConsoleFront.autocomplete("window[func")).matches;
+ ok(!matches.includes("function"),
+ "'function' is not returned when doing an element access");
+ }
+
+ async function dontAutocomplete(webConsoleFront) {
+ const inputs = [
+ "",
+ " ",
+ "\n",
+ "\n ",
+ " \n ",
+ " \n",
+ "true;",
+ "true,",
+ "({key:",
+ "a=",
+ "if(a<",
+ "if(a>",
+ "1+",
+ "1-",
+ "++",
+ "--",
+ "1*",
+ "2**",
+ "1/",
+ "1%",
+ "1|",
+ "1&",
+ "1^",
+ "~",
+ "1<<",
+ "1>>",
+ "1>>>",
+ "false||",
+ "false&&",
+ "x=true?",
+ "x=false?1:",
+ "!",
+ ...RESERVED_JS_KEYWORDS.map(keyword => `${keyword} `),
+ ...RESERVED_JS_KEYWORDS.map(keyword => `${keyword} `),
+ ];
+ for (const input of inputs) {
+ info(`test autocomplete for "${input}"`);
+ const matches = (await webConsoleFront.autocomplete(input)).matches;
+ is(matches, null, `No autocomplete result for ${input}"`);
+ }
+ }
+
+ async function getAutocompleteMatches(webConsoleFront, input) {
+ info(`test autocomplete for "${input}"`);
+ const res = (await webConsoleFront.autocomplete(input));
+ return res.matches;
+ }
+
+ async function evaluateExpression(consoleFront, expression) {
+ const onEvaluationResult = consoleFront.once("evaluationResult");
+ await consoleFront.evaluateJSAsync({ text: expression });
+ return onEvaluationResult;
+ }
+
+</script>
+</body>
+</html>