ES6Class_BaseClassConstruction.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // ES6 super chain tests
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var tests = [
  8. {
  9. name: "Simple base class object construction",
  10. body: function () {
  11. class Simple {
  12. bar() {
  13. return 'bar';
  14. }
  15. constructor(val) {
  16. this.val = val;
  17. this.foo = "Simple";
  18. }
  19. };
  20. let result = new Simple('val');
  21. assert.areEqual("Simple", result.foo, "'this' is valid to use in Simple.constructor");
  22. assert.areEqual("val", result.val, "Arguments passed to Simple.constructor pass through correctly");
  23. assert.areEqual("bar", result.bar(), "Result object can call class members");
  24. assert.isTrue(result instanceof Simple, "new Simple(); uses new.target as 'Simple' itself which creates instanceof Simple class");
  25. }
  26. },
  27. {
  28. name: "Simple base class object construction which uses a lambda to access this",
  29. body: function () {
  30. class Simple {
  31. constructor(val) {
  32. let arrow = () => {
  33. this.val = val;
  34. this.foo = "Simple";
  35. };
  36. arrow();
  37. }
  38. };
  39. let result = new Simple('val');
  40. assert.areEqual("Simple", result.foo, "'this' is valid to use in Simple.constructor");
  41. assert.areEqual("val", result.val, "Arguments passed to Simple.constructor pass through correctly");
  42. assert.isTrue(result instanceof Simple, "new Simple(); uses new.target as 'Simple' itself which creates instanceof Simple class");
  43. }
  44. },
  45. {
  46. name: "Base class constructors return 'this' if they explicitly return a non-object",
  47. body: function () {
  48. class ReturnArgumentBaseClass {
  49. constructor(val) {
  50. this.foo = 'ReturnArgumentBaseClass';
  51. return val;
  52. }
  53. };
  54. let result = new ReturnArgumentBaseClass(null);
  55. assert.areEqual("ReturnArgumentBaseClass", result.foo, "new ReturnArgumentBaseClass(null); returns 'this'");
  56. assert.isTrue(result instanceof ReturnArgumentBaseClass, "new ReturnArgumentBaseClass(null); returns an instance of ReturnArgumentBaseClass");
  57. result = new ReturnArgumentBaseClass(undefined);
  58. assert.areEqual("ReturnArgumentBaseClass", result.foo, "new ReturnArgumentBaseClass(undefined); returns 'this'");
  59. assert.isTrue(result instanceof ReturnArgumentBaseClass, "new ReturnArgumentBaseClass(undefined); returns an instance of ReturnArgumentBaseClass");
  60. result = new ReturnArgumentBaseClass();
  61. assert.areEqual("ReturnArgumentBaseClass", result.foo, "new ReturnArgumentBaseClass(); returns 'this'");
  62. assert.isTrue(result instanceof ReturnArgumentBaseClass, "new ReturnArgumentBaseClass(); returns an instance of ReturnArgumentBaseClass");
  63. result = new ReturnArgumentBaseClass('string');
  64. assert.areEqual("ReturnArgumentBaseClass", result.foo, "new ReturnArgumentBaseClass('string'); returns 'this'");
  65. assert.isTrue(result instanceof ReturnArgumentBaseClass, "new ReturnArgumentBaseClass('string'); returns an instance of ReturnArgumentBaseClass");
  66. result = new ReturnArgumentBaseClass(5);
  67. assert.areEqual("ReturnArgumentBaseClass", result.foo, "new ReturnArgumentBaseClass(5); returns 'this'");
  68. assert.isTrue(result instanceof ReturnArgumentBaseClass, "new ReturnArgumentBaseClass(5); returns an instance of ReturnArgumentBaseClass");
  69. }
  70. },
  71. {
  72. name: "Base class constructors which return an object override return of 'this'",
  73. body: function () {
  74. class ReturnArgumentBaseClass {
  75. constructor(val) {
  76. this.foo = 'ReturnArgumentBaseClass';
  77. return val;
  78. }
  79. };
  80. let result = new ReturnArgumentBaseClass({foo:'test'});
  81. assert.areEqual("test", result.foo, "new ReturnArgumentBaseClass({foo:'test'}); returns {foo:'test'}");
  82. assert.isFalse(result instanceof ReturnArgumentBaseClass, "new ReturnArgumentBaseClass({foo:'test'}); doesn't return an instance of ReturnArgumentBaseClass");
  83. result = new ReturnArgumentBaseClass(new Boolean(false));
  84. assert.areEqual(new Boolean(false), result, "new ReturnArgumentBaseClass(new Boolean(false)); returns new Boolean(false)");
  85. assert.isTrue(result instanceof Boolean, "new ReturnArgumentBaseClass(new Boolean(false)); returns an instance of Boolean");
  86. }
  87. },
  88. {
  89. name: "Class that extends null has right prototypes",
  90. body: function () {
  91. class A extends null {}
  92. assert.areEqual(Function.prototype, Object.getPrototypeOf(A));
  93. assert.areEqual(null, Object.getPrototypeOf(A.prototype));
  94. }
  95. },
  96. {
  97. name: "Class that extends null doesn't bind 'this' implicitly",
  98. body: function () {
  99. class B extends null {
  100. constructor() { }
  101. }
  102. assert.throws(() => new B(), ReferenceError, "implicit return of 'this' throws", "Use before declaration");
  103. }
  104. },
  105. {
  106. name: "Class that extends null throws TypeError upon super call in constructor",
  107. body: function () {
  108. var beforeSuper = 0;
  109. var afterSuper = 0;
  110. class C extends null {
  111. constructor() {
  112. beforeSuper++;
  113. super();
  114. afterSuper++;
  115. }
  116. }
  117. assert.throws(function(){new C();}, TypeError, "super", "Function is not a constructor");
  118. assert.areEqual(1, beforeSuper);
  119. assert.areEqual(0, afterSuper);
  120. }
  121. },
  122. {
  123. name: "Class that extends null with explicit return in constructor",
  124. body: function () {
  125. class A extends null {
  126. constructor() { return {}; }
  127. }
  128. var a;
  129. assert.doesNotThrow(()=>{a = new A()});
  130. assert.areEqual(Object.prototype, Object.getPrototypeOf(a));
  131. }
  132. },
  133. {
  134. name: "Class that extends null with super references",
  135. body: function () {
  136. class A extends null {
  137. constructor() { super['prop'] = 'something'; return {}; }
  138. }
  139. assert.throws(() => new A(), ReferenceError, "super reference loads 'this' and throws if it's undecl ", "Use before declaration");
  140. var prop = 'prop';
  141. class B extends null {
  142. constructor() { super[prop] = 'something'; return {}; }
  143. }
  144. assert.throws(() => new B(), ReferenceError, "super reference loads 'this' and throws if it's undecl ", "Use before declaration");
  145. class C extends null {
  146. constructor() { super['prop']; return {}; }
  147. }
  148. assert.throws(() => new C(), ReferenceError, "super reference loads 'this' and throws if it's undecl ", "Use before declaration");
  149. class D extends null {
  150. constructor() { super[prop]; return {}; }
  151. }
  152. assert.throws(() => new D(), ReferenceError, "super reference loads 'this' and throws if it's undecl ", "Use before declaration");
  153. }
  154. },
  155. ];
  156. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });