react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / vendor / fbtransform / transforms / __tests__ / react-test.js
81164 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @emails react-core9*/1011/*jshint evil:true, unused:false*/1213"use strict";1415require('mock-modules').autoMockOff();1617describe('react jsx', function() {18var transformAll = require('../../syntax.js').transformAll;19var xjs = require('../xjs.js');2021// Add <font-face> to list of known tags to ensure that when we test support22// for hyphentated known tags, it's there.23// TODO: remove this when/if <font-face> is supported out of the box.24xjs.knownTags['font-face'] = true;2526var transform = function(code, options, excludes) {27return transformAll(28code,29options,30(excludes || []).concat(['sourcemeta', 'allocate'])31);32};3334// These are placeholder variables in scope that we can use to assert that a35// specific variable reference was passed, rather than an object clone of it.36var x = 123456;37var y = 789012;38var z = 345678;3940var expectObjectAssign = function(code) {41var Component = jest.genMockFunction();42var Child = jest.genMockFunction();43var objectAssignMock = jest.genMockFunction();44React.__spread = objectAssignMock;45eval(transform(code).code);46return expect(objectAssignMock);47}4849var React = {50createElement: jest.genMockFunction()51};5253it('should convert simple tags', function() {54var code = 'var x = <div></div>;';55var result = 'var x = React.createElement("div", null);';5657expect(transform(code).code).toEqual(result);58});5960it('should convert simple text', function() {61var code = 'var x = <div>text</div>;';62var result = 'var x = React.createElement("div", null, "text");';6364expect(transform(code).code).toEqual(result);65});6667it('should have correct comma in nested children', function() {68var code = [69'var x = <div>',70' <div><br /></div>',71' <Component>{foo}<br />{bar}</Component>',72' <br />',73'</div>;'74].join('\n');75var result = [76'var x = React.createElement("div", null, ',77' React.createElement("div", null, ' +78'React.createElement("br", null)), ',79' React.createElement(Component, null, foo, ' +80'React.createElement("br", null), bar), ',81' React.createElement("br", null)',82');'83].join('\n');8485expect(transform(code).code).toEqual(result);86});8788it('should avoid wrapping in extra parens if not needed', function() {89// Try with a single composite child, wrapped in a div.90var code = [91'var x = <div>',92' <Component />',93'</div>;'94].join('\n');95var result = [96'var x = React.createElement("div", null, ',97' React.createElement(Component, null)',98');'99].join('\n');100101expect(transform(code).code).toEqual(result);102103// Try with a single interpolated child, wrapped in a div.104code = [105'var x = <div>',106' {this.props.children}',107'</div>;'108].join('\n');109result = [110'var x = React.createElement("div", null, ',111' this.props.children',112');'113].join('\n');114expect(transform(code).code).toEqual(result);115116// Try with a single interpolated child, wrapped in a composite.117code = [118'var x = <Composite>',119' {this.props.children}',120'</Composite>;'121].join('\n');122result = [123'var x = React.createElement(Composite, null, ',124' this.props.children',125');'126].join('\n');127expect(transform(code).code).toEqual(result);128129// Try with a single composite child, wrapped in a composite.130code = [131'var x = <Composite>',132' <Composite2 />',133'</Composite>;'134].join('\n');135result = [136'var x = React.createElement(Composite, null, ',137' React.createElement(Composite2, null)',138');'139].join('\n');140expect(transform(code).code).toEqual(result);141});142143it('should insert commas after expressions before whitespace', function() {144var code = [145'var x =',146' <div',147' attr1={',148' "foo" + "bar"',149' }',150' attr2={',151' "foo" + "bar" +',152' ',153' "baz" + "bug"',154' }',155' attr3={',156' "foo" + "bar" +',157' "baz" + "bug"',158' // Extra line here.',159' }',160' attr4="baz">',161' </div>;'162].join('\n');163var result = [164'var x =',165' React.createElement("div", {',166' attr1: ',167' "foo" + "bar", ',168' ',169' attr2: ',170' "foo" + "bar" +',171' ',172' "baz" + "bug", ',173' ',174' attr3: ',175' "foo" + "bar" +',176' "baz" + "bug", ',177' // Extra line here.',178' ',179' attr4: "baz"}',180' );'181].join('\n');182183expect(transform(code).code).toEqual(result);184});185186it('should properly handle comments adjacent to children', function() {187var code = [188'var x = (',189' <div>',190' {/* A comment at the beginning */}',191' {/* A second comment at the beginning */}',192' <span>',193' {/* A nested comment */}',194' </span>',195' {/* A sandwiched comment */}',196' <br />',197' {/* A comment at the end */}',198' {/* A second comment at the end */}',199' </div>',200');'201].join('\n');202var result = [203'var x = (',204' React.createElement("div", null, ',205' /* A comment at the beginning */',206' /* A second comment at the beginning */',207' React.createElement("span", null',208' /* A nested comment */',209' ), ',210' /* A sandwiched comment */',211' React.createElement("br", null)',212' /* A comment at the end */',213' /* A second comment at the end */',214' )',215');'216].join('\n');217218expect(transform(code).code).toBe(result);219});220221it('should properly handle comments between props', function() {222var code = [223'var x = (',224' <div',225' /* a multi-line',226' comment */',227' attr1="foo">',228' <span // a double-slash comment',229' attr2="bar"',230' />',231' </div>',232');'233].join('\n');234var result = [235'var x = (',236' React.createElement("div", {',237' /* a multi-line',238' comment */',239' attr1: "foo"}, ',240' React.createElement("span", {// a double-slash comment',241' attr2: "bar"}',242' )',243' )',244');'245].join('\n');246247expect(transform(code).code).toBe(result);248});249250it('should not strip tags with a single child of ', function() {251var code = [252'<div> </div>;'253].join('\n');254var result = [255'React.createElement("div", null, "\u00A0");'256].join('\n');257258expect(transform(code).code).toBe(result);259});260261it('should not strip even coupled with other whitespace', function() {262var code = [263'<div> </div>;'264].join('\n');265var result = [266'React.createElement("div", null, "\u00A0 ");'267].join('\n');268269expect(transform(code).code).toBe(result);270});271272it('should handle hasOwnProperty correctly', function() {273var code = '<hasOwnProperty>testing</hasOwnProperty>;';274// var result = 'React.createElement("hasOwnProperty", null, "testing");';275276// expect(transform(code).code).toBe(result);277278// This is currently not supported, and will generate a string tag in279// a follow up.280expect(() => transform(code)).toThrow();281});282283it('should allow constructor as prop', function() {284var code = '<Component constructor="foo" />;';285var result = 'React.createElement(Component, {constructor: "foo"});';286287expect(transform(code).code).toBe(result);288});289290it('should allow JS namespacing', function() {291var code = '<Namespace.Component />;';292var result = 'React.createElement(Namespace.Component, null);';293294expect(transform(code).code).toBe(result);295});296297it('should allow deeper JS namespacing', function() {298var code = '<Namespace.DeepNamespace.Component />;';299var result =300'React.createElement(Namespace.DeepNamespace.Component, null);';301302expect(transform(code).code).toBe(result);303});304305it('should disallow XML namespacing', function() {306var code = '<Namespace:Component />;';307308expect(() => transform(code)).toThrow();309});310311it('wraps props in React.__spread for spread attributes', function() {312var code =313'<Component { ... x } y\n' +314'={2 } z />';315var result =316'React.createElement(Component, React.__spread({}, x , {y: \n' +317'2, z: true}))';318319expect(transform(code).code).toBe(result);320});321322it('adds appropriate newlines when using spread attribute', function() {323var code =324'<Component\n' +325' {...this.props}\n' +326' sound="moo" />';327var result =328'React.createElement(Component, React.__spread({}, \n' +329' this.props, \n' +330' {sound: "moo"}))';331332expect(transform(code).code).toBe(result);333});334335it('should transform known hyphenated tags', function() {336var code = '<font-face />;';337var result = 'React.createElement("font-face", null);';338339expect(transform(code).code).toBe(result);340});341342it('does not call React.__spread when there are no spreads', function() {343expectObjectAssign(344'<Component x={y} />'345).not.toBeCalled();346});347348it('should throw for unknown hyphenated tags', function() {349var code = '<x-component />;';350351expect(() => transform(code)).toThrow();352});353354it('calls assign with a new target object for spreads', function() {355expectObjectAssign(356'<Component {...x} />'357).toBeCalledWith({}, x);358});359360it('calls assign with an empty object when the spread is first', function() {361expectObjectAssign(362'<Component { ...x } y={2} />'363).toBeCalledWith({}, x, { y: 2 });364});365366it('coalesces consecutive properties into a single object', function() {367expectObjectAssign(368'<Component { ... x } y={2} z />'369).toBeCalledWith({}, x, { y: 2, z: true });370});371372it('avoids an unnecessary empty object when spread is not first', function() {373expectObjectAssign(374'<Component x={1} {...y} />'375).toBeCalledWith({x: 1}, y);376});377378it('passes the same value multiple times to React.__spread', function() {379expectObjectAssign(380'<Component x={1} y="2" {...z} {...z}><Child /></Component>'381).toBeCalledWith({x: 1, y: "2"}, z, z);382});383384it('evaluates sequences before passing them to React.__spread', function() {385expectObjectAssign(386'<Component x="1" {...(z = { y: 2 }, z)} z={3}>Text</Component>'387).toBeCalledWith({x: "1"}, { y: 2 }, {z: 3});388});389390});391392393