react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / jstransform / src / __tests__ / jstransform-test.js
81152 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*/1718require('mock-modules').autoMockOff();1920describe('jstransform', function() {21var transformFn;22var Syntax = require('esprima-fb').Syntax;2324beforeEach(function() {25require('mock-modules').dumpCache();26transformFn = require('../jstransform').transform;27});2829function _runVisitor(source, nodeCount, visitor) {30var actualVisitationCount = 0;31function shimVisitor(traverse, node, path, state) {32actualVisitationCount++;33return visitor(traverse, node, path, state);34}35shimVisitor.test = visitor.test;36transformFn([shimVisitor], source);37expect(actualVisitationCount).toBe(nodeCount);38}3940function testScopeBoundary(source, localIdents, nodeCount, visitorTest) {41function visitor(traverse, node, path, state) {42var actualLocalIdents = Object.keys(state.localScope.identifiers);43expect(actualLocalIdents.sort()).toEqual(localIdents.sort());44}45visitor.test = visitorTest;46_runVisitor(source, nodeCount, visitor);47}4849function testParentScope(source, parentIdents, nodeCount, visitorTest) {50function visitor(traverse, node, path, state) {51parentIdents = parentIdents && parentIdents.sort();52var parentScope = state.localScope.parentScope;53var actualParentIdents =54parentScope && Object.keys(parentScope.identifiers).sort();55expect(actualParentIdents).toEqual(parentIdents);56}57visitor.test = visitorTest;58_runVisitor(source, nodeCount, visitor);59}6061describe('closure scope boundaries', function() {62it('creates a scope boundary around Program scope', function() {63var source =64'var foo;' +65'var bar, baz;' +66'function blah() {}';67var idents = ['foo', 'bar', 'baz', 'blah'];6869testScopeBoundary(source, idents, 3, function(node, path, state) {70return path[0] && path[0].type === Syntax.Program;71});72});7374it('creates a scope boundary around FunctionDeclarations', function() {75var source =76'var foo;' +77'function blah() {' +78' var bar;' +79' function nested() {' +80' var baz;' +81' }' +82'}';83var programIdents = ['foo', 'blah'];84var blahIdents = ['arguments', 'bar', 'nested'];85var nestedIdents = ['arguments', 'baz'];8687testScopeBoundary(source, programIdents, 2, function(node, path, state) {88return path[0] && path[0].type === Syntax.Program;89});9091testScopeBoundary(source, blahIdents, 2, function(node, path, state) {92// All direct children of blah()93return path[0] && path[0].type === Syntax.BlockStatement &&94path[1] && path[1].type === Syntax.FunctionDeclaration &&95path[1].id.name === 'blah';96});9798testScopeBoundary(source, nestedIdents, 1, function(node, path, state) {99// All direct children of nested()100return path[0] && path[0].type === Syntax.BlockStatement &&101path[1] && path[1].type === Syntax.FunctionDeclaration &&102path[1].id.name === 'nested';103});104});105106it('creates a scope boundary around MethodDefinitions', function() {107var source =108'var foo;' +109'class ClassA {' +110' blah() {' +111' var bar;' +112' }' +113' another() {' +114' var baz;' +115' }' +116'}';117var programIdents = ['foo', 'ClassA'];118var blahIdents = ['arguments', 'bar'];119var anotherIdents = ['arguments', 'baz'];120121testScopeBoundary(source, programIdents, 2, function(node, path, state) {122return path[0] && path[0].type === Syntax.Program;123});124125testScopeBoundary(source, blahIdents, 1, function(node, path, state) {126// All direct children of blah()127return path[0] && path[0].type === Syntax.BlockStatement &&128path[1] && path[1].type === Syntax.FunctionExpression &&129path[2] && path[2].type === Syntax.MethodDefinition &&130path[2].key.name === 'blah';131});132133testScopeBoundary(source, anotherIdents, 1, function(node, path, state) {134// All direct children of another()135return path[0] && path[0].type === Syntax.BlockStatement &&136path[1] && path[1].type === Syntax.FunctionExpression &&137path[2] && path[2].type === Syntax.MethodDefinition &&138path[2].key.name === 'another';139});140});141142it('uses VariableDeclarations to determine scope boundary', function() {143var source =144'var foo = 1;' +145'function bar() {' +146' foo++;' +147' function baz() {' +148' var foo = 2;' +149' }' +150'}';151var programIdents = ['foo', 'bar'];152var barIdents = ['arguments', 'baz'];153var bazIdents = ['arguments', 'foo'];154155testScopeBoundary(source, programIdents, 2, function(node, path, state) {156return path[0] && path[0].type === Syntax.Program;157});158159testScopeBoundary(source, barIdents, 2, function(node, path, state) {160// All direct children of blah()161return path[0] && path[0].type === Syntax.BlockStatement &&162path[1] && path[1].type === Syntax.FunctionDeclaration &&163path[1].id.name === 'bar';164});165166testScopeBoundary(source, bazIdents, 1, function(node, path, state) {167// All direct children of baz()168return path[0] && path[0].type === Syntax.BlockStatement &&169path[1] && path[1].type === Syntax.FunctionDeclaration &&170path[1].id.name === 'baz';171});172});173174it('includes function args in functions scope boundary', function() {175var source =176'var foo;' +177'function blah(bar) {' +178' var baz;' +179'}';180var programIdents = ['foo', 'blah'];181var blahIdents = ['arguments', 'bar', 'baz'];182183testScopeBoundary(source, programIdents, 2, function(node, path, state) {184return path[0] && path[0].type === Syntax.Program;185});186187testScopeBoundary(source, blahIdents, 1, function(node, path, state) {188// All direct children of blah()189return path[0] && path[0].type === Syntax.BlockStatement &&190path[1] && path[1].type === Syntax.FunctionDeclaration &&191path[1].id.name === 'blah';192});193});194195it('puts FunctionExpression names within function scope', function() {196var source =197'var foo;' +198'var bar = function baz() {' +199' var blah;' +200'};';201var programIdents = ['foo', 'bar'];202var bazIdents = ['arguments', 'baz', 'blah'];203204testScopeBoundary(source, programIdents, 2, function(node, path, state) {205return path[0] && path[0].type === Syntax.Program;206});207208testScopeBoundary(source, bazIdents, 1, function(node, path, state) {209// All direct children of baz()210return path[0] && path[0].type === Syntax.BlockStatement &&211path[1] && path[1].type === Syntax.FunctionExpression &&212path[1].id.name === 'baz';213});214});215});216217describe('block scope boundaries', function() {218it('creates a scope boundary around CatchClauses with params', function() {219var source =220'var blah = 0;' +221'try {' +222'} catch (e) {' +223' blah++;' +224'}';225var programIdents = ['blah'];226var catchIdents = ['e'];227228testScopeBoundary(source, programIdents, 2, function(node, path, state) {229return path[0] && path[0].type === Syntax.Program;230});231232testScopeBoundary(source, catchIdents, 1, function(node, path, state) {233// All direct children of catch(e) block234return path[0] && path[0].type === Syntax.BlockStatement &&235path[1] && path[1].type === Syntax.CatchClause;236});237});238239it('includes vars defined in CatchClauses in the parent scope', function() {240var source =241'try {' +242'} catch (e) {' +243' var blah;' +244'}';245var programIdents = ['blah'];246var catchIdents = ['e'];247248testScopeBoundary(source, programIdents, 1, function(node, path, state) {249return path[0] && path[0].type === Syntax.Program;250});251252testScopeBoundary(source, catchIdents, 1, function(node, path, state) {253// All direct children of catch(e) block254return path[0] && path[0].type === Syntax.BlockStatement &&255path[1] && path[1].type === Syntax.CatchClause;256});257});258});259260describe('scope chain linking', function() {261it('links parent scope boundaries', function() {262var source =263'var foo;' +264'function blah() {' +265' var bar;' +266' function nested() {' +267' var baz;' +268' }' +269'}';270var programIdents = ['foo', 'blah'];271var blahIdents = ['arguments', 'bar', 'nested'];272273testParentScope(source, programIdents, 2, function(node, path, state) {274// All direct children of blah()275return path[0] && path[0].type === Syntax.BlockStatement &&276path[1] && path[1].type === Syntax.FunctionDeclaration &&277path[1].id.name === 'blah';278});279280testParentScope(source, blahIdents, 1, function(node, path, state) {281// All direct children of nested()282return path[0] && path[0].type === Syntax.BlockStatement &&283path[1] && path[1].type === Syntax.FunctionDeclaration &&284path[1].id.name === 'nested';285});286});287288it('nests MethodDefinition boundaries under parent scope', function() {289var source =290'var foo;' +291'class ClassA {' +292' blah() {' +293' var bar;' +294' }' +295'}';296var programIdents = ['foo', 'ClassA'];297298testParentScope(source, programIdents, 1, function(node, path, state) {299// All direct children of blah()300return path[0] && path[0].type === Syntax.BlockStatement &&301path[1] && path[1].type === Syntax.FunctionExpression &&302path[2] && path[2].type === Syntax.MethodDefinition &&303path[2].key.name === 'blah';304});305});306});307308describe('"use strict" tracking', function() {309function testStrictness(expectedStrict, source) {310var visitedNodes = 0;311function visitor(traverse, node, path, state) {312visitedNodes++;313expect(state.scopeIsStrict).toBe(expectedStrict);314}315visitor.test = function(node, path, state) {316return node.type === Syntax.Literal317&& node.value === 'testStr';318};319transformFn([visitor], source);320expect(visitedNodes).toBe(1);321}322323it('detects program-level strictness', function() {324testStrictness(false, '"testStr";');325testStrictness(true, '"use strict"; "testStr";');326});327328it('detects non-inherited strictness', function() {329testStrictness(true, [330'function foo() {',331' "use strict";',332' "testStr";',333'}'334].join('\n'));335});336337it('detects program-inherited strictness', function() {338testStrictness(true, [339'"use strict";',340'function foo() {',341' "testStr";',342'}'343].join('\n'));344});345346it('detects function-inherited strictness', function() {347testStrictness(true, [348'function foo() {',349' "use strict";',350' function bar() {',351' "testStr";',352' }',353'}'354].join('\n'));355});356357it('does not detect sibling strictness', function() {358testStrictness(false, [359'function foo() {',360' "use strict";',361'}',362'function bar() {',363' "testStr";',364'}'365].join('\n'));366});367});368369describe('visitors', function() {370it('should visit nodes in order', function() {371var source = [372'// Foo comment',373'function foo() {}',374'',375'// Bar comment',376'function bar() {}'377].join('\n');378379var actualNodes = [];380381function visitFunction(traverse, node, path, state) {382actualNodes.push([node.id.name, node.range[0]]);383}384visitFunction.test = function(node, path, state) {385return node.type === Syntax.FunctionDeclaration;386};387388function visitComments(traverse, node, path, state) {389actualNodes.push([node.value, node.range[0]]);390}391visitComments.test = function(node, path, state) {392return node.type === 'Line';393};394395transformFn([visitComments, visitFunction], source);396397expect(actualNodes).toEqual([398[' Foo comment', 0],399['foo', 15],400[' Bar comment', 34],401['bar', 49]402]);403});404});405});406407408