ReactComponent-test.jsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. import ReactTestUtils from "../../lib/ReactTestUtils";
  2. import React from '../../src/May';
  3. import { render, unmountComponentAtNode, findDOMNode } from '../../src/may-dom/MayDom'
  4. var ReactDOM = {
  5. render: render,
  6. unmountComponentAtNode: unmountComponentAtNode,
  7. findDOMNode: findDOMNode
  8. }
  9. React.render = render;
  10. import ReactDOMServer from '../../src/may-server/MayServer'
  11. // import React from "../dist/ReactANU";
  12. // var ReactDOM = React;
  13. // var React = require('react');//hyphenate
  14. // var ReactDOM = require('react-dom');
  15. //https://github.com/facebook/react/blob/master/src/isomorphic/children/__tests__/ReactChildren-test.js
  16. describe("ReactComponent", function () {
  17. // this.timeout(200000);
  18. it("should throw on invalid render targets", () => {
  19. var container = document.createElement("div");
  20. // jQuery objects are basically arrays; people often pass them in by mistake
  21. expect(function() {
  22. ReactDOM.render(<div />, [container]);
  23. }).toThrowError(/container参数错误/);
  24. });
  25. it("should throw when supplying a ref outside of render method", () => {
  26. var instance = <div ref="badDiv" />;
  27. instance = ReactTestUtils.renderIntoDocument(instance);
  28. });
  29. it('mayRender', () => {
  30. spyOn(console, 'error');
  31. var container = document.createElement('div');
  32. class Child extends React.Component {
  33. // constructor(props){
  34. // super(props);
  35. // this.state={val2:'I wonder'};
  36. // }
  37. render() {
  38. return (
  39. <div>
  40. {this.props.key}
  41. {this.props.val}
  42. </div>);
  43. }
  44. }
  45. class Parent extends React.Component {
  46. constructor() {
  47. super();
  48. this.state = { val: 'I wonder' };
  49. this.Change = this.Change.bind(this);
  50. }
  51. Change() {
  52. this.setState({ val: 'I see' });
  53. }
  54. onFocus() {
  55. this.refs.inputRef.focus()
  56. }
  57. render() {
  58. var item = [];
  59. return (
  60. <div className="mystyle" style={{ width: '40%', marginLeft: '30px' }}>
  61. {this.state.val === 'I wonder' ? '' : <Child key="1" val="2" />}
  62. <input onChange={this.Change} type="text" value={this.state.val} />
  63. 666&nbsp; {this.state.val}
  64. {this.state.val !== 'I wonder' ? <Child key="1" val="2" /> : <Child key="3" val="4" />}
  65. <Child key="0" val={this.state.val} />
  66. </div>
  67. )
  68. }
  69. }
  70. //this._updateDOMChildren
  71. React.render(<Parent />, container);
  72. expect(console.error.calls.count()).toBe(0);
  73. });
  74. it("should warn when children are mutated during render", () => {
  75. function Wrapper(props) {
  76. props.children[1] = <p key={1} />; // Mutation is illegal
  77. return <div>{props.children}</div>;
  78. }
  79. var instance = ReactTestUtils.renderIntoDocument(
  80. <Wrapper>
  81. <span key={0} />
  82. <span key={1} />
  83. <span key={2} />
  84. </Wrapper>
  85. );
  86. expect(ReactTestUtils.scryRenderedDOMComponentsWithTag(instance, "p").length).toBe(1);
  87. });
  88. it("should warn when children are mutated during update", () => {
  89. class Wrapper extends React.Component {
  90. componentDidMount() {
  91. this.props.children[1] = <p key={1} />; // Mutation is illegal
  92. this.forceUpdate();
  93. }
  94. render() {
  95. return <div>{this.props.children}</div>;
  96. }
  97. }
  98. var instance = ReactTestUtils.renderIntoDocument(
  99. <Wrapper>
  100. <span key={0} />
  101. <span key={1} />
  102. <span key={2} />
  103. </Wrapper>
  104. );
  105. expect(ReactTestUtils.scryRenderedDOMComponentsWithTag(instance, "p").length).toBe(1);
  106. });
  107. it("should support refs on owned components", () => {
  108. var innerObj = {};
  109. var outerObj = {};
  110. class Wrapper extends React.Component {
  111. getObject = () => {
  112. return this.props.object;
  113. };
  114. render() {
  115. return <div>{this.props.children}</div>;
  116. }
  117. }
  118. class Component extends React.Component {
  119. render() {
  120. var inner = <Wrapper object={innerObj} ref="inner" />;
  121. var outer = (
  122. <Wrapper object={outerObj} ref="outer">
  123. {inner}
  124. </Wrapper>
  125. );
  126. return outer;
  127. }
  128. componentDidMount() {
  129. expect(this.refs.inner.getObject()).toEqual(innerObj);
  130. expect(this.refs.outer.getObject()).toEqual(outerObj);
  131. }
  132. }
  133. ReactTestUtils.renderIntoDocument(<Component />);
  134. });
  135. it("should not have refs on unmounted components", () => {
  136. class Parent extends React.Component {
  137. render() {
  138. return (
  139. <Child>
  140. <div ref="test" />
  141. </Child>
  142. );
  143. }
  144. componentDidMount() {
  145. expect(this.refs && this.refs.test).toEqual(null);
  146. }
  147. }
  148. class Child extends React.Component {
  149. render() {
  150. return <div />;
  151. }
  152. }
  153. ReactTestUtils.renderIntoDocument(<Parent child={<span />} />);
  154. });
  155. it("should support new-style refs", () => {
  156. var innerObj = {};
  157. var outerObj = {};
  158. class Wrapper extends React.Component {
  159. getObject = () => {
  160. return this.props.object;
  161. };
  162. render() {
  163. return <div>{this.props.children}</div>;
  164. }
  165. }
  166. var mounted = false;
  167. class Component extends React.Component {
  168. render() {
  169. var inner = <Wrapper object={innerObj} ref={c => (this.innerRef = c)} />;
  170. var outer = (
  171. <Wrapper object={outerObj} ref={c => (this.outerRef = c)}>
  172. {inner}
  173. </Wrapper>
  174. );
  175. return outer;
  176. }
  177. componentDidMount() {
  178. expect(this.innerRef.getObject()).toEqual(innerObj);
  179. expect(this.outerRef.getObject()).toEqual(outerObj);
  180. mounted = true;
  181. }
  182. }
  183. ReactTestUtils.renderIntoDocument(<Component />);
  184. expect(mounted).toBe(true);
  185. });
  186. it("should support new-style refs with mixed-up owners", () => {
  187. class Wrapper extends React.Component {
  188. getTitle = () => {
  189. return this.props.title;
  190. };
  191. render() {
  192. return this.props.getContent();
  193. }
  194. }
  195. var mounted = false;
  196. class Component extends React.Component {
  197. getInner = () => {
  198. // (With old-style refs, it's impossible to get a ref to this div
  199. // because Wrapper is the current owner when this function is called.)
  200. return <div className="inner" ref={c => (this.innerRef = c)} />;
  201. };
  202. render() {
  203. return <Wrapper title="wrapper" ref={c => (this.wrapperRef = c)} getContent={this.getInner} />;
  204. }
  205. componentDidMount() {
  206. // Check .props.title to make sure we got the right elements back
  207. expect(this.wrapperRef.getTitle()).toBe("wrapper");
  208. expect(ReactDOM.findDOMNode(this.innerRef).className).toBe("inner");
  209. mounted = true;
  210. }
  211. }
  212. ReactTestUtils.renderIntoDocument(<Component />);
  213. expect(mounted).toBe(true);
  214. });
  215. /**
  216. * ------------------ The Life-Cycle of a Composite Component ------------------
  217. *
  218. * - constructor: Initialization of state. The instance is now retained.
  219. * - componentWillMount
  220. * - render
  221. * - [children's constructors]
  222. * - [children's componentWillMount and render]
  223. * - [children's componentDidMount]
  224. * - componentDidMount
  225. *
  226. * Update Phases:
  227. * - componentWillReceiveProps (only called if parent updated)
  228. * - shouldComponentUpdate
  229. * - componentWillUpdate
  230. * - render
  231. * - [children's constructors or receive props phases]
  232. * - componentDidUpdate
  233. *
  234. * - componentWillUnmount
  235. * - [children's componentWillUnmount]
  236. * - [children destroyed]
  237. * - (destroyed): The instance is now blank, released by React and ready for GC.
  238. *
  239. * -----------------------------------------------------------------------------
  240. */
  241. it("should call refs at the correct time", () => {
  242. var log = [];
  243. class Inner extends React.Component {
  244. render() {
  245. log.push(`inner ${this.props.id} render`);
  246. return <div />;
  247. }
  248. componentDidMount() {
  249. log.push(`inner ${this.props.id} componentDidMount`);
  250. }
  251. componentDidUpdate() {
  252. log.push(`inner ${this.props.id} componentDidUpdate`);
  253. }
  254. componentWillUnmount() {
  255. log.push(`inner ${this.props.id} componentWillUnmount`);
  256. }
  257. }
  258. class Outer extends React.Component {
  259. render() {
  260. return (
  261. <div>
  262. <Inner
  263. id={1}
  264. ref={c => {
  265. log.push(`ref 1 got ${c ? `instance ${c.props.id}` : "null"}`);
  266. }}
  267. />
  268. <Inner
  269. id={2}
  270. ref={c => {
  271. log.push(`ref 2 got ${c ? `instance ${c.props.id}` : "null"}`);
  272. }}
  273. />
  274. </div>
  275. );
  276. }
  277. componentDidMount() {
  278. log.push("outer componentDidMount");
  279. }
  280. componentDidUpdate() {
  281. log.push("outer componentDidUpdate");
  282. }
  283. componentWillUnmount() {
  284. log.push("outer componentWillUnmount");
  285. }
  286. }
  287. // mount, update, unmount
  288. var container = document.createElement("div");
  289. log.push("start mount");
  290. ReactDOM.render(<Outer />, container);
  291. log.push("start update");
  292. ReactDOM.render(<Outer />, container);
  293. log.push("start unmount");
  294. ReactDOM.unmountComponentAtNode(container);
  295. //eslint-disable indent
  296. expect(log).toEqual([
  297. "start mount",
  298. "inner 1 render",
  299. "inner 2 render",
  300. "inner 1 componentDidMount",
  301. "ref 1 got instance 1",
  302. "inner 2 componentDidMount",
  303. "ref 2 got instance 2",
  304. "outer componentDidMount",
  305. "start update",
  306. // Stack resets refs before rendering
  307. "ref 1 got null",
  308. "inner 1 render",
  309. "ref 2 got null",
  310. "inner 2 render",
  311. "inner 1 componentDidUpdate",
  312. "ref 1 got instance 1",
  313. "inner 2 componentDidUpdate",
  314. "ref 2 got instance 2",
  315. "outer componentDidUpdate",
  316. "start unmount",
  317. "outer componentWillUnmount",
  318. "ref 1 got null",
  319. "inner 1 componentWillUnmount",
  320. "ref 2 got null",
  321. "inner 2 componentWillUnmount"
  322. ]);
  323. });
  324. it("includes owner name in the error about badly-typed elements", () => {
  325. spyOn(console, "error");
  326. var X = 'undefined';
  327. function Indirection(props) {
  328. return <div>{props.children}</div>;
  329. }
  330. function Bar() {
  331. return (
  332. <Indirection>
  333. <X />
  334. </Indirection>
  335. );
  336. }
  337. function Foo() {
  338. return <Bar />;
  339. }
  340. ReactTestUtils.renderIntoDocument(<Foo />)
  341. });
  342. it("throws if a plain object is used as a child", () => {
  343. var children = {
  344. x: <span />,
  345. y: <span />,
  346. z: <span />
  347. };
  348. var element = <div>{[children]}</div>;
  349. var container = document.createElement("div");
  350. var ex;
  351. try {
  352. ReactDOM.render(element, container);
  353. } catch (e) {
  354. ex = e;
  355. }
  356. // expect(ex).toBeDefined();
  357. });
  358. it("throws if a plain object even if it is in an owner", () => {
  359. class Foo extends React.Component {
  360. render() {
  361. var children = {
  362. a: <span />,
  363. b: <span />,
  364. c: <span />
  365. };
  366. return <div>{[children]}</div>;
  367. }
  368. }
  369. var container = document.createElement("div");
  370. var ex;
  371. try {
  372. ReactDOM.render(<Foo />, container);
  373. } catch (e) {
  374. ex = e;
  375. }
  376. // expect(ex).toBeDefined();
  377. });
  378. it("throws if a plain object is used as a child when using SSR", async () => {
  379. var children = {
  380. x: <span />,
  381. y: <span />,
  382. z: <span />
  383. };
  384. var element = <div>{[children]}</div>;
  385. var ex;
  386. try {
  387. ReactDOMServer.renderToString(element);
  388. } catch (e) {
  389. ex = e;
  390. console.warn(e);
  391. }
  392. // expect(ex).toBeDefined();
  393. });
  394. it("throws if a plain object even if it is in an owner when using SSR", async () => {
  395. class Foo extends React.Component {
  396. render() {
  397. var children = {
  398. a: <span />,
  399. b: <span />,
  400. c: <span />
  401. };
  402. return <div>{[children]}</div>;
  403. }
  404. }
  405. var container = document.createElement("div");
  406. var ex;
  407. try {
  408. ReactDOMServer.renderToString(<Foo />, container);
  409. } catch (e) {
  410. ex = e;
  411. console.warn(e);
  412. }
  413. // expect(ex).toBeDefined();
  414. });
  415. });