react-ionicons
Version:
A React SVG ionicon component
395 lines (339 loc) • 11.1 kB
JavaScript
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
/*jshint evil:true, unused:false*/
;
require('mock-modules').autoMockOff();
var transformFn = require('jstransform').transform;
var visitors = require('../react-jsx-visitors').visitorList;
function transform(code) {
return transformFn(visitors, code);
}
describe('react jsx', function() {
// These are placeholder variables in scope that we can use to assert that a
// specific variable reference was passed, rather than an object clone of it.
var x = 123456;
var y = 789012;
var z = 345678;
var expectObjectAssign = function(code) {
/*eslint-disable no-unused-vars, no-eval*/
var Component = jest.genMockFunction();
var Child = jest.genMockFunction();
var objectAssignMock = jest.genMockFunction();
React.__spread = objectAssignMock;
eval(transform(code).code);
return expect(objectAssignMock);
/*eslint-enable*/
};
var React = {
createElement: jest.genMockFunction()
};
it('should convert simple tags', function() {
var code = 'var x = <div></div>;';
var result = 'var x = React.createElement("div", null);';
expect(transform(code).code).toEqual(result);
});
it('should convert simple text', function() {
var code = 'var x = <div>text</div>;';
var result = 'var x = React.createElement("div", null, "text");';
expect(transform(code).code).toEqual(result);
});
it('should have correct comma in nested children', function() {
var code = [
'var x = <div>',
' <div><br /></div>',
' <Component>{foo}<br />{bar}</Component>',
' <br />',
'</div>;'
].join('\n');
var result = [
'var x = React.createElement("div", null, ',
' React.createElement("div", null, ' +
'React.createElement("br", null)), ',
' React.createElement(Component, null, foo, ' +
'React.createElement("br", null), bar), ',
' React.createElement("br", null)',
');'
].join('\n');
expect(transform(code).code).toEqual(result);
});
it('should avoid wrapping in extra parens if not needed', function() {
// Try with a single composite child, wrapped in a div.
var code = [
'var x = <div>',
' <Component />',
'</div>;'
].join('\n');
var result = [
'var x = React.createElement("div", null, ',
' React.createElement(Component, null)',
');'
].join('\n');
expect(transform(code).code).toEqual(result);
// Try with a single interpolated child, wrapped in a div.
code = [
'var x = <div>',
' {this.props.children}',
'</div>;'
].join('\n');
result = [
'var x = React.createElement("div", null, ',
' this.props.children',
');'
].join('\n');
expect(transform(code).code).toEqual(result);
// Try with a single interpolated child, wrapped in a composite.
code = [
'var x = <Composite>',
' {this.props.children}',
'</Composite>;'
].join('\n');
result = [
'var x = React.createElement(Composite, null, ',
' this.props.children',
');'
].join('\n');
expect(transform(code).code).toEqual(result);
// Try with a single composite child, wrapped in a composite.
code = [
'var x = <Composite>',
' <Composite2 />',
'</Composite>;'
].join('\n');
result = [
'var x = React.createElement(Composite, null, ',
' React.createElement(Composite2, null)',
');'
].join('\n');
expect(transform(code).code).toEqual(result);
});
it('should insert commas after expressions before whitespace', function() {
var code = [
'var x =',
' <div',
' attr1={',
' "foo" + "bar"',
' }',
' attr2={',
' "foo" + "bar" +',
' ',
' "baz" + "bug"',
' }',
' attr3={',
' "foo" + "bar" +',
' "baz" + "bug"',
' // Extra line here.',
' }',
' attr4="baz">',
' </div>;'
].join('\n');
var result = [
'var x =',
' React.createElement("div", {',
' attr1: ',
' "foo" + "bar", ',
' ',
' attr2: ',
' "foo" + "bar" +',
' ',
' "baz" + "bug", ',
' ',
' attr3: ',
' "foo" + "bar" +',
' "baz" + "bug", ',
' // Extra line here.',
' ',
' attr4: "baz"}',
' );'
].join('\n');
expect(transform(code).code).toEqual(result);
});
it('should properly handle comments adjacent to children', function() {
var code = [
'var x = (',
' <div>',
' {/* A comment at the beginning */}',
' {/* A second comment at the beginning */}',
' <span>',
' {/* A nested comment */}',
' </span>',
' {/* A sandwiched comment */}',
' <br />',
' {/* A comment at the end */}',
' {/* A second comment at the end */}',
' </div>',
');'
].join('\n');
var result = [
'var x = (',
' React.createElement("div", null, ',
' /* A comment at the beginning */',
' /* A second comment at the beginning */',
' React.createElement("span", null',
' /* A nested comment */',
' ), ',
' /* A sandwiched comment */',
' React.createElement("br", null)',
' /* A comment at the end */',
' /* A second comment at the end */',
' )',
');'
].join('\n');
expect(transform(code).code).toBe(result);
});
it('should properly handle comments between props', function() {
var code = [
'var x = (',
' <div',
' /* a multi-line',
' comment */',
' attr1="foo">',
' <span // a double-slash comment',
' attr2="bar"',
' />',
' </div>',
');'
].join('\n');
var result = [
'var x = (',
' React.createElement("div", {',
' /* a multi-line',
' comment */',
' attr1: "foo"}, ',
' React.createElement("span", {// a double-slash comment',
' attr2: "bar"}',
' )',
' )',
');'
].join('\n');
expect(transform(code).code).toBe(result);
});
it('should not strip tags with a single child of ', function() {
var code = [
'<div> </div>;'
].join('\n');
var result = [
'React.createElement("div", null, "\u00A0");'
].join('\n');
expect(transform(code).code).toBe(result);
});
it('should not strip even coupled with other whitespace', function() {
var code = [
'<div> </div>;'
].join('\n');
var result = [
'React.createElement("div", null, "\u00A0 ");'
].join('\n');
expect(transform(code).code).toBe(result);
});
it('should handle hasOwnProperty correctly', function() {
var code = '<hasOwnProperty>testing</hasOwnProperty>;';
var result = 'React.createElement("hasOwnProperty", null, "testing");';
expect(transform(code).code).toBe(result);
});
it('should allow constructor as prop', function() {
var code = '<Component constructor="foo" />;';
var result = 'React.createElement(Component, {constructor: "foo"});';
expect(transform(code).code).toBe(result);
});
it('should allow JS namespacing', function() {
var code = '<Namespace.Component />;';
var result = 'React.createElement(Namespace.Component, null);';
expect(transform(code).code).toBe(result);
});
it('should allow deeper JS namespacing', function() {
var code = '<Namespace.DeepNamespace.Component />;';
var result =
'React.createElement(Namespace.DeepNamespace.Component, null);';
expect(transform(code).code).toBe(result);
});
it('should disallow XML namespacing', function() {
var code = '<Namespace:Component />;';
expect(() => transform(code)).toThrow();
});
it('wraps props in React.__spread for spread attributes', function() {
var code =
'<Component { ... x } y\n' +
'={2 } z />';
var result =
'React.createElement(Component, React.__spread({}, x , {y: \n' +
'2, z: true}))';
expect(transform(code).code).toBe(result);
});
it('adds appropriate newlines when using spread attribute', function() {
var code =
'<Component\n' +
' {...this.props}\n' +
' sound="moo" />';
var result =
'React.createElement(Component, React.__spread({}, \n' +
' this.props, \n' +
' {sound: "moo"}))';
expect(transform(code).code).toBe(result);
});
it('handles overparenthesized JS', function() {
var code =
'<foo a={(b)} c={(d)}>Foo {(e+f //A line comment\n' +
'/* A multiline comment */)\n' +
'} bar\n' +
'</foo>';
var result = 'React.createElement("foo", {a: (b), c: (d)}, "Foo ", (e+f //A line comment\n' +
'/* A multiline comment */), \n' +
'" bar"\n' +
')';
expect(transform(code).code).toBe(result);
});
it('should transform known hyphenated tags', function() {
var code = '<font-face />;';
var result = 'React.createElement("font-face", null);';
expect(transform(code).code).toBe(result);
});
it('does not call React.__spread when there are no spreads', function() {
expectObjectAssign(
'<Component x={y} />'
).not.toBeCalled();
});
it('should not throw for unknown hyphenated tags', function() {
var code = '<x-component />;';
expect(function() {
transform(code);
}).not.toThrow();
});
it('calls assign with a new target object for spreads', function() {
expectObjectAssign(
'<Component {...x} />'
).toBeCalledWith({}, x);
});
it('calls assign with an empty object when the spread is first', function() {
expectObjectAssign(
'<Component { ...x } y={2} />'
).toBeCalledWith({}, x, {y: 2});
});
it('coalesces consecutive properties into a single object', function() {
expectObjectAssign(
'<Component { ... x } y={2} z />'
).toBeCalledWith({}, x, {y: 2, z: true});
});
it('avoids an unnecessary empty object when spread is not first', function() {
expectObjectAssign(
'<Component x={1} {...y} />'
).toBeCalledWith({x: 1}, y);
});
it('passes the same value multiple times to React.__spread', function() {
expectObjectAssign(
'<Component x={1} y="2" {...z} {...z}><Child /></Component>'
).toBeCalledWith({x: 1, y: '2'}, z, z);
});
it('evaluates sequences before passing them to React.__spread', function() {
expectObjectAssign(
'<Component x="1" {...(z = { y: 2 }, z)} z={3}>Text</Component>'
).toBeCalledWith({x: '1'}, {y: 2}, {z: 3});
});
});