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>