blob: 12d0d9e96947d0cb33969cedd507750e06229388 [file] [log] [blame]
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;