react / wstein / node_modules / react / node_modules / envify / node_modules / jstransform / visitors / __tests__ / es6-class-visitors-test.js
80552 views/**1* Copyright 2013 Facebook, Inc.2*3* Licensed under the Apache License, Version 2.0 (the "License");4* you may not use this file except in compliance with the License.5* You may obtain a copy of the License at6*7* http://www.apache.org/licenses/LICENSE-2.08*9* Unless required by applicable law or agreed to in writing, software10* distributed under the License is distributed on an "AS IS" BASIS,11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12* See the License for the specific language governing permissions and13* limitations under the License.14*15* @emails [email protected]16*/1718/*jshint evil:true*/19/*jshint -W117*/2021jest.autoMockOff();2223describe('es6-classes', function() {24var transformFn;25var classVisitors;26var arrowFunctionVisitors;27var visitors;2829beforeEach(function() {30require('mock-modules').dumpCache();3132transformFn = require('../../src/jstransform').transform;3334classVisitors = require('../es6-class-visitors').visitorList;35arrowFunctionVisitors = require('../es6-arrow-function-visitors').visitorList;3637visitors = classVisitors.concat(arrowFunctionVisitors);38});3940function transform(code, opts) {41return transformFn(visitors, code, opts).code;42}4344describe('ClassDeclarations', function() {45describe('preserves line numbers', function() {46it('does not add "use strict" unless necessary', function() {47var code = [48'function strictStuff() {',49' "use strict";',50' class A {',51' foo() {}',52' }',53'}',54'class B {',55' bar() {',56' class C {}',57' }',58'}'59].join('\n');6061var expected = [62'function strictStuff() {',63' "use strict";',64' function A(){}',65' Object.defineProperty(A.prototype,"foo",{writable:true,configurable:true,value:function() {}});',66' ',67'}',68'function B(){"use strict";}',69' Object.defineProperty(B.prototype,"bar",{writable:true,configurable:true,value:function() {"use strict";',70' function C(){}',71' }});',72''73].join('\n');7475expect(transform(code)).toBe(expected);76});7778it('preserves lines with no inheritance', function() {79var code = [80'"use strict";',81'class Foo {',82' foo() {',83' ',84' ',85' }',86'',87' constructor(p1,',88' p2) {',89'',90' this.p1 = p1;',91' this.p2 = p2;',92' }',93'',94' bar(){}',95' static baz() {',96'}',97'}'98].join('\n');99100var expected = [101'"use strict";',102'',103' Object.defineProperty(Foo.prototype,"foo",{writable:true,configurable:true,value:function() {',104' ',105' ',106' }});',107'',108' function Foo(p1,',109' p2) {',110'',111' this.p1 = p1;',112' this.p2 = p2;',113' }',114'',115' Object.defineProperty(Foo.prototype,"bar",{writable:true,configurable:true,value:function(){}});',116' Object.defineProperty(Foo,"baz",{writable:true,configurable:true,value:function() {',117'}});',118''119].join('\n');120121expect(transform(code)).toBe(expected);122});123124it('preserves lines with inheritance from identifier', function() {125var code = [126'class Foo extends Bar {',127' foo() {',128' ',129' ',130' super(p1,',131' p2);',132' }',133'',134' constructor(p1,',135' p2) {',136'',137' this.p1 = p1;',138' this.p2 = p2;',139' super.blah(p1,',140' p2);',141' }',142'',143' bar(){}',144' static baz() {',145'}',146'}'147].join('\n');148149var expected = [150'for(var Bar____Key in Bar){' +151'if(Bar.hasOwnProperty(Bar____Key)){' +152'Foo[Bar____Key]=Bar[Bar____Key];' +153'}' +154'}' +155'var ____SuperProtoOfBar=' +156'Bar===null' +157'?null:' +158'Bar.prototype;' +159'Foo.prototype=Object.create(____SuperProtoOfBar);' +160'Foo.prototype.constructor=Foo;' +161'Foo.__superConstructor__=Bar;',162163' Object.defineProperty(Foo.prototype,"foo",{writable:true,configurable:true,value:function() {"use strict";',164' ',165' ',166' ____SuperProtoOfBar.foo.call(this,p1,',167' p2);',168' }});',169'',170' function Foo(p1,',171' p2) {"use strict";',172'',173' this.p1 = p1;',174' this.p2 = p2;',175' ____SuperProtoOfBar.blah.call(this,p1,',176' p2);',177' }',178'',179' Object.defineProperty(Foo.prototype,"bar",{writable:true,configurable:true,value:function(){"use strict";}});',180' Object.defineProperty(Foo,"baz",{writable:true,configurable:true,value:function() {"use strict";',181'}});',182''183].join('\n');184185expect(transform(code)).toBe(expected);186});187188it('preserves lines with inheritance from expression', function() {189var code = [190'class Foo extends mixin(Bar, Baz) {',191' foo() {',192' ',193' ',194' }',195'',196' constructor(p1,',197' p2) {',198'',199' this.p1 = p1;',200' this.p2 = p2;',201' }',202'',203' bar(){}',204' static baz() {',205'}',206'}'207].join('\n');208209var expected = [210'var ____Class0=mixin(Bar, Baz);' +211'for(var ____Class0____Key in ____Class0){' +212'if(____Class0.hasOwnProperty(____Class0____Key)){' +213'Foo[____Class0____Key]=____Class0[____Class0____Key];' +214'}' +215'}' +216'var ____SuperProtoOf____Class0=' +217'____Class0===null' +218'?null' +219':____Class0.prototype;' +220'Foo.prototype=Object.create(____SuperProtoOf____Class0);' +221'Foo.prototype.constructor=Foo;' +222'Foo.__superConstructor__=____Class0;',223224' Object.defineProperty(Foo.prototype,"foo",{writable:true,configurable:true,value:function() {"use strict";',225' ',226' ',227' }});',228'',229' function Foo(p1,',230' p2) {"use strict";',231'',232' this.p1 = p1;',233' this.p2 = p2;',234' }',235'',236' Object.defineProperty(Foo.prototype,"bar",{writable:true,configurable:true,value:function(){"use strict";}});',237' Object.defineProperty(Foo,"baz",{writable:true,configurable:true,value:function() {"use strict";',238'}});',239''240].join('\n');241242expect(transform(code)).toBe(expected);243});244});245246describe('functional tests', function() {247it('handles an empty body', function() {248var code = transform(249'class Foo {}'250);251252eval(code);253254var fooInst = new Foo();255expect(fooInst instanceof Foo).toBe(true);256});257258it('handles constructors without params', function() {259var code = transform([260'class Foo {',261' constructor() {',262' this.test = "testValue";',263' }',264'}'265].join('\n'));266267eval(code);268269var fooInst = new Foo();270expect(fooInst.test).toBe('testValue');271});272273it('handles constructors with params', function() {274var code = transform([275'class Foo {',276' constructor(p1, p2) {',277' this.p1 = p1;',278' this.p2 = p2;',279' }',280'}'281].join('\n'));282283eval(code);284285var fooInst = new Foo('a', 'b');286expect(fooInst.p1).toBe('a');287expect(fooInst.p2).toBe('b');288});289290it('handles prototype methods without params', function() {291var code = transform([292'class Foo {',293' bar() {',294' return "stuff";',295' }',296'}'297].join('\n'));298299eval(code);300301var fooInst = new Foo();302expect(fooInst.bar()).toBe('stuff');303});304305it('handles prototype methods with params', function() {306var code = transform([307'class Foo {',308' bar(p1, p2) {',309' this.p1 = p1;',310' this.p2 = p2;',311' }',312'}'313].join('\n'));314315eval(code);316317var fooInst = new Foo();318fooInst.bar('a', 'b');319expect(fooInst.p1).toBe('a');320expect(fooInst.p2).toBe('b');321});322323it('handles static methods without params', function() {324var code = transform([325'class Foo {',326' static bar() {',327' return "stuff";',328' }',329'}'330].join('\n'));331332eval(code);333334expect(Foo.bar()).toBe('stuff');335var fooInst = new Foo();336expect(fooInst.bar).toBe(undefined);337});338339it('handles static methods with params', function() {340var code = transform([341'class Foo {',342' static bar(p1, p2) {',343' return [p1, p2];',344' }',345'}'346].join('\n'));347348eval(code);349350expect(Foo.bar('a', 'b')).toEqual(['a', 'b']);351var fooInst = new Foo();352expect(fooInst.bar).toBe(undefined);353});354355it('handles extension from an identifier', function() {356var code = transform([357'function Parent() {}',358'Parent.prototype.protoProp = "protoProp";',359'Parent.staticProp = "staticProp";',360361'class Child extends Parent {}'362].join('\n'));363364var exports = new Function(365code + 'return {Child: Child, Parent: Parent};'366)();367var Child = exports.Child;368var Parent = exports.Parent;369370expect(Child.protoProp).toBe(undefined);371expect(Child.staticProp).toBe('staticProp');372var childInst = new Child();373expect(childInst instanceof Child).toBe(true);374expect(childInst instanceof Parent).toBe(true);375expect(childInst.protoProp).toBe('protoProp');376});377378// ES6 draft section 14.5379it('handles extension from a left hand expression', function() {380var code = transform([381'function Parent1() {}',382'Parent1.prototype.protoProp = "protoProp";',383'Parent1.staticProp = "staticProp";',384385'function Parent2() {}',386387'class Child extends (true ? Parent1 : Parent2) {}'388].join('\n'));389390var exports = new Function(391code + 'return {Parent1: Parent1, Child: Child};'392)();393var Child = exports.Child;394var Parent1 = exports.Parent1;395396expect(Child.protoProp).toBe(undefined);397expect(Child.staticProp).toBe('staticProp');398var childInst = new Child();399expect(childInst instanceof Child).toBe(true);400expect(childInst instanceof Parent1).toBe(true);401expect(childInst.protoProp).toBe('protoProp');402expect(childInst.staticProp).toBe(undefined);403});404405it('runs parent constructor when child constructor absent', function() {406var code = transform([407'class Parent {',408' constructor(p1, p2) {',409' this.p1 = p1;',410' this.p2 = p2;',411' }',412'}',413414'class Child extends Parent {}'415].join('\n'));416417var Child = new Function(code + 'return Child;')();418419var childInst = new Child('a', 'b');420expect(childInst.p1).toBe('a');421expect(childInst.p2).toBe('b');422});423424it('sets constructor property to point at constructor func', function() {425var code = transform([426'class Parent {}',427'class Child extends Parent {}'428].join('\n'));429430var Child = new Function(code + 'return Child;')();431432var childInst = new Child();433expect(childInst.constructor).toBe(Child);434});435436it('handles super CallExpressions within constructors', function() {437var code = transform([438'class Parent {',439' constructor(p1, p2) {',440' this.p1 = p1;',441' this.p2 = p2;',442' }',443'}',444445'class Child extends Parent {',446' constructor() {',447' super("a", "b");',448' this.childRan = true;',449' }',450'}'451].join('\n'));452453var Child = new Function(code + 'return Child;')();454455var childInst = new Child();456expect(childInst.p1).toBe('a');457expect(childInst.p2).toBe('b');458expect(childInst.childRan).toBe(true);459});460461it('handles super CallExpressions within proto methods', function() {462var code = transform([463'class Parent {',464' bar(p1, p2) {',465' this.p1 = p1;',466' this.p2 = p2;',467' }',468' "baz qux"(p3) {',469' this.p3 = p3;',470' }',471'}',472473'class Child extends Parent {',474' bar() {',475' super("a", "b");',476' this.barRan = true;',477' }',478' "baz qux"() {',479' super("c");',480' this["baz qux run"] = true;',481' }',482'}'483].join('\n'));484485var Child = new Function(code + 'return Child;')();486487var childInst = new Child();488expect(childInst.p1).toBe(undefined);489expect(childInst.p2).toBe(undefined);490expect(childInst.barRan).toBe(undefined);491492childInst.bar();493expect(childInst.p1).toBe('a');494expect(childInst.p2).toBe('b');495expect(childInst.barRan).toBe(true);496497expect(childInst.p3).toBe(undefined);498expect(childInst['baz qux run']).toBe(undefined);499500childInst['baz qux']();501expect(childInst.p3).toBe('c');502expect(childInst['baz qux run']).toBe(true);503});504505it('handles computed super MemberExpressions',506function() {507var code = transform([508'class Parent {',509' constructor() {',510' this.counter = 0;',511' }',512' incrementCounter(amount) {',513' this.counter += amount;',514' }',515'}',516517'class Child extends Parent {',518' childIncrement() {',519' super["increment" + "Counter"](2);',520' }',521'}'522].join('\n'));523524var Child = new Function(code + 'return Child;')();525526var childInst = new Child();527expect(childInst.counter).toBe(0);528childInst.childIncrement();529expect(childInst.counter).toBe(2);530});531532it('handles simple super MemberExpression access', function() {533var code = transform([534'class Parent {',535' getFoo(p) {',536' return "foo" + p;',537' }',538'}',539540'class Child extends Parent {',541' getChildFoo() {',542' var x = super.getFoo;',543' return x("bar");',544' }',545'}'546].join('\n'));547548var Child = new Function(code + 'return Child;')();549550var childInst = new Child();551expect(childInst.getChildFoo()).toBe('foobar');552});553554it('handles CallExpression on a super MemberExpression', function() {555var code = transform([556'class Parent {',557' getFoo(p) {',558' this.fooValue = "foo";',559' return this.fooValue + p;',560' }',561'}',562563'class Child extends Parent {',564' getChildFoo() {',565' return super.getFoo.call(this, "bar");',566' }',567'}'568].join('\n'));569570var Child = new Function(code + 'return Child;')();571572var childInst = new Child();573expect(childInst.getChildFoo()).toBe('foobar');574expect(childInst.fooValue).toBe('foo');575});576577it('handles super MemberExpressions within constructors', function() {578var code = transform([579'class Parent {',580' setParams(p1, p2) {',581' this.p1 = p1;',582' this.p2 = p2;',583' }',584'}',585586'class Child extends Parent {',587' constructor() {',588' super.setParams("a", "b");',589' }',590'}'591].join('\n'));592593var Child = new Function(code + 'return Child;')();594595var childInst = new Child();596expect(childInst.p1).toBe('a');597expect(childInst.p2).toBe('b');598});599600it('handles super MemberExpressions within proto methods', function() {601var code = transform([602'class Parent {',603' setParams(p1, p2) {',604' this.p1 = p1;',605' this.p2 = p2;',606' }',607'}',608609'class Child extends Parent {',610' bar() {',611' super.setParams("a", "b");',612' this.barRan = true;',613' }',614'}'615].join('\n'));616617var Child = new Function(code + 'return Child;')();618619var childInst = new Child();620expect(childInst.p1).toBe(undefined);621expect(childInst.p2).toBe(undefined);622expect(childInst.barRan).toBe(undefined);623childInst.bar();624expect(childInst.p1).toBe('a');625expect(childInst.p2).toBe('b');626expect(childInst.barRan).toBe(true);627});628629it('consistently munges private property identifiers', function() {630var code = transform([631'class Foo {',632' constructor(p1) {',633' this._p1 = p1;',634' }',635' getP1() {',636' return this._p1;',637' }',638'}'639].join('\n'));640641eval(code);642643var fooInst = new Foo('a');644expect(fooInst._p1).toBe(undefined);645expect(fooInst.getP1()).toBe('a');646});647648it('stores munged private properties on the instance', function() {649// Protects against subtle transform bugs like:650// `this._p1 = 42` -> `this$Foo_p1 = 42`651var code = transform([652'class Foo {',653' constructor(p1) {',654' this._p1 = p1;',655' }',656' getP1() {',657' return this._p1;',658' }',659'}'660].join('\n'));661662eval(code);663664var fooInst1 = new Foo('a');665var fooInst2 = new Foo('b');666expect(fooInst1.getP1()).toBe('a');667expect(fooInst2.getP1()).toBe('b');668});669670it('consistently munges nested private property identifiers', function() {671var code = transform([672'class Foo {',673' constructor(p1) {',674' this._data = {_p1: null};',675' this._data._p1 = p1;',676' }',677' getData() {',678' return this._data;',679' }',680' getP1() {',681' return this._data._p1;',682' }',683'}'684].join('\n'));685686eval(code);687688var fooInst = new Foo('a');689expect(fooInst.getData()._p1).toBe(undefined);690expect(fooInst.getP1()).toBe('a');691});692693it('consistently munges private method identifiers', function() {694var code = transform([695'class Foo {',696' getBar() {',697' return this._getBar();',698' }',699' _getBar() {',700' return 42;',701' }',702'}'703].join('\n'));704705eval(code);706707var fooInst = new Foo();708expect(fooInst._getBar).toBe(undefined);709expect(fooInst.getBar()).toBe(42);710});711712it('consistently munges private method params', function() {713var code = transform([714'class Foo {',715' bar(_counter, _function) {',716' this.counter = _counter;',717' _function();',718' }',719'}'720].join('\n'));721722eval(code);723724var fooInst = new Foo();725var callbackCalled = false;726fooInst.bar(42, function() { callbackCalled = true; });727expect(fooInst.counter).toBe(42);728expect(callbackCalled).toBe(true);729});730731it('consistently munges private idents in super call params', function() {732var code = transform([733'class Parent {',734' constructor(foo) {',735' this.foo = foo;',736' }',737' setBar(bar) {',738' this.bar = bar;',739' }',740'}',741'class Child extends Parent {',742' constructor(_foo, _bar) {',743' super(_foo);',744' super.setBar(_bar);',745' }',746'}'747].join('\n'));748749var Child = new Function(code + 'return Child;')();750751var childInst = new Child('foo', 'bar');752expect(childInst.foo).toBe('foo');753expect(childInst.bar).toBe('bar');754});755756it('consistently munges private idents in nested funcs', function() {757var code = transform([758'class Foo {',759' bar(_p1, p2) {',760' return function(_a) {',761' return [_p1, p2, _a];',762' };',763' }',764'}'765].join('\n'));766767eval(code);768769var fooInst = new Foo();770expect(fooInst.bar('a', 'b')('c')).toEqual(['a', 'b', 'c']);771});772773it('consistently munges private idents in nested arrow funcs', function() {774var code = transform([775'class Foo {',776' bar(_p1, p2) {',777' return (_a, b) => {',778' return [_p1, p2, _a, b];',779' };',780' }',781'}'782].join('\n'));783784eval(code);785786var fooInst = new Foo();787expect(fooInst.bar('a', 'b')('c', 'd')).toEqual(['a', 'b', 'c', 'd']);788});789790it('does not munge dunder-scored properties', function() {791var code = transform([792'class Foo {',793' constructor(p1) {',794' this.__p1 = p1;',795' }',796'}'797].join('\n'));798799eval(code);800801var fooInst = new Foo('a');802expect(fooInst.__p1).toBe('a');803});804805it('does not munge dunder-scored methods', function() {806var code = transform([807'class Foo {',808' __getBar() {',809' return 42;',810' }',811'}'812].join('\n'));813814eval(code);815816var fooInst = new Foo();817expect(fooInst.__getBar()).toBe(42);818});819820it('properly handles private vars declared in outer scope', function() {821var code = transform([822'var _bar = "outer";',823'class Foo {',824' getOuterBar() {',825' return _bar;',826' }',827'}'828].join('\n'));829830var Foo = new Function(code + 'return Foo;')();831832var fooInst = new Foo();833expect(fooInst.getOuterBar()).toBe('outer');834});835836it('does not munge outer-declared private vars when used to calculate ' +837'a computed member expression', function() {838var code = transform([839'var _privateObjKey = "pvt";',840'var outerDataStore = {pvt: 42};',841'class Foo {',842' getStuff() {',843' return outerDataStore[_privateObjKey];',844' }',845'}'846].join('\n'));847848var Foo = new Function(code + 'return Foo;')();849850var fooInst = new Foo();851expect(fooInst.getStuff()).toBe(42);852});853854it('properly handles private vars declared in inner scope', function() {855var code = transform([856'var _bar = {_private: 42};',857'class Foo {',858' getBarPrivate(p1) {',859' var _bar = {_private: p1};',860' return _bar._private;',861' }',862'}'863].join('\n'));864865eval(code);866867var fooInst = new Foo();868expect(fooInst.getBarPrivate('a')).toBe('a');869});870871it('munges properties of private vars declared out of scope', function() {872var code = transform([873'var _bar = {_private: 42}',874'class Foo {',875' getOuterPrivate() {',876' return _bar._private;',877' }',878'}'879].join('\n'));880881var exports = new Function(code + 'return {_bar: _bar, Foo: Foo};')();882var _bar = exports._bar;883var Foo = exports.Foo;884885var fooInst = new Foo();886expect(_bar._private).toBe(42);887expect(fooInst.getOuterPrivate()).toBe(undefined);888});889890it('does not munge when @preventMunge is specified', function() {891var code = transform([892'/**',893' * @preventMunge',894' */',895'class Foo {',896' constructor(p1) {',897' this._p1 = p1;',898' }',899' _privateMethod() {',900' }',901'}'902].join('\n'));903904eval(code);905906var fooInst = new Foo('a');907expect(fooInst._p1).toBe('a');908expect(fooInst._privateMethod).not.toBe(undefined);909});910911it('minifies private properties when minify opt is set', function() {912var code = transform([913'class Foo {',914' constructor(p1) {',915' this._p1 = p1;',916' }',917'}'918].join('\n'), {minify: true});919920eval(code);921922var fooInst = new Foo('a');923expect(fooInst.$Foo0).toBe('a');924});925926it('minifies private methods when minify opt is set', function() {927var code = transform([928'class Foo {',929' _bar() {',930' return 42;',931' }',932'}'933].join('\n'), {minify: true});934935eval(code);936937var fooInst = new Foo();938expect(fooInst.$Foo0()).toBe(42);939});940941it('munges child class different from parent in same file', function() {942var code = transform([943'class Parent {',944' setParentFoo(foo) {',945' this._foo = foo;',946' }',947' getParentFoo() {',948' return this._foo;',949' }',950'}',951952'class Child extends Parent {',953' setChildFoo(foo) {',954' this._foo = foo;',955' }',956' getChildFoo() {',957' return this._foo;',958' }',959'}'960].join('\n'));961962var Child = new Function(code + 'return Child;')();963964var childInst = new Child();965childInst.setParentFoo('parent');966childInst.setChildFoo('child');967expect(childInst.getParentFoo()).toBe('parent');968expect(childInst.getChildFoo()).toBe('child');969});970971it('munges child class different from parent in other file', function() {972var code1 = transform([973'class Parent {',974' setParentFoo(foo) {',975' this._foo = foo;',976' }',977' getParentFoo() {',978' return this._foo;',979' }',980'}'981].join('\n'));982983var code2 = transform([984'class Child extends Parent {',985' setChildFoo(foo) {',986' this._foo = foo;',987' }',988' getChildFoo() {',989' return this._foo;',990' }',991'}'992].join('\n'));993994var exports = new Function(995code1 + code2 + 'return {Parent: Parent, Child: Child};'996)();997var Child = exports.Child;998999var childInst = new Child();1000childInst.setParentFoo('parent');1001childInst.setChildFoo('child');1002expect(childInst.getParentFoo()).toBe('parent');1003expect(childInst.getChildFoo()).toBe('child');1004});10051006it('makes class methods implicitly "use strict"', function() {1007var code = transform([1008'class Foo {',1009' constructor() {',1010' this.constructorIsStrict = ' +1011'(function() {return this === undefined;})();',1012' }',1013' protoFn() {',1014' return (function() {return this === undefined;})();',1015' }',1016' static staticFn() {',1017' return (function() {return this === undefined;})();',1018' }',1019'}'1020].join('\n'));10211022eval(code);10231024var fooInst = new Foo();1025expect(fooInst.constructorIsStrict).toBe(true);1026expect(fooInst.protoFn()).toBe(true);1027expect(Foo.staticFn()).toBe(true);1028});10291030it('preserves generators', function() {1031var code = transform([1032'class Foo {',1033' static *title() {',1034' yield 21;',1035' }',1036'',1037' *gen() {',1038' yield 42;',1039' }',1040'}'1041].join('\n'));10421043expect(code).toMatch(/function\*\(/);1044expect(code).toMatch(/function\*\(/);1045});10461047it('properly handles methods in ES3 compat mode', function() {1048var code = transform([1049'class Foo {',1050' title() {',1051' return 42;',1052' }',1053'}'1054].join('\n'), {es3: true});10551056eval(code);10571058var fooInst = new Foo();1059var descriptor =1060Object.getOwnPropertyDescriptor(Foo.prototype, 'title');10611062expect(fooInst.title()).toBe(42);1063expect(descriptor.enumerable).toBe(true);1064expect(descriptor.configurable).toBe(true);1065});10661067it('properly handles static methods in ES3 compat mode', function() {1068var code = transform([1069'class Foo {',1070' static title() {',1071' return 42;',1072' }',1073'}'1074].join('\n'), {es3: true});10751076eval(code);10771078var descriptor =1079Object.getOwnPropertyDescriptor(Foo, 'title');10801081expect(Foo.title()).toBe(42);1082expect(descriptor.enumerable).toBe(true);1083expect(descriptor.configurable).toBe(true);1084});10851086it('properly handles getter methods in ES5 compat mode', function() {1087var code = transform([1088'class Foo {',1089' get title() {',1090' return 42;',1091' }',1092' get "foo bar"() {',1093' return 21;',1094' }',1095'}'1096].join('\n'), {es5: true});10971098eval(code);10991100var fooInst = new Foo();1101var descriptor =1102Object.getOwnPropertyDescriptor(Foo.prototype, 'title');11031104expect(fooInst.title).toBe(42);1105expect(descriptor.enumerable).toBe(false);1106expect(descriptor.configurable).toBe(true);1107expect(fooInst['foo bar']).toBe(21);1108});11091110it('properly handles setter methods in ES5 compat mode', function() {1111var code = transform([1112'class Foo {',1113' set title(value) {',1114' this.__title = 42;',1115' }',1116' set "foo bar"(value) {',1117' this.__fooBar = 21;',1118' }',1119'}'1120].join('\n'), {es5: true});11211122eval(code);11231124var fooInst = new Foo();1125fooInst.title = 42;1126fooInst['foo bar'] = 21;1127var descriptor =1128Object.getOwnPropertyDescriptor(Foo.prototype, 'title');11291130expect(fooInst.__title).toBe(42);1131expect(descriptor.enumerable).toBe(false);1132expect(descriptor.configurable).toBe(true);1133expect(fooInst.__fooBar).toBe(21);1134});11351136it('properly handles getters and setters in ES5 compat mode', function() {1137var code = transform([1138'class Foo {',1139' get title() {',1140' return this.__title;',1141' }',1142'',1143' set title(value) {',1144' this.__title = value;',1145' }',1146'}'1147].join('\n'), {es5: true});11481149eval(code);11501151var fooInst = new Foo();1152var descriptor =1153Object.getOwnPropertyDescriptor(Foo.prototype, 'title');1154fooInst.title = 42;11551156expect(fooInst.__title).toBe(42);1157expect(fooInst.title).toBe(42);1158expect(descriptor.enumerable).toBe(false);1159expect(descriptor.configurable).toBe(true);1160});11611162it('properly handles static and non-static getters and setters ' +1163'with the same name in ES5 compat mode', function() {1164var code = transform([1165'class Foo {',1166' static get title() {',1167' return this._title;',1168' }',1169'',1170' static set title(value) {',1171' this._title = value;',1172' }',1173'',1174' get title() {',1175' return this.__title;',1176' }',1177'',1178' set title(value) {',1179' this.__title = value;',1180' }',1181'}'1182].join('\n'), {es5: true});11831184eval(code);11851186var fooInst = new Foo();1187Foo.title = 21;1188fooInst.title = 42;11891190expect(Foo.title).toBe(21);1191expect(fooInst.title).toBe(42);1192});11931194it('properly handles private getters and setters in ES5 compat mode',1195function() {1196var code = transform([1197'class Foo {',1198' get title() {',1199' return this._private;',1200' }',1201'',1202' set title(value) {',1203' this._private = value;',1204' }',1205'',1206' get _private() {',1207' return this.__superPrivate;',1208' }',1209'',1210' set _private(value) {',1211' this.__superPrivate = value;',1212' }',1213'}'1214].join('\n'), {es5: true});12151216eval(code);12171218var fooInst = new Foo();1219fooInst.title = 42;12201221expect(fooInst.__superPrivate).toBe(42);1222});12231224it('throws upon encountering getter methods', function() {1225expect(function() {1226transform([1227'class Foo {',1228' get title() {',1229' return 42;',1230' }',1231'}'1232].join('\n'));1233}).toThrow(1234'This transform does not support getter methods for ES6 classes. ' +1235'(line: 2, col: 2)'1236);1237});12381239it('throws upon encountering setter methods', function() {1240expect(function() {1241transform([1242'class Foo {',1243' set title(value) {',1244' this._title = value;',1245' }',1246'}'1247].join('\n'));1248}).toThrow(1249'This transform does not support setter methods for ES6 classes. ' +1250'(line: 2, col: 2)'1251);1252});1253});1254});12551256describe('ClassExpressions', function() {1257describe('preserves line numbers', function() {1258it('preserves lines with no inheritance', function() {1259var code = [1260'var Foo = class {',1261' foo() {',1262' ',1263' ',1264' }',1265'',1266' constructor(p1,',1267' p2) {',1268'',1269' this.p1 = p1;',1270' this.p2 = p2;',1271' }',1272'',1273' bar(){}',1274' static baz() {',1275'}',1276'}'1277].join('\n');12781279var expected = [1280'var Foo = (function(){',1281' Object.defineProperty(____Class0.prototype,"foo",{writable:true,configurable:true,value:function() {"use strict";',1282' ',1283' ',1284' }});',1285'',1286' function ____Class0(p1,',1287' p2) {"use strict";',1288'',1289' this.p1 = p1;',1290' this.p2 = p2;',1291' }',1292'',1293' Object.defineProperty(____Class0.prototype,"bar",{writable:true,configurable:true,value:function(){"use strict";}});',1294' Object.defineProperty(____Class0,"baz",{writable:true,configurable:true,value:function() {"use strict";',1295'}});',1296'return ____Class0;})()'1297].join('\n');12981299expect(transform(code)).toBe(expected);1300});13011302it('preserves lines with inheritance from identifier', function() {1303var code = [1304'var Foo = class extends Bar {',1305' foo() {',1306' ',1307' ',1308' super(p1,',1309' p2);',1310' }',1311'',1312' constructor(p1,',1313' p2) {',1314'',1315' this.p1 = p1;',1316' this.p2 = p2;',1317' super.blah(p1,',1318' p2);',1319' }',1320'',1321' bar(){}',1322' static baz() {',1323'}',1324'}'1325].join('\n');13261327var expected = [1328'var Foo = (function(){' +1329'for(var Bar____Key in Bar){' +1330'if(Bar.hasOwnProperty(Bar____Key)){' +1331'____Class0[Bar____Key]=Bar[Bar____Key];' +1332'}' +1333'}' +1334'var ____SuperProtoOfBar=' +1335'Bar===null' +1336'?null' +1337':Bar.prototype;' +1338'____Class0.prototype=Object.create(____SuperProtoOfBar);' +1339'____Class0.prototype.constructor=____Class0;' +1340'____Class0.__superConstructor__=Bar;',13411342' Object.defineProperty(____Class0.prototype,"foo",{writable:true,configurable:true,value:function() {"use strict";',1343' ',1344' ',1345' ____SuperProtoOfBar.foo.call(this,p1,',1346' p2);',1347' }});',1348'',1349' function ____Class0(p1,',1350' p2) {"use strict";',1351'',1352' this.p1 = p1;',1353' this.p2 = p2;',1354' ____SuperProtoOfBar.blah.call(this,p1,',1355' p2);',1356' }',1357'',1358' Object.defineProperty(____Class0.prototype,"bar",{writable:true,configurable:true,value:function(){"use strict";}});',1359' Object.defineProperty(____Class0,"baz",{writable:true,configurable:true,value:function() {"use strict";',1360'}});',1361'return ____Class0;})()'1362].join('\n');13631364expect(transform(code)).toBe(expected);1365});13661367it('preserves lines with inheritance from expression', function() {1368var code = [1369'var Foo = class extends mixin(Bar, Baz) {',1370' foo() {',1371' ',1372' ',1373' }',1374'',1375' constructor(p1,',1376' p2) {',1377'',1378' this.p1 = p1;',1379' this.p2 = p2;',1380' }',1381'',1382' bar(){}',1383' static baz() {',1384'}',1385'}'1386].join('\n');13871388var expected = [1389'var Foo = (function(){' +1390'var ____Class1=mixin(Bar, Baz);' +1391'for(var ____Class1____Key in ____Class1){' +1392'if(____Class1.hasOwnProperty(____Class1____Key)){' +1393'____Class0[____Class1____Key]=____Class1[____Class1____Key];' +1394'}' +1395'}' +1396'var ____SuperProtoOf____Class1=' +1397'____Class1===null' +1398'?null' +1399':____Class1.prototype;' +1400'____Class0.prototype=Object.create(____SuperProtoOf____Class1);' +1401'____Class0.prototype.constructor=____Class0;' +1402'____Class0.__superConstructor__=____Class1;',14031404' Object.defineProperty(____Class0.prototype,"foo",{writable:true,configurable:true,value:function() {"use strict";',1405' ',1406' ',1407' }});',1408'',1409' function ____Class0(p1,',1410' p2) {"use strict";',1411'',1412' this.p1 = p1;',1413' this.p2 = p2;',1414' }',1415'',1416' Object.defineProperty(____Class0.prototype,"bar",{writable:true,configurable:true,value:function(){"use strict";}});',1417' Object.defineProperty(____Class0,"baz",{writable:true,configurable:true,value:function() {"use strict";',1418'}});',1419'return ____Class0;})()'1420].join('\n');14211422expect(transform(code)).toBe(expected);1423});1424});14251426describe('functional tests', function() {1427it('scopes each anonymous class separately', function() {1428var code = transform([1429'var Foo = class {',1430' constructor() {',1431' this._name = "foo";',1432' var properties = [];',1433' for (var key in this) {',1434' properties.push(key);',1435' }',1436' this.properties = properties',1437' }',1438'};',14391440'var Bar = class {',1441' constructor() {',1442' this._name = "bar";',1443' var properties = [];',1444' for (var key in this) {',1445' properties.push(key);',1446' }',1447' this.properties = properties',1448' }',1449'}'1450].join('\n'));14511452eval(code);14531454var fooInst = new Foo();1455var barInst = new Bar();1456expect(fooInst.properties).not.toEqual(barInst.properties);1457expect(fooInst[fooInst.properties[0]]).toBe('foo');1458expect(barInst[barInst.properties[0]]).toBe('bar');1459});1460});1461});14621463describe('handles reserved words', function() {1464it('handles reserved words', function() {1465expect(transform([1466'class Foo {',1467' delete(x, y) {',1468' bar();',1469' }',1470'}'1471].join('\n'))).toBe([1472'function Foo(){"use strict";}',1473' Object.defineProperty(Foo.prototype,"delete",{writable:true,configurable:true,value:function(x, y) {"use strict";',1474' bar();',1475' }});',1476''1477].join('\n'));1478});1479});14801481describe('preserves non-class syntax/style', function() {1482it('preserve newlines', function() {1483expect(transform([1484'class Foo {',1485' A',1486' (',1487' x, y) {',1488' bar();',1489' }',1490'}'1491].join('\n'))).toBe([1492'function Foo(){"use strict";}',1493' Object.defineProperty(Foo.prototype,"A",{writable:true,configurable:true,value:function(',1494'',1495'x, y) {"use strict";',1496' bar();',1497' }});',1498''1499].join('\n'));1500});15011502it('preserves comments between method params and open-bracket', function() {1503expect(transform([1504'class Foo {',1505' testMethod() /* comment */ {}',1506'}',1507].join('\n'))).toBe([1508'function Foo(){"use strict";}',1509' Object.defineProperty(Foo.prototype,"testMethod",{writable:true,configurable:true,value:function() /* comment */ {"use strict";}});',1510''1511].join('\n'));1512});1513});1514});151515161517