test_js_property_provider.js (23794B)
1 // Any copyright is dedicated to the Public Domain. 2 // http://creativecommons.org/publicdomain/zero/1.0/ 3 4 "use strict"; 5 const { 6 fallibleJsPropertyProvider: jsPropertyProvider, 7 } = require("resource://devtools/shared/webconsole/js-property-provider.js"); 8 9 const { addDebuggerToGlobal } = ChromeUtils.importESModule( 10 "resource://gre/modules/jsdebugger.sys.mjs" 11 ); 12 addDebuggerToGlobal(globalThis); 13 14 function run_test() { 15 Services.prefs.setBoolPref( 16 "security.allow_parent_unrestricted_js_loads", 17 true 18 ); 19 registerCleanupFunction(() => { 20 Services.prefs.clearUserPref("security.allow_parent_unrestricted_js_loads"); 21 }); 22 23 const testArray = `var testArray = [ 24 {propA: "A"}, 25 { 26 propB: "B", 27 propC: [ 28 "D" 29 ] 30 }, 31 [ 32 {propE: "E"} 33 ] 34 ]`; 35 36 const testObject = 'var testObject = {"propA": [{"propB": "B"}]}'; 37 const testHyphenated = 'var testHyphenated = {"prop-A": "res-A"}'; 38 const testLet = "let foobar = {a: ''}; const blargh = {a: 1};"; 39 40 const testGenerators = ` 41 // Test with generator using a named function. 42 function* genFunc() { 43 for (let i = 0; i < 10; i++) { 44 yield i; 45 } 46 } 47 let gen1 = genFunc(); 48 gen1.next(); 49 50 // Test with generator using an anonymous function. 51 let gen2 = (function* () { 52 for (let i = 0; i < 10; i++) { 53 yield i; 54 } 55 })();`; 56 57 const testGetters = ` 58 var testGetters = { 59 get x() { 60 return Object.create(null, Object.getOwnPropertyDescriptors({ 61 hello: "", 62 world: "", 63 })); 64 }, 65 get y() { 66 return Object.create(null, Object.getOwnPropertyDescriptors({ 67 get y() { 68 return "plop"; 69 }, 70 })); 71 } 72 }; 73 `; 74 75 const testProxies = ` 76 var testSelfPrototypeProxy = new Proxy({ 77 hello: 1 78 }, { 79 getPrototypeOf: () => testProxy 80 }); 81 var testArrayPrototypeProxy = new Proxy({ 82 world: 2 83 }, { 84 getPrototypeOf: () => Array.prototype 85 }) 86 `; 87 88 const sandbox = Cu.Sandbox("http://example.com"); 89 const dbg = new Debugger(); 90 const dbgObject = dbg.addDebuggee(sandbox); 91 const dbgEnv = dbgObject.asEnvironment(); 92 Cu.evalInSandbox( 93 ` 94 const hello = Object.create(null, Object.getOwnPropertyDescriptors({world: 1})); 95 String.prototype.hello = hello; 96 Number.prototype.hello = hello; 97 Array.prototype.hello = hello; 98 `, 99 sandbox 100 ); 101 Cu.evalInSandbox(testArray, sandbox); 102 Cu.evalInSandbox(testObject, sandbox); 103 Cu.evalInSandbox(testHyphenated, sandbox); 104 Cu.evalInSandbox(testLet, sandbox); 105 Cu.evalInSandbox(testGenerators, sandbox); 106 Cu.evalInSandbox(testGetters, sandbox); 107 Cu.evalInSandbox(testProxies, sandbox); 108 109 info("Running tests with dbgObject"); 110 runChecks(dbgObject, null, sandbox); 111 112 info("Running tests with dbgEnv"); 113 runChecks(null, dbgEnv, sandbox); 114 } 115 116 function runChecks(dbgObject, environment, sandbox) { 117 const propertyProvider = (inputValue, options) => 118 jsPropertyProvider({ 119 dbgObject, 120 environment, 121 inputValue, 122 ...options, 123 }); 124 125 info("Test that suggestions are given for 'this'"); 126 let results = propertyProvider("t"); 127 test_has_result(results, "this"); 128 129 if (dbgObject != null) { 130 info("Test that suggestions are given for 'this.'"); 131 results = propertyProvider("this."); 132 test_has_result(results, "testObject"); 133 134 info("Test that suggestions are given for '(this).'"); 135 results = propertyProvider("(this)."); 136 test_has_result(results, "testObject"); 137 138 info("Test that suggestions are given for deep 'this' properties access"); 139 results = propertyProvider("(this).testObject.propA."); 140 test_has_result(results, "shift"); 141 142 results = propertyProvider("(this).testObject.propA["); 143 test_has_result(results, `"shift"`); 144 145 results = propertyProvider("(this)['testObject']['propA']["); 146 test_has_result(results, `"shift"`); 147 148 results = propertyProvider("(this).testObject['propA']."); 149 test_has_result(results, "shift"); 150 151 info("Test that no suggestions are given for 'this.this'"); 152 results = propertyProvider("this.this"); 153 test_has_no_results(results); 154 } 155 156 info("Test that suggestions are given for 'globalThis'"); 157 results = propertyProvider("g"); 158 test_has_result(results, "globalThis"); 159 160 info("Test that suggestions are given for 'globalThis.'"); 161 results = propertyProvider("globalThis."); 162 test_has_result(results, "testObject"); 163 164 info("Test that suggestions are given for '(globalThis).'"); 165 results = propertyProvider("(globalThis)."); 166 test_has_result(results, "testObject"); 167 test_has_result(results, "Infinity"); 168 169 info( 170 "Test that suggestions are given for deep 'globalThis' properties access" 171 ); 172 results = propertyProvider("(globalThis).testObject.propA."); 173 test_has_result(results, "shift"); 174 175 results = propertyProvider("(globalThis).testObject.propA["); 176 test_has_result(results, `"shift"`); 177 178 results = propertyProvider("(globalThis)['testObject']['propA']["); 179 test_has_result(results, `"shift"`); 180 181 results = propertyProvider("(globalThis).testObject['propA']."); 182 test_has_result(results, "shift"); 183 184 info("Testing lexical scope issues (Bug 1207868)"); 185 results = propertyProvider("foobar"); 186 test_has_result(results, "foobar"); 187 188 results = propertyProvider("foobar."); 189 test_has_result(results, "a"); 190 191 results = propertyProvider("blargh"); 192 test_has_result(results, "blargh"); 193 194 results = propertyProvider("blargh."); 195 test_has_result(results, "a"); 196 197 info("Test that suggestions are given for 'foo[n]' where n is an integer."); 198 results = propertyProvider("testArray[0]."); 199 test_has_result(results, "propA"); 200 201 info("Test that suggestions are given for multidimensional arrays."); 202 results = propertyProvider("testArray[2][0]."); 203 test_has_result(results, "propE"); 204 205 info("Test that suggestions are given for nested arrays."); 206 results = propertyProvider("testArray[1].propC[0]."); 207 test_has_result(results, "indexOf"); 208 209 info("Test that suggestions are given for literal arrays."); 210 results = propertyProvider("[1,2,3]."); 211 test_has_result(results, "indexOf"); 212 213 results = propertyProvider("[1,2,3].h"); 214 test_has_result(results, "hello"); 215 216 results = propertyProvider("[1,2,3].hello.w"); 217 test_has_result(results, "world"); 218 219 info("Test that suggestions are given for literal arrays with newlines."); 220 results = propertyProvider("[1,2,3,\n4\n]."); 221 test_has_result(results, "indexOf"); 222 223 info("Test that suggestions are given for literal strings."); 224 results = propertyProvider("'foo'."); 225 test_has_result(results, "charAt"); 226 results = propertyProvider('"foo".'); 227 test_has_result(results, "charAt"); 228 results = propertyProvider("`foo`."); 229 test_has_result(results, "charAt"); 230 results = propertyProvider("`foo doc`."); 231 test_has_result(results, "charAt"); 232 results = propertyProvider('`foo " doc`.'); 233 test_has_result(results, "charAt"); 234 results = propertyProvider("`foo ' doc`."); 235 test_has_result(results, "charAt"); 236 results = propertyProvider("'[1,2,3]'."); 237 test_has_result(results, "charAt"); 238 results = propertyProvider("'foo'.h"); 239 test_has_result(results, "hello"); 240 results = propertyProvider("'foo'.hello.w"); 241 test_has_result(results, "world"); 242 results = propertyProvider(`"\\n".`); 243 test_has_result(results, "charAt"); 244 results = propertyProvider(`'\\r'.`); 245 test_has_result(results, "charAt"); 246 results = propertyProvider("`\\\\`."); 247 test_has_result(results, "charAt"); 248 results = propertyProvider(`"🧑".c`); 249 test_has_result(results, "codePointAt"); 250 251 info("Test that suggestions are not given for syntax errors."); 252 results = propertyProvider("'foo\""); 253 Assert.equal(null, results); 254 results = propertyProvider("'foo d"); 255 Assert.equal(null, results); 256 results = propertyProvider(`"foo d`); 257 Assert.equal(null, results); 258 results = propertyProvider("`foo d"); 259 Assert.equal(null, results); 260 results = propertyProvider("[1,',2]"); 261 Assert.equal(null, results); 262 results = propertyProvider("'[1,2]."); 263 Assert.equal(null, results); 264 results = propertyProvider("'foo'.."); 265 Assert.equal(null, results); 266 267 info("Test that suggestions are not given without a dot."); 268 results = propertyProvider("'foo'"); 269 test_has_no_results(results); 270 results = propertyProvider("`foo`"); 271 test_has_no_results(results); 272 results = propertyProvider("[1,2,3]"); 273 test_has_no_results(results); 274 results = propertyProvider("[1,2,3].\n'foo'"); 275 test_has_no_results(results); 276 277 info("Test that suggestions are not given for index that's out of bounds."); 278 results = propertyProvider("testArray[10]."); 279 Assert.equal(null, results); 280 281 info("Test that invalid element access syntax does not return anything"); 282 results = propertyProvider("testArray[][1]."); 283 Assert.equal(null, results); 284 285 info("Test that deep element access works."); 286 results = propertyProvider("testObject['propA'][0]."); 287 test_has_result(results, "propB"); 288 289 results = propertyProvider("testArray[1]['propC']."); 290 test_has_result(results, "shift"); 291 292 results = propertyProvider("testArray[1].propC[0]["); 293 test_has_result(results, `"trim"`); 294 295 results = propertyProvider("testArray[1].propC[0]."); 296 test_has_result(results, "trim"); 297 298 info( 299 "Test that suggestions are displayed when variable is wrapped in parens" 300 ); 301 results = propertyProvider("(testObject)['propA'][0]."); 302 test_has_result(results, "propB"); 303 304 results = propertyProvider("(testArray)[1]['propC']."); 305 test_has_result(results, "shift"); 306 307 results = propertyProvider("(testArray)[1].propC[0]["); 308 test_has_result(results, `"trim"`); 309 310 results = propertyProvider("(testArray)[1].propC[0]."); 311 test_has_result(results, "trim"); 312 313 info("Test that suggestions are given if there is an hyphen in the chain."); 314 results = propertyProvider("testHyphenated['prop-A']."); 315 test_has_result(results, "trim"); 316 317 info("Test that we have suggestions for generators."); 318 const gen1Result = Cu.evalInSandbox("gen1.next().value", sandbox); 319 results = propertyProvider("gen1."); 320 test_has_result(results, "next"); 321 info("Test that the generator next() was not executed"); 322 const gen1NextResult = Cu.evalInSandbox("gen1.next().value", sandbox); 323 Assert.equal(gen1Result + 1, gen1NextResult); 324 325 info("Test with an anonymous generator."); 326 const gen2Result = Cu.evalInSandbox("gen2.next().value", sandbox); 327 results = propertyProvider("gen2."); 328 test_has_result(results, "next"); 329 const gen2NextResult = Cu.evalInSandbox("gen2.next().value", sandbox); 330 Assert.equal(gen2Result + 1, gen2NextResult); 331 332 info( 333 "Test that getters are not executed if authorizedEvaluations is undefined" 334 ); 335 results = propertyProvider("testGetters.x."); 336 Assert.deepEqual(results, { 337 isUnsafeGetter: true, 338 getterPath: ["testGetters", "x"], 339 }); 340 341 results = propertyProvider("testGetters.x["); 342 Assert.deepEqual(results, { 343 isUnsafeGetter: true, 344 getterPath: ["testGetters", "x"], 345 }); 346 347 results = propertyProvider("testGetters.x.hell"); 348 Assert.deepEqual(results, { 349 isUnsafeGetter: true, 350 getterPath: ["testGetters", "x"], 351 }); 352 353 results = propertyProvider("testGetters.x['hell"); 354 Assert.deepEqual(results, { 355 isUnsafeGetter: true, 356 getterPath: ["testGetters", "x"], 357 }); 358 359 info( 360 "Test that getters are not executed if authorizedEvaluations does not match" 361 ); 362 results = propertyProvider("testGetters.x.", { authorizedEvaluations: [] }); 363 Assert.deepEqual(results, { 364 isUnsafeGetter: true, 365 getterPath: ["testGetters", "x"], 366 }); 367 368 results = propertyProvider("testGetters.x.", { 369 authorizedEvaluations: [["testGetters"]], 370 }); 371 Assert.deepEqual(results, { 372 isUnsafeGetter: true, 373 getterPath: ["testGetters", "x"], 374 }); 375 376 results = propertyProvider("testGetters.x.", { 377 authorizedEvaluations: [["testGtrs", "x"]], 378 }); 379 Assert.deepEqual(results, { 380 isUnsafeGetter: true, 381 getterPath: ["testGetters", "x"], 382 }); 383 384 results = propertyProvider("testGetters.x.", { 385 authorizedEvaluations: [["x"]], 386 }); 387 Assert.deepEqual(results, { 388 isUnsafeGetter: true, 389 getterPath: ["testGetters", "x"], 390 }); 391 392 info("Test that deep getter property access returns intermediate getters"); 393 results = propertyProvider("testGetters.y.y."); 394 Assert.deepEqual(results, { 395 isUnsafeGetter: true, 396 getterPath: ["testGetters", "y"], 397 }); 398 399 results = propertyProvider("testGetters['y'].y."); 400 Assert.deepEqual(results, { 401 isUnsafeGetter: true, 402 getterPath: ["testGetters", "y"], 403 }); 404 405 results = propertyProvider("testGetters['y']['y']."); 406 Assert.deepEqual(results, { 407 isUnsafeGetter: true, 408 getterPath: ["testGetters", "y"], 409 }); 410 411 results = propertyProvider("testGetters.y['y']."); 412 Assert.deepEqual(results, { 413 isUnsafeGetter: true, 414 getterPath: ["testGetters", "y"], 415 }); 416 417 info("Test that deep getter property access invoke intermediate getters"); 418 results = propertyProvider("testGetters.y.y.", { 419 authorizedEvaluations: [["testGetters", "y"]], 420 }); 421 Assert.deepEqual(results, { 422 isUnsafeGetter: true, 423 getterPath: ["testGetters", "y", "y"], 424 }); 425 426 results = propertyProvider("testGetters['y'].y.", { 427 authorizedEvaluations: [["testGetters", "y"]], 428 }); 429 Assert.deepEqual(results, { 430 isUnsafeGetter: true, 431 getterPath: ["testGetters", "y", "y"], 432 }); 433 434 results = propertyProvider("testGetters['y']['y'].", { 435 authorizedEvaluations: [["testGetters", "y"]], 436 }); 437 Assert.deepEqual(results, { 438 isUnsafeGetter: true, 439 getterPath: ["testGetters", "y", "y"], 440 }); 441 442 results = propertyProvider("testGetters.y['y'].", { 443 authorizedEvaluations: [["testGetters", "y"]], 444 }); 445 Assert.deepEqual(results, { 446 isUnsafeGetter: true, 447 getterPath: ["testGetters", "y", "y"], 448 }); 449 450 info( 451 "Test that getters are executed if matching an authorizedEvaluation element" 452 ); 453 results = propertyProvider("testGetters.x.", { 454 authorizedEvaluations: [["testGetters", "x"]], 455 }); 456 test_has_exact_results(results, ["hello", "world"]); 457 Assert.strictEqual(Object.keys(results).includes("isUnsafeGetter"), false); 458 Assert.strictEqual(Object.keys(results).includes("getterPath"), false); 459 460 results = propertyProvider("testGetters.x.", { 461 authorizedEvaluations: [["testGetters", "x"], ["y"]], 462 }); 463 test_has_exact_results(results, ["hello", "world"]); 464 Assert.strictEqual(Object.keys(results).includes("isUnsafeGetter"), false); 465 Assert.strictEqual(Object.keys(results).includes("getterPath"), false); 466 467 info("Test that executing getters filters with provided string"); 468 results = propertyProvider("testGetters.x.hell", { 469 authorizedEvaluations: [["testGetters", "x"]], 470 }); 471 test_has_exact_results(results, ["hello"]); 472 473 results = propertyProvider("testGetters.x['hell", { 474 authorizedEvaluations: [["testGetters", "x"]], 475 }); 476 test_has_exact_results(results, ["'hello'"]); 477 478 info( 479 "Test children getters are not executed if not included in authorizedEvaluation" 480 ); 481 results = propertyProvider("testGetters.y.y.", { 482 authorizedEvaluations: [["testGetters", "y", "y"]], 483 }); 484 Assert.deepEqual(results, { 485 isUnsafeGetter: true, 486 getterPath: ["testGetters", "y"], 487 }); 488 489 info( 490 "Test children getters are executed if matching an authorizedEvaluation element" 491 ); 492 results = propertyProvider("testGetters.y.y.", { 493 authorizedEvaluations: [ 494 ["testGetters", "y"], 495 ["testGetters", "y", "y"], 496 ], 497 }); 498 test_has_result(results, "trim"); 499 500 info("Test with number literals"); 501 results = propertyProvider("1."); 502 Assert.strictEqual( 503 results, 504 null, 505 "Does not complete on possible floating number" 506 ); 507 508 results = propertyProvider("(1).."); 509 Assert.strictEqual(results, null, "Does not complete on invalid syntax"); 510 511 results = propertyProvider("(1.1.)."); 512 Assert.strictEqual(results, null, "Does not complete on invalid syntax"); 513 514 results = propertyProvider("1.."); 515 test_has_result(results, "toFixed"); 516 517 results = propertyProvider("1 ."); 518 test_has_result(results, "toFixed"); 519 520 results = propertyProvider("1\n."); 521 test_has_result(results, "toFixed"); 522 523 results = propertyProvider(".1."); 524 test_has_result(results, "toFixed"); 525 526 results = propertyProvider("1["); 527 test_has_result(results, `"toFixed"`); 528 529 results = propertyProvider("1[toFixed"); 530 test_has_exact_results(results, [`"toFixed"`]); 531 532 results = propertyProvider("1['toFixed"); 533 test_has_exact_results(results, ["'toFixed'"]); 534 535 results = propertyProvider("1.1["); 536 test_has_result(results, `"toFixed"`); 537 538 results = propertyProvider("(1)."); 539 test_has_result(results, "toFixed"); 540 541 results = propertyProvider("(.1)."); 542 test_has_result(results, "toFixed"); 543 544 results = propertyProvider("(1.1)."); 545 test_has_result(results, "toFixed"); 546 547 results = propertyProvider("(1).toFixed"); 548 test_has_exact_results(results, ["toFixed"]); 549 550 results = propertyProvider("(1)["); 551 test_has_result(results, `"toFixed"`); 552 553 results = propertyProvider("(1.1)["); 554 test_has_result(results, `"toFixed"`); 555 556 results = propertyProvider("(1)[toFixed"); 557 test_has_exact_results(results, [`"toFixed"`]); 558 559 results = propertyProvider("(1)['toFixed"); 560 test_has_exact_results(results, ["'toFixed'"]); 561 562 results = propertyProvider("(1).h"); 563 test_has_result(results, "hello"); 564 565 results = propertyProvider("(1).hello.w"); 566 test_has_result(results, "world"); 567 568 info("Test access on dot-notation invalid property name"); 569 results = propertyProvider("testHyphenated.prop"); 570 Assert.ok( 571 !results.matches.has("prop-A"), 572 "Does not return invalid property name on dot access" 573 ); 574 575 results = propertyProvider("testHyphenated['prop"); 576 test_has_result(results, `'prop-A'`); 577 578 results = propertyProvider(`//t`); 579 Assert.strictEqual(results, null, "Does not complete in inline comment"); 580 581 results = propertyProvider(`// t`); 582 Assert.strictEqual( 583 results, 584 null, 585 "Does not complete in inline comment after space" 586 ); 587 588 results = propertyProvider(`//I'm a comment\nt`); 589 test_has_result(results, "testObject"); 590 591 results = propertyProvider(`1/t`); 592 test_has_result(results, "testObject"); 593 594 results = propertyProvider(`1/(t`); 595 test_has_result(results, "testObject"); 596 597 results = propertyProvider(`/* t`); 598 Assert.strictEqual(results, null, "Does not complete in multiline comment"); 599 600 results = propertyProvider(`/*I'm\nt`); 601 Assert.strictEqual( 602 results, 603 null, 604 "Does not complete in multiline comment after line break" 605 ); 606 607 results = propertyProvider(`/*I'm a comment\n \t * /t`); 608 Assert.strictEqual( 609 results, 610 null, 611 "Does not complete in multiline comment after line break and invalid comment end" 612 ); 613 614 results = propertyProvider(`/*I'm a comment\n \t */t`); 615 test_has_result(results, "testObject"); 616 617 results = propertyProvider(`/*I'm a comment\n \t */\n\nt`); 618 test_has_result(results, "testObject"); 619 620 info("Test local expression variables"); 621 results = propertyProvider("b", { expressionVars: ["a", "b", "c"] }); 622 test_has_result(results, "b"); 623 Assert.equal(results.matches.has("a"), false); 624 Assert.equal(results.matches.has("c"), false); 625 626 info( 627 "Test that local expression variables are not included when accessing an object properties" 628 ); 629 results = propertyProvider("testObject.prop", { 630 expressionVars: ["propLocal"], 631 }); 632 Assert.equal(results.matches.has("propLocal"), false); 633 test_has_result(results, "propA"); 634 635 results = propertyProvider("testObject['prop", { 636 expressionVars: ["propLocal"], 637 }); 638 test_has_result(results, "'propA'"); 639 Assert.equal(results.matches.has("propLocal"), false); 640 641 info("Test that expression with optional chaining operator are completed"); 642 results = propertyProvider("testObject?.prop"); 643 test_has_result(results, "propA"); 644 645 results = propertyProvider("testObject?.propA[0]?.propB?.to"); 646 test_has_result(results, "toString"); 647 648 results = propertyProvider("testObject?.propA?.[0]?.propB?.to"); 649 test_has_result(results, "toString"); 650 651 results = propertyProvider( 652 "testObject ?. propA[0] ?. propB ?. to" 653 ); 654 test_has_result(results, "toString"); 655 656 results = propertyProvider("testObject?.[prop"); 657 test_has_result(results, '"propA"'); 658 659 results = propertyProvider(`testObject?.["prop`); 660 test_has_result(results, '"propA"'); 661 662 results = propertyProvider(`testObject?.['prop`); 663 test_has_result(results, `'propA'`); 664 665 results = propertyProvider(`testObject?.["propA"]?.[0]?.["propB"]?.["to`); 666 test_has_result(results, `"toString"`); 667 668 results = propertyProvider( 669 `testObject ?. ["propA"] ?. [0] ?. ["propB"] ?. ['to` 670 ); 671 test_has_result(results, "'toString'"); 672 673 results = propertyProvider("[1,2,3]?."); 674 test_has_result(results, "indexOf"); 675 676 results = propertyProvider("'foo'?."); 677 test_has_result(results, "charAt"); 678 679 results = propertyProvider("1?."); 680 test_has_result(results, "toFixed"); 681 682 // check this doesn't throw since `propC` is not defined. 683 results = propertyProvider("testObject?.propC?.this?.does?.not?.exist?.d"); 684 685 // check that ternary operator isn't mistaken for optional chaining 686 results = propertyProvider(`true?.3.to`); 687 test_has_result(results, `toExponential`); 688 689 results = propertyProvider(`true?.3?.to`); 690 test_has_result(results, `toExponential`); 691 692 // Test more ternary 693 results = propertyProvider(`true?t`); 694 test_has_result(results, `testObject`); 695 696 results = propertyProvider(`true??t`); 697 test_has_result(results, `testObject`); 698 699 results = propertyProvider(`true?/* comment */t`); 700 test_has_result(results, `testObject`); 701 702 results = propertyProvider(`true?<t`); 703 test_has_no_results(results); 704 705 // Test autocompletion on debugger statement does not throw 706 results = propertyProvider(`debugger.`); 707 Assert.strictEqual(results, null, "Does not complete a debugger keyword"); 708 709 // Test autocompletion on Proxies 710 // proxy does not get autocompletion result from prototype defined in `getPrototypeOf` 711 test_has_no_results(propertyProvider(`testArrayPrototypeProxy.filte`)); 712 results = propertyProvider(`testArrayPrototypeProxy.`); 713 // it does get the own property 714 test_has_result(results, `world`); 715 // as well as method from the actual proxy target prototype 716 test_has_result(results, `hasOwnProperty`); 717 718 results = propertyProvider(`testSelfPrototypeProxy.`); 719 test_has_result(results, `hello`); 720 test_has_result(results, `hasOwnProperty`); 721 722 info("Test suggestion for Infinity"); 723 results = propertyProvider("Inf"); 724 test_has_result(results, "Infinity"); 725 } 726 727 /** 728 * A helper that ensures an empty array of results were found. 729 * 730 * @param Object results 731 * The results returned by jsPropertyProvider. 732 */ 733 function test_has_no_results(results) { 734 Assert.notEqual(results, null); 735 Assert.equal(results.matches.size, 0); 736 } 737 /** 738 * A helper that ensures (required) results were found. 739 * 740 * @param Object results 741 * The results returned by jsPropertyProvider. 742 * @param String requiredSuggestion 743 * A suggestion that must be found from the results. 744 */ 745 function test_has_result(results, requiredSuggestion) { 746 Assert.notEqual(results, null); 747 Assert.greater(results.matches.size, 0); 748 Assert.ok( 749 results.matches.has(requiredSuggestion), 750 `<${requiredSuggestion}> found in ${[...results.matches.values()].join( 751 " - " 752 )}` 753 ); 754 } 755 756 /** 757 * A helper that ensures results are the expected ones. 758 * 759 * @param Object results 760 * The results returned by jsPropertyProvider. 761 * @param Array expectedMatches 762 * An array of the properties that should be returned by jsPropertyProvider. 763 */ 764 function test_has_exact_results(results, expectedMatches) { 765 Assert.deepEqual([...results.matches], expectedMatches); 766 }