diff --git a/TODO.md b/TODO.md index 5ae25da7..69482a37 100644 --- a/TODO.md +++ b/TODO.md @@ -1,26 +1,3 @@ # TODO * Prevent injection of class into scope function for its methods. - -* Tests for `super()` in arrow functions: - -```js -class Y extends X { - constructor() { - const callSuper = () => super(); - callSuper(); - } -} -return Y; -``` - -```js -let callSuper; -class Y extends X { - constructor() { - callSuper = () => super(); - } -} -try { new Y() } catch {} -return callSuper; -``` diff --git a/test/classes.test.js b/test/classes.test.js index 7cd97fbf..3668539f 100644 --- a/test/classes.test.js +++ b/test/classes.test.js @@ -3391,6 +3391,114 @@ describe('Classes', () => { }); }); + describe('`super()` in arrow function', () => { + itSerializes('when class serialized', { + in() { + class X { + constructor() { + this.x = 1; + } + } + return class Y extends X { + constructor() { // eslint-disable-line constructor-super + const callSuper = () => super(); + callSuper(); + } + }; + }, + out: `(()=>{ + const a=Object.setPrototypeOf, + b=class X{ + constructor(){ + this.x=1 + } + }, + c=a( + class Y extends class{}{ + constructor(){ + const a=()=>super(); + a() + } + }, + b + ); + a(c.prototype,b.prototype); + return c + })()`, + validate(Klass) { + expect(Klass).toBeFunction(); + expect(Klass.name).toBe('Y'); + const {prototype} = Klass; + expect(prototype).toBeObject(); + expect(prototype.constructor).toBe(Klass); + const proto = Object.getPrototypeOf(prototype); + expect(proto).toBeObject(); + expect(proto).not.toBe(Object.prototype); + expect(proto).toHavePrototype(Object.prototype); + const SuperClass = proto.constructor; + expect(SuperClass).toBeFunction(); + expect(SuperClass.name).toBe('X'); + const instance = new Klass(); + expect(instance).toBeInstanceOf(Klass); + expect(instance).toBeInstanceOf(SuperClass); + expect(instance).toHaveOwnPropertyNames(['x']); + expect(instance.x).toBe(1); + } + }); + + itSerializes('when arrow function serialized', { + in() { + class X { + constructor() { + this.x = 1; + } + } + + class Y extends X { + constructor() { + return {callSuper: (0, () => super())}; // eslint-disable-line no-constructor-return + } + } + + return new Y().callSuper; + }, + out: `(()=>{ + const a=Object.setPrototypeOf, + b=class X{ + constructor(){ + this.x=1 + } + }, + c=a( + class Y extends class{}{ + constructor(){ + return{callSuper:(0,()=>super())} + } + }, + b + ); + a(c.prototype,b.prototype); + return(a=>()=>Reflect.construct(Object.getPrototypeOf(a),[],a))(c) + })()`, + validate(fn) { + expect(fn).toBeFunction(); + const instance = fn(); + expect(instance).toBeObject(); + expect(instance).toHaveOwnPropertyNames(['x']); + expect(instance.x).toBe(1); + const proto = Object.getPrototypeOf(instance); + expect(proto).toBeObject(); + const Klass = proto.constructor; + expect(Klass).toBeFunction(); + expect(Klass.name).toBe('Y'); + const SuperClass = Object.getPrototypeOf(Klass); + expect(SuperClass).toBeFunction(); + expect(SuperClass.name).toBe('X'); + expect(Object.getPrototypeOf(proto).constructor).toBe(SuperClass); + } + }); + }); + itSerializes("defined in another class method's computed key", { in() { let Klass;