| |
| description('Tests for ES6 class syntax "super"'); |
| |
| function shouldThrow(s, message) { |
| var threw = false; |
| try { |
| eval(s); |
| } catch(e) { |
| threw = true; |
| if (!message || e.toString() === eval(message)) |
| testPassed(s + ":::" + e.toString()); |
| else |
| testFailed(s); |
| } |
| if (!threw) |
| testFailed(s); |
| } |
| |
| function shouldNotThrow(s, message) { |
| var threw = false; |
| try { |
| eval(s); |
| } catch(e) { |
| threw = true; |
| } |
| if (threw) |
| testFailed(s); |
| else |
| testPassed(s); |
| } |
| |
| function shouldBe(a, b) { |
| if (eval(a) === eval(b)) |
| testPassed(a + ":::" + b); |
| else |
| testFailed(a + ":::" + b); |
| } |
| |
| function shouldBeTrue(s) { |
| if (eval(s) === true) |
| testPassed(s); |
| else |
| testFailed(s); |
| } |
| |
| function shouldBeFalse(s) { |
| if (eval(s) === false) |
| testPassed(s); |
| else |
| testFailed(s); |
| } |
| |
| var baseMethodValue = {}; |
| var valueInSetter = null; |
| |
| class Base { |
| constructor() { } |
| baseMethod() { return baseMethodValue; } |
| chainMethod() { return 'base'; } |
| static staticMethod() { return 'base3'; } |
| } |
| |
| class Derived extends Base { |
| constructor() { super(); } |
| chainMethod() { return [super.chainMethod(), 'derived']; } |
| callBaseMethod() { return super.baseMethod(); } |
| get callBaseMethodInGetter() { return super['baseMethod'](); } |
| set callBaseMethodInSetter(x) { valueInSetter = super.baseMethod(); } |
| get baseMethodInGetterSetter() { return super.baseMethod; } |
| set baseMethodInGetterSetter(x) { valueInSetter = super['baseMethod']; } |
| static staticMethod() { return super.staticMethod(); } |
| } |
| |
| class SecondDerived extends Derived { |
| constructor() { super(); } |
| chainMethod() { return super.chainMethod().concat(['secondDerived']); } |
| } |
| |
| class DerivedWithEval extends Base { |
| constructor(throwTDZ) { |
| if (throwTDZ) |
| this.id = ''; |
| |
| eval("super()"); |
| } |
| } |
| |
| shouldBeTrue('(new Base) instanceof Base'); |
| shouldBeTrue('(new Derived) instanceof Derived'); |
| shouldBeTrue('(new DerivedWithEval) instanceof DerivedWithEval'); |
| shouldThrow('(new DerivedWithEval(true))', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`); |
| shouldBe('(new Derived).callBaseMethod()', 'baseMethodValue'); |
| shouldBe('x = (new Derived).callBaseMethod; x()', 'baseMethodValue'); |
| shouldBe('(new Derived).callBaseMethodInGetter', 'baseMethodValue'); |
| shouldBe('(new Derived).callBaseMethodInSetter = 1; valueInSetter', 'baseMethodValue'); |
| shouldBe('(new Derived).baseMethodInGetterSetter', '(new Base).baseMethod'); |
| shouldBe('(new Derived).baseMethodInGetterSetter = 1; valueInSetter', '(new Base).baseMethod'); |
| shouldBe('Derived.staticMethod()', '"base3"'); |
| shouldBe('(new SecondDerived).chainMethod().toString()', '["base", "derived", "secondDerived"].toString()'); |
| shouldNotThrow('x = class extends Base { constructor() { super(); } super() {} }'); |
| shouldThrow('x = class extends Base { constructor() { super(); } method() { super() } }', |
| '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('x = class extends Base { constructor() { super(); } method() { super } }', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('x = class extends Base { constructor() { super(); } method() { return new super } }', '"SyntaxError: Cannot use new with super call."'); |
| shouldNotThrow('x = class extends Base { constructor() { super(); } method1() { delete (super.foo) } method2() { delete super["foo"] } }'); |
| shouldThrow('(new x).method1()', '"ReferenceError: Cannot delete a super property"'); |
| shouldThrow('(new x).method2()', '"ReferenceError: Cannot delete a super property"'); |
| shouldBeTrue('(new (class { constructor() { super.property = "ABC"; } })).property === "ABC"'); |
| shouldBeTrue('(new (class extends Base { constructor() { super(); super.property = "ABC"; } })).property === "ABC"'); |
| shouldBeTrue('(new (class { constructor() { var arr = () => super.property = "ABC"; arr(); } })).property === "ABC"'); |
| shouldBeTrue('(new (class { constructor() { var async_arr = async () => super.property = "ABC"; async_arr(); } })).property === "ABC"'); |
| shouldBeTrue('(new (class { constructor() { eval(\'super.property = "ABC"\'); } })).property === "ABC"'); |
| shouldBeTrue('(new (class { constructor() { var arr = () => eval(\'super.property = "ABC"\'); arr(); } })).property === "ABC"'); |
| shouldBeTrue('new (class { constructor() { return undefined; } }) instanceof Object'); |
| shouldBeTrue('new (class { constructor() { return 1; } }) instanceof Object'); |
| shouldThrow('new (class extends Base { constructor() { return undefined } })'); |
| shouldBeTrue('new (class extends Base { constructor() { super(); return undefined } }) instanceof Object'); |
| shouldBe('x = { }; new (class extends Base { constructor() { return x } });', 'x'); |
| shouldBeFalse('x instanceof Base'); |
| shouldThrow('new (class extends Base { constructor() { } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`); |
| shouldThrow('new (class extends Base { constructor() { return 1; } })', '"TypeError: Cannot return a non-object type in the constructor of a derived class."'); |
| shouldThrow('new (class extends null { constructor() { return undefined } })'); |
| shouldThrow('new (class extends null { constructor() { super(); return undefined } })', '"TypeError: function is not a constructor (evaluating \'super()\')"'); |
| shouldBe('x = { }; new (class extends null { constructor() { return x } });', 'x'); |
| shouldBeTrue('x instanceof Object'); |
| shouldThrow('new (class extends null { constructor() { } })'); |
| shouldThrow('new (class extends null { constructor() { return 1; } })'); |
| shouldThrow('new (class extends null { constructor() { super() } })', '"TypeError: function is not a constructor (evaluating \'super()\')"'); |
| shouldThrow('new (class { constructor() { super() } })', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('function x() { super(); }', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('new (class extends Object { constructor() { function x() { super() } } })', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('new (class extends Object { constructor() { function x() { super.method } } })', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('function x() { super.method(); }', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('function x() { super(); }', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('eval("super.method()")', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('eval("super()")', '"SyntaxError: super is not valid in this context."'); |
| |
| shouldThrow('(function () { eval("super.method()");})()', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('(function () { eval("super()");})()', '"SyntaxError: super is not valid in this context."'); |
| |
| shouldThrow('new (class { constructor() { (function () { eval("super()");})(); } })', '"SyntaxError: super is not valid in this context."'); |
| shouldThrow('(new (class { method() { (function () { eval("super.method()");})(); }})).method()', '"SyntaxError: super is not valid in this context."'); |
| |
| shouldThrow('new (class extends Base { constructor() { super(); super();}})', '"ReferenceError: \'super()\' can\'t be called more than once in a constructor."'); |
| shouldThrow('(new class D extends class { m() {}} { constructor() { eval(\'super["m"]()\') } })', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`); |
| shouldThrow('new class extends class { m() {}} { constructor() { super["m"](super()) } }', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`); |
| shouldThrow('(new class D extends class { m() {}} { constructor(f) { super[f()]() } }(()=>"m"))', `"ReferenceError: 'super()' must be called in derived constructor before accessing |this| or returning non-object."`); |
| |
| shouldNotThrow('(new class D extends class { m() {}} { constructor() { super(); eval(\'super["m"]()\') } })'); |
| shouldThrow('new class extends class { m() {}} { constructor() { super(); super["m"](super()) } }', '"ReferenceError: \'super()\' can\'t be called more than once in a constructor."'); |
| shouldNotThrow('(new class D extends class { m() {}} { constructor(f) { super(); super[f()]() } }(()=>"m"))'); |
| |
| var successfullyParsed = true; |