ReactElementClone-test.jsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. import PropTypes from '../../lib/ReactPropTypes';
  2. import ReactTestUtils from "../../lib/ReactTestUtils";
  3. import React from '../../src/May';
  4. import { render, unmountComponentAtNode, findDOMNode } from '../../src/may-dom/MayDom';
  5. import {shallowCompare} from '../../src/PureComponent';
  6. var ReactDOM = {
  7. render: render,
  8. unmountComponentAtNode: unmountComponentAtNode,
  9. findDOMNode: findDOMNode
  10. }
  11. React.render = render;
  12. // import React from "../../dist/ReactANU";
  13. // var ReactDOM = React;
  14. // var ReactTestUtils = {
  15. // renderIntoDocument: function (element) {
  16. // var div = document.createElement("div");
  17. // return React.render(element, div);
  18. // }
  19. // };
  20. // https://github.com/facebook/react/blob/master/src/renderers/__tests__/EventPluginHub-test.js
  21. describe("ReactElementClone", function() {
  22. // this.timeout(200000);
  23. // NOTE: We're explicitly not using JSX here. This is intended to test
  24. // classic JS without JSX.
  25. var ComponentClass = class extends React.Component {
  26. render() {
  27. return React.createElement("div");
  28. }
  29. };
  30. it("should clone a DOM component with new props", () => {
  31. class Grandparent extends React.Component {
  32. render() {
  33. return <Parent child={<div className="child" />} />;
  34. }
  35. }
  36. class Parent extends React.Component {
  37. render() {
  38. return (
  39. <div className="parent">
  40. {React.cloneElement(this.props.child, {className: "xyz"})}
  41. </div>
  42. );
  43. }
  44. }
  45. var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
  46. expect(ReactDOM.findDOMNode(component).childNodes[0].className).toBe("xyz");
  47. });
  48. it("should clone a composite component with new props", () => {
  49. class Child extends React.Component {
  50. render() {
  51. return <div className={this.props.className} />;
  52. }
  53. }
  54. class Grandparent extends React.Component {
  55. render() {
  56. return <Parent child={<Child className="child" />} />;
  57. }
  58. }
  59. class Parent extends React.Component {
  60. render() {
  61. return (
  62. <div className="parent">
  63. {React.cloneElement(this.props.child, {className: "xyz"})}
  64. </div>
  65. );
  66. }
  67. }
  68. var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
  69. expect(ReactDOM.findDOMNode(component).childNodes[0].className).toBe("xyz");
  70. });
  71. it("does not fail if config has no prototype", () => {
  72. var config = Object.create(null, {foo: {value: 1, enumerable: true}});
  73. React.cloneElement(<div />, config);
  74. });
  75. it("should keep the original ref if it is not overridden", () => {
  76. class Grandparent extends React.Component {
  77. render() {
  78. return <Parent child={<div ref="yolo" />} />;
  79. }
  80. }
  81. class Parent extends React.Component {
  82. render() {
  83. return (
  84. <div>
  85. {React.cloneElement(this.props.child, {className: "xyz"})}
  86. </div>
  87. );
  88. }
  89. }
  90. var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
  91. expect(component.refs.yolo.tagName).toBe("DIV");
  92. });
  93. it('should transfer the key property', () => {
  94. class Component extends React.Component {
  95. render() {
  96. return null;
  97. }
  98. }
  99. var clone = React.cloneElement(<Component />, {key: 'xyz'});
  100. expect(clone.key).toBe('xyz');
  101. });
  102. it('should transfer children', () => {
  103. class Component extends React.Component {
  104. render() {
  105. expect(this.props.children).toBe('xyz');
  106. return <div />;
  107. }
  108. }
  109. ReactTestUtils.renderIntoDocument(
  110. React.cloneElement(<Component />, {children: 'xyz'}),
  111. );
  112. });
  113. it('should shallow clone children', () => {
  114. class Component extends React.Component {
  115. render() {
  116. expect(this.props.children).toBe('xyz');
  117. return <div />;
  118. }
  119. }
  120. ReactTestUtils.renderIntoDocument(
  121. React.cloneElement(<Component>xyz</Component>, {}),
  122. );
  123. });
  124. // it('should accept children as rest arguments', () => {
  125. // class Component extends React.Component {
  126. // render() {
  127. // return null;
  128. // }
  129. // }
  130. // var clone = React.cloneElement(
  131. // <Component>xyz</Component>,
  132. // {children: <Component />},
  133. // <div />,
  134. // <span />,
  135. // );
  136. // expect(clone.props.children).toEqual([<div />, <span />]);
  137. // });
  138. // it('should override children if undefined is provided as an argument', () => {
  139. // var element = React.createElement(
  140. // ComponentClass,
  141. // {
  142. // children: 'text',
  143. // },
  144. // undefined,
  145. // );
  146. // expect(element.props.children).toBe(undefined);
  147. // var element2 = React.cloneElement(
  148. // React.createElement(ComponentClass, {
  149. // children: 'text',
  150. // }),
  151. // {},
  152. // undefined,
  153. // );
  154. // expect(element2.props.children).toBe(undefined);
  155. // });
  156. it('should support keys and refs', () => {
  157. class Parent extends React.Component {
  158. render() {
  159. var clone = React.cloneElement(this.props.children, {
  160. key: 'xyz',
  161. ref: 'xyz',
  162. });
  163. expect(clone.key).toBe('xyz');
  164. // expect(clone.ref).toBe('xyz');
  165. return <div>{clone}</div>;
  166. }
  167. }
  168. class Grandparent extends React.Component {
  169. render() {
  170. return <Parent ref="parent"><span key="abc" /></Parent>;
  171. }
  172. }
  173. var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
  174. expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
  175. });
  176. it('should steal the ref if a new ref is specified', () => {
  177. class Parent extends React.Component {
  178. render() {
  179. var clone = React.cloneElement(this.props.children, {ref: 'xyz'});
  180. return <div>{clone}</div>;
  181. }
  182. }
  183. class Grandparent extends React.Component {
  184. render() {
  185. return <Parent ref="parent"><span ref="child" /></Parent>;
  186. }
  187. }
  188. var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
  189. expect(component.refs.child).toBe(null);
  190. expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
  191. });
  192. it('should overwrite props', () => {
  193. class Component extends React.Component {
  194. render() {
  195. expect(this.props.myprop).toBe('xyz');
  196. return <div />;
  197. }
  198. }
  199. ReactTestUtils.renderIntoDocument(
  200. React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'}),
  201. );
  202. });
  203. it('should normalize props with default values', () => {
  204. class Component extends React.Component {
  205. render() {
  206. return <span />;
  207. }
  208. }
  209. Component.defaultProps = {prop: 'testKey'};
  210. var instance = React.createElement(Component);
  211. var clonedInstance = React.cloneElement(instance, {prop: undefined});
  212. expect(clonedInstance.props.prop).toBe('testKey');
  213. var clonedInstance2 = React.cloneElement(instance, {prop: null});
  214. expect(clonedInstance2.props.prop).toBe(null);
  215. var instance2 = React.createElement(Component, {prop: 'newTestKey'});
  216. var cloneInstance3 = React.cloneElement(instance2, {prop: undefined});
  217. expect(cloneInstance3.props.prop).toBe('testKey');
  218. var cloneInstance4 = React.cloneElement(instance2, {});
  219. expect(cloneInstance4.props.prop).toBe('newTestKey');
  220. });
  221. it('does not warns for arrays of elements with keys', () => {
  222. spyOn(console, 'error');
  223. React.cloneElement(<div />, null, [<div key="#1" />, <div key="#2" />]);
  224. expect(console.error.calls.count()).toBe(0);
  225. });
  226. it('does not warn when the element is directly in rest args', () => {
  227. spyOn(console, 'error');
  228. React.cloneElement(<div />, null, <div />, <div />);
  229. expect(console.error.calls.count()).toBe(0);
  230. });
  231. it('does not warn when the array contains a non-element', () => {
  232. spyOn(console, 'error');
  233. React.cloneElement(<div />, null, [{}, {}]);
  234. expect(console.error.calls.count()).toBe(0);
  235. });
  236. it('should ignore key and ref warning getters', () => {
  237. var elementA = React.createElement('div');
  238. var elementB = React.cloneElement(elementA, elementA.props);
  239. expect(!!elementB.key).toBe(false);
  240. expect(!!elementB.ref).toBe(false);
  241. });
  242. it('should ignore undefined key and ref', () => {
  243. var element = React.createFactory(ComponentClass)({
  244. key: '12',
  245. ref: '34',
  246. foo: '56',
  247. });
  248. var props = {
  249. key: undefined,
  250. ref: undefined,
  251. foo: 'ef',
  252. };
  253. var clone = React.cloneElement(element, props);
  254. expect(clone.type).toBe(ComponentClass);
  255. expect(clone.key).toBe(null);
  256. expect(clone.ref).toBe(null);
  257. // expect(Object.isFrozen(element)).toBe(true);
  258. // expect(Object.isFrozen(element.props)).toBe(true);
  259. // expect(clone.props).toEqual({foo: 'ef'});
  260. });
  261. it('should extract null key and ref', () => {
  262. var element = React.createFactory(ComponentClass)({
  263. key: '12',
  264. ref: '34',
  265. foo: '56',
  266. });
  267. var props = {
  268. key: null,
  269. ref: null,
  270. foo: 'ef',
  271. };
  272. var clone = React.cloneElement(element, props);
  273. expect(clone.type).toBe(ComponentClass);
  274. expect(clone.key).toBe('null');
  275. expect(!!clone.ref).toBe(false);
  276. // expect(Object.isFrozen(element)).toBe(true);
  277. // expect(Object.isFrozen(element.props)).toBe(true);
  278. // expect(clone.props).toEqual({foo: 'ef'});
  279. });
  280. it("子元素被克隆", function(){
  281. function Bar(props) {
  282. return React.cloneElement(props.children, {className: props.className})
  283. }
  284. var container = document.createElement('div');
  285. var myNodeA = ReactDOM.render(<Bar className="a"><span /></Bar>, container);
  286. expect(myNodeA.className).toBe("a")
  287. myNodeA = ReactDOM.render(<Bar className="kk"><span /></Bar>, container);
  288. expect(myNodeA.className).toBe("kk")
  289. })
  290. it("子元素被克隆2", function(){
  291. function Bar(props) {
  292. return React.cloneElement(props.children, {className: props.className})
  293. }
  294. function Foo(props) {
  295. return props.className === "a" ? <span {...props} />:<p {...props} />
  296. }
  297. var container = document.createElement('div');
  298. var myNodeA = ReactDOM.render(<Bar className="a"><Foo /></Bar>, container);
  299. expect(myNodeA.className).toBe("a")
  300. myNodeA = ReactDOM.render(<Bar className="kk"><Foo /></Bar>, container);
  301. expect(myNodeA.className).toBe("kk")
  302. })/**/
  303. });