node.spec.jsx 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  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. // var React = require('react');
  11. // var ReactDOM = require('react-dom');
  12. // import React from "../../dist/ReactANU";
  13. // var ReactDOM = React;
  14. // var ReactTestUtils = { Simulate: {} };
  15. // "click,change,keyDown,keyUp,KeyPress,mouseDown,mouseUp,mouseMove".replace(/\w+/g, function (name) {
  16. // ReactTestUtils.Simulate[name] = function (node, opts) {
  17. // if (!node || node.nodeType !== 1) {
  18. // throw "第一个参数必须为元素节点";
  19. // }
  20. // var fakeNativeEvent = opts || {};
  21. // fakeNativeEvent.target = node;
  22. // fakeNativeEvent.simulated = true;
  23. // fakeNativeEvent.type = name.toLowerCase();
  24. // React.eventSystem.dispatchEvent(fakeNativeEvent, name.toLowerCase());
  25. // };
  26. // });
  27. describe('node模块', function () {
  28. var body = document.body, div
  29. beforeEach(function () {
  30. div = document.createElement('div')
  31. body.appendChild(div)
  32. })
  33. afterEach(function () {
  34. body.removeChild(div)
  35. })
  36. // it('连续点击一个DIV', async () => {
  37. // div.innerHTML = '看到我吗?'
  38. // var a = 1
  39. // div.onclick = function () {
  40. // a++
  41. // }
  42. // await browser.click(div).pause(100).$apply()
  43. // expect(a).toBe(2)
  44. // await browser.click(div).pause(100).$apply()
  45. // expect(a).toBe(3)
  46. // });
  47. it('输出简单的元素', async () => {
  48. var s = React.render(<div>222</div>, div)
  49. //组件直接返回元素节点
  50. expect(s.nodeName).toBe('DIV');
  51. });
  52. it('InputControlES6', async () => {
  53. class InputControlES6 extends React.Component {
  54. constructor(props) {
  55. super(props);
  56. // 设置 initial state
  57. this.state = {
  58. text: props.initialValue || 'placeholder'
  59. }
  60. // ES6 类中函数必须手动绑定
  61. this.handleChange = this
  62. .handleChange
  63. .bind(this);
  64. }
  65. handleChange(event) {
  66. this.setState({ text: event.target.value });
  67. }
  68. render() {
  69. return (
  70. <div>
  71. Type something:
  72. <input ref="input" onChange={this.handleChange} value={this.state.text} />
  73. </div>
  74. )
  75. }
  76. }
  77. InputControlES6.defaultProps = {
  78. initialValue: '请输入内容'
  79. }
  80. var s = React.render(<InputControlES6 />, div)
  81. var input = s.refs.input
  82. expect(input.value).toBe('请输入内容')
  83. //input已经是dom 暂不做这个兼容了
  84. // expect(input.getDOMNode()).toBe(input)
  85. })
  86. it('forceUpdate', async () => {
  87. class App extends React.Component {
  88. constructor(props) {
  89. super(props);
  90. // 设置 initial state
  91. this.state = {
  92. text: 'xxx'
  93. };
  94. }
  95. shouldComponentUpdate() {
  96. return false
  97. }
  98. render() {
  99. return (
  100. <div>
  101. Type something:
  102. <input ref="input" value={new Date - 0} />
  103. </div>
  104. );
  105. }
  106. }
  107. App.defaultProps = {
  108. initialValue: '请输入内容'
  109. };
  110. div.innerHTML = '<span>remove</span>'
  111. var s = React.render(<App />, div)
  112. var index = 0
  113. expect(s.mayInst.hostNode.nodeName).toBe('DIV')
  114. s.forceUpdate(function () {
  115. index++
  116. })
  117. expect(index).toBe(1)
  118. s.forceUpdate(function () {
  119. index++
  120. })
  121. expect(index).toBe(2)
  122. })
  123. it('下拉菜单的选择', async () => {
  124. class Select extends React.Component {
  125. constructor() {
  126. super()
  127. this.state = {
  128. city: "bj"
  129. }
  130. }
  131. handleCity(e) {
  132. // expect(e.type).toBe('change')
  133. console.warn(e.type);
  134. var value = e.target.value;
  135. this.setState({ city: value })
  136. }
  137. render() {
  138. return <select
  139. name='city'
  140. id="node2"
  141. value={this.state.city}
  142. onChange={this
  143. .handleCity
  144. .bind(this)}>
  145. <option value='hz'>杭州</option>
  146. <option value='bj'>北京</option>
  147. <option value='sh'>上海</option>
  148. </select>
  149. }
  150. }
  151. var s = React.render(<Select />, div)
  152. expect(div.firstChild.children[1].selected).toBe(true)
  153. // await browser.selectByVisibleText('#node2', '上海').pause(100).$apply()
  154. // expect(div.firstChild.children[2].selected).toBe(true)
  155. // await browser.selectByVisibleText('#node2', '杭州').pause(100).$apply()
  156. // expect(div.firstChild.children[0].selected).toBe(true)
  157. })
  158. it('下拉菜单的options重排后确保selected正确', async () => {
  159. class Select extends React.Component {
  160. constructor() {
  161. super()
  162. this.state = {
  163. city: "bj",
  164. cities: [
  165. {
  166. value: 'bj',
  167. text: '北京'
  168. }, {
  169. value: 'hj',
  170. text: '杭州'
  171. }, {
  172. value: 'nj',
  173. text: '南京'
  174. }
  175. ]
  176. }
  177. }
  178. change() {
  179. this.setState({
  180. cities: [
  181. {
  182. value: 'hj',
  183. text: '杭州'
  184. }, {
  185. value: 'nj',
  186. text: '南京'
  187. }, {
  188. value: 'bj',
  189. text: '北京'
  190. }
  191. ]
  192. })
  193. }
  194. handleCity(e) {
  195. var value = e.target.value;
  196. this.setState({ city: value })
  197. }
  198. render() {
  199. return <select
  200. name='city'
  201. id="node3"
  202. value={this.state.city}
  203. onChange={this
  204. .handleCity
  205. .bind(this)}>
  206. {this
  207. .state
  208. .cities
  209. .map(function (el) {
  210. return <option value={el.value}>{el.text}</option>
  211. })
  212. }
  213. </select>
  214. }
  215. }
  216. ;
  217. var s = React.render(<Select />, div)
  218. expect(s.mayInst.hostNode.children[0].text).toBe('北京')
  219. expect(s.mayInst.hostNode.children[1].text).toBe('杭州')
  220. expect(s.mayInst.hostNode.children[2].text).toBe('南京')
  221. s.change()
  222. expect(s.mayInst.hostNode.children[0].text).toBe('杭州')
  223. expect(s.mayInst.hostNode.children[1].text).toBe('南京')
  224. expect(s.mayInst.hostNode.children[2].text).toBe('北京')
  225. })
  226. it('测试radio的onchange事件', async () => {
  227. class Radio extends React.Component {
  228. constructor() {
  229. super()
  230. this.state = {
  231. checkedIndex: 2
  232. }
  233. }
  234. handleChange(index) {
  235. this.setState({ checkedIndex: index })
  236. }
  237. // webdriver.io不支持触发
  238. // checkbox的onchange事件,只能browsers.click它,然后在一个onClick回调中手动调用onChange回调
  239. onClick(index) {
  240. var me = this
  241. me.handleChange(index);
  242. // setTimeout(function () {
  243. // me.handleChange(index)
  244. // })
  245. }
  246. render() {
  247. return <div>
  248. {[1, 2, 3]
  249. .map(function (el) {
  250. return <input
  251. type='radio'
  252. id={'radio' + el}
  253. name='xxx'
  254. key={el}
  255. value={el}
  256. checked={this.state.checkedIndex === el}
  257. onClick={this
  258. .onClick
  259. .bind(this, el)}
  260. onChange={this
  261. .handleChange
  262. .bind(this, el)} />
  263. }, this)
  264. }
  265. </div>
  266. }
  267. }
  268. var s = React.render(<Radio />, div)
  269. expect(s.mayInst.hostNode.children[0].checked).toBe(false)
  270. expect(s.mayInst.hostNode.children[1].checked).toBe(true)
  271. expect(s.mayInst.hostNode.children[2].checked).toBe(false)
  272. ReactTestUtils.Simulate.click(document.getElementById('radio3'));
  273. expect(s.mayInst.hostNode.children[0].checked).toBe(false)
  274. expect(s.mayInst.hostNode.children[1].checked).toBe(false)
  275. expect(s.mayInst.hostNode.children[2].checked).toBe(true)
  276. })
  277. it('测试input元素的oninput事件', async () => {
  278. var values = ['x', 'xx', 'xxx', 'xxxx']
  279. var el = ''
  280. class Input extends React.Component {
  281. constructor() {
  282. super()
  283. this.state = {
  284. value: 2
  285. }
  286. }
  287. onInput(e) {
  288. console.log('oninput', e.type, e.target.value)
  289. el = values.shift()
  290. this.setState({ value: e.target.value })
  291. }
  292. componentDidUpdate() {
  293. // console.warn(s.mayInst.hostNode.children[0].value);
  294. // expect(s.mayInst.hostNode.children[0].value).toBe(el)
  295. }
  296. render() {
  297. return <div>
  298. <input
  299. id='node4'
  300. value={this.state.value}
  301. onInput={this
  302. .onInput
  303. .bind(this)} />{this.state.value}
  304. <input type='input' id="node3" />
  305. <input type='button' value='提交' />
  306. </div>
  307. }
  308. }
  309. var s = React.render(<Input />, div)
  310. expect(s.mayInst.hostNode.children[0].value).toBe('2')
  311. })
  312. it('测试textarea元素的oninput事件', async () => {
  313. var values = ['y', 'yy', 'yyy', 'yyyy']
  314. var el = ''
  315. class TextArea extends React.Component {
  316. constructor() {
  317. super()
  318. this.state = {
  319. value: 4
  320. }
  321. }
  322. onInput(e) {
  323. el = values.shift()
  324. this.setState({ value: e.target.value })
  325. }
  326. componentDidUpdate() {
  327. // expect(s._renderedVnode._hostNode.children[0].value).toBe(el)
  328. }
  329. render() {
  330. return <div>
  331. <textarea
  332. id='node5'
  333. onInput={this
  334. .onInput
  335. .bind(this)}>{this.state.value}</textarea>{this.state.value}
  336. </div>
  337. }
  338. }
  339. var s = React.render(<TextArea />, div)
  340. expect(s.mayInst.hostNode.children[0].value).toBe('4')
  341. // await browser
  342. // .setValue('#node5', 'yyyy').pause(300).$apply()
  343. })
  344. it('非受控组件textarea的value不可变', async () => {
  345. class TextArea extends React.Component {
  346. constructor() {
  347. super()
  348. this.state = {
  349. value: 5
  350. }
  351. }
  352. render() {
  353. return <div>
  354. <textarea id='node6' value={this.state.value}></textarea>{this.state.value}
  355. </div>
  356. }
  357. }
  358. var s = React.render(<TextArea />, div)
  359. // expect(s.mayInst.hostNode.children[0].value).toBe('5')
  360. })
  361. it('非受控组件checkbox的checked不可变', async () => {
  362. class Checkbox extends React.Component {
  363. constructor() {
  364. super()
  365. this.state = {
  366. value: true
  367. }
  368. }
  369. render() {
  370. return <div>
  371. <input id='node7' type='checkbox' name='xxx' checked={this.state.value} />
  372. </div>
  373. }
  374. }
  375. var s = React.render(<Checkbox />, div)
  376. expect(s.mayInst.hostNode.children[0].checked).toBe(true)
  377. })
  378. it('非受控组件radio的checked不可变', async () => {
  379. class Radio extends React.Component {
  380. constructor() {
  381. super()
  382. this.state = {
  383. value: false
  384. }
  385. }
  386. render() {
  387. return <div>
  388. <input id='radio7' type='checkbox' name='xxx' checked={this.state.value} />
  389. </div>
  390. }
  391. }
  392. var s = React.render(<Radio />, div)
  393. expect(s.mayInst.hostNode.children[0].checked).toBe(false)
  394. ReactTestUtils.Simulate.click(document.getElementById('radio7'));
  395. expect(s.mayInst.hostNode.children[0].checked).toBe(false)
  396. })
  397. it('元素节点存在dangerouslySetInnerHTML', async () => {
  398. class App extends React.Component {
  399. constructor() {
  400. super()
  401. this.state = {
  402. aaa: 0
  403. }
  404. }
  405. change(s) {
  406. this.setState({
  407. aaa: 1
  408. })
  409. }
  410. render() {
  411. return <div>{this.state.aaa === 1 ? <p dangerouslySetInnerHTML={{ __html: "<span>111</span" }} >222</p> :
  412. <p><strong>222</strong></p>
  413. }</div>
  414. }
  415. }
  416. var s = React.render(<App />, div)
  417. expect(div.getElementsByTagName('strong').length).toBe(1)
  418. s.change(1)
  419. expect(div.getElementsByTagName('span').length).toBe(1)
  420. })
  421. it('非受控组件select的value不可变', async () => {
  422. class Com extends React.Component {
  423. constructor() {
  424. super()
  425. this.state = {
  426. value: 'bbb'
  427. }
  428. }
  429. render() {
  430. return <select id='node8' value={this.state.value}>
  431. <option value='aaa'>aaa</option>
  432. <option value='bbb'>bbb</option>
  433. <option value='ccc'>ccc</option>
  434. </select>
  435. }
  436. }
  437. var s = React.render(<Com />, div)
  438. // expect(s.mayInst.hostNode.children[1].selected).toBe(true)
  439. // expect(s.mayInst.hostNode.children[2].selected).toBe(false)
  440. // expect(s.mayInst.hostNode.children[1].selected).toBe(true)
  441. })
  442. it('父子组件间的通信', async () => {
  443. class Select extends React.Component {
  444. constructor(props) {
  445. super(props)
  446. this.state = {
  447. value: props.value
  448. }
  449. this.onUpdate = props.onUpdate
  450. this.onChange = this.onChange.bind(this)
  451. }
  452. componentWillReceiveProps(props) {
  453. this.state = { //更新自己
  454. value: props.value
  455. }
  456. }
  457. onChange(e) {//让父组件更新自己
  458. this.onUpdate(e.target.value)
  459. }
  460. render() {
  461. return <select id="communicate" value={this.state.value} onChange={this.onChange}>
  462. <option>北京</option>
  463. <option>南京</option>
  464. <option>东京</option>
  465. </select>
  466. }
  467. }
  468. class App extends React.Component {
  469. constructor(props) {
  470. super(props)
  471. this.state = {
  472. value: '南京'
  473. }
  474. }
  475. onUpdate(value) { //让子组件调用这个父组件的方法
  476. this.setState({
  477. value: value
  478. })
  479. }
  480. onChange(e) {
  481. this.onUpdate(e.target.value)
  482. }
  483. render() {
  484. return <div><Select onUpdate={this.onUpdate.bind(this)} value={this.state.value} /><input ref='sss' value={this.state.value} onChange={this.onChange.bind(this)} /></div>
  485. }
  486. }
  487. var s = React.render(<App />, div)
  488. expect(s.refs.sss.value).toBe('南京')
  489. })
  490. it('empty Component', async () => {
  491. class Empty extends React.Component {
  492. render() {
  493. return null
  494. }
  495. }
  496. class App extends React.Component {
  497. constructor(props) {
  498. super(props)
  499. this.state = {
  500. value: '南京'
  501. }
  502. }
  503. onUpdate(value) { //让子组件调用这个父组件的方法
  504. this.setState({
  505. value: value
  506. })
  507. }
  508. onChange(e) {//让父组件更新自己
  509. this.onUpdate(e.target.value)
  510. }
  511. render() {
  512. return <div><Empty />
  513. <input ref="a" value={this.state.value} onInput={this.onChange.bind(this)} /></div>
  514. }
  515. }
  516. var s = React.render(<App />, div)
  517. expect(s.refs.a.value).toBe('南京')
  518. // await browser.setValue(s.refs.a, '北京').pause(100)
  519. // .$apply()
  520. // expect(s.refs.a.value).toBe('北京')
  521. })
  522. it('移除组件', async () => {
  523. var str = ''
  524. class Component1 extends React.Component {
  525. componentWillUnmount() {
  526. str += 'xxxx'
  527. }
  528. render() {
  529. return <div className="component1">{this.props.children}</div>
  530. }
  531. }
  532. class Component2 extends React.Component {
  533. componentWillUnmount() {
  534. str += ' yyyy'
  535. }
  536. render() {
  537. return <div className="component2">xxx</div>
  538. }
  539. }
  540. var index = 1
  541. function detect(a) {
  542. console.log('detect 方法', index, a)
  543. if (index === 1) {
  544. expect(typeof a).toBe('object')
  545. } else {
  546. expect(a).toBeNull()
  547. }
  548. }
  549. class App extends React.Component {
  550. constructor(props) {
  551. super(props)
  552. this.handleClick = this.handleClick.bind(this)
  553. }
  554. handleClick() {
  555. index = 0
  556. this.forceUpdate()
  557. setTimeout(function () {
  558. console.warn('应该输出', str)
  559. })
  560. }
  561. render() {
  562. return index ?
  563. <div ref='a' onClick={this.handleClick.bind(this)}>
  564. <Component1>
  565. <p ref={detect}>这是子节点(移除节点测试1)</p>
  566. <Component2 />
  567. </Component1>
  568. </div> : <div>文本节点</div>
  569. }
  570. };
  571. var s = React.render(<App />, div)
  572. ReactTestUtils.Simulate.click(s.refs.a);
  573. // await browser.pause(100).click(s.refs.a).pause(100)
  574. // .$apply()
  575. expect(str).toBe('xxxx yyyy')
  576. })
  577. it('移除组件2', async () => {
  578. var index = 1
  579. class App extends React.Component {
  580. constructor(props) {
  581. super(props)
  582. this.handleClick = this.handleClick.bind(this)
  583. }
  584. handleClick() {
  585. index = 0
  586. this.forceUpdate()
  587. }
  588. render() {
  589. return index ?
  590. <div ref='a' onClick={this.handleClick.bind(this)}>
  591. <div ref='b'><span>这是点击前</span></div>
  592. </div> : <div><p><strong>这是点击后</strong></p></div>
  593. }
  594. };
  595. var s = React.render(<App />, div)
  596. ReactTestUtils.Simulate.click(s.refs.a);
  597. // await browser.pause(100).click(s.refs.a).pause(100)
  598. // .$apply()
  599. expect(div.getElementsByTagName('p').length).toBe(1)
  600. })
  601. it('removedChildren', async () => {
  602. var index = 1
  603. class App extends React.Component {
  604. constructor(props) {
  605. super(props)
  606. this.handleClick = this.handleClick.bind(this)
  607. }
  608. handleClick() {
  609. index = 0
  610. this.forceUpdate()
  611. }
  612. render() {
  613. return index ?
  614. <div ref='a' onClick={this.handleClick.bind(this)}>
  615. <p><strong>111</strong></p><p>2</p><p>3</p><p>4</p>
  616. </div> : <div><p>11</p></div>
  617. }
  618. };
  619. var s = React.render(<App />, div)
  620. expect(div.getElementsByTagName('p').length).toBe(4)
  621. ReactTestUtils.Simulate.click(s.refs.a);
  622. expect(div.getElementsByTagName('p').length).toBe(1)
  623. })
  624. it('一个元素拥有多个实例', async () => {
  625. var arr = ['111', '222', '333']
  626. class App extends React.Component {
  627. constructor(props) {
  628. super(props)
  629. this.state = {
  630. title: 111
  631. }
  632. }
  633. handleClick() {
  634. this.setState({
  635. title: arr.shift() || new Date - 0
  636. })
  637. }
  638. render() {
  639. return <B title={this.state.title} onClick={this.handleClick.bind(this)} />
  640. }
  641. }
  642. class B extends React.Component {
  643. componentWillReceiveProps() {
  644. this.forceUpdate()
  645. }
  646. render() {
  647. return <div title={this.props.title} onClick={this.props.onClick} >{new Date - 0}<C /></div>;
  648. }
  649. }
  650. class C extends React.Component {
  651. render() {
  652. return <strong >{new Date - 0}</strong>;
  653. }
  654. }
  655. var s = React.render(<App />, div)
  656. expect(div.getElementsByTagName('strong').length).toBe(1)
  657. expect(s instanceof App).toBe(true)
  658. //expect(div.getElementsByTagName('p').length).toBe(1)
  659. })
  660. it('一个元素拥有多个实例2', async () => {
  661. var arr = ['111', '222', '333']
  662. class App extends React.Component {
  663. render() {
  664. return <div><A /></div>
  665. }
  666. }
  667. class A extends React.Component {
  668. constructor(props) {
  669. super(props)
  670. this.state = {
  671. title: 111
  672. }
  673. }
  674. handleClick() {
  675. this.setState({
  676. title: arr.shift() || new Date - 0
  677. })
  678. }
  679. render() {
  680. return <B title={this.state.title} onClick={this.handleClick.bind(this)} />
  681. }
  682. }
  683. class B extends React.Component {
  684. componentWillReceiveProps() {
  685. this.forceUpdate()
  686. }
  687. render() {
  688. return <div title={this.props.title} onClick={this.props.onClick} >{new Date - 0}<C /></div>;
  689. }
  690. }
  691. class C extends React.Component {
  692. render() {
  693. return <strong >{new Date - 0}</strong>;
  694. }
  695. }
  696. var s = React.render(<App />, div)
  697. expect(div.getElementsByTagName('strong').length).toBe(1)
  698. s.forceUpdate()
  699. expect(div.getElementsByTagName('strong').length).toBe(1)
  700. //expect(div.getElementsByTagName('p').length).toBe(1)
  701. })
  702. it('用一个新组件替换另一个组件', async () => {
  703. var index = 1
  704. class App extends React.Component {
  705. handleClick() {
  706. index = 0
  707. this.forceUpdate()
  708. }
  709. render() {
  710. return <div onClick={this.handleClick.bind(this)}>
  711. {index ? <A /> : <B />}</div>
  712. }
  713. }
  714. class A extends React.Component {
  715. render() {
  716. return <strong>111</strong>
  717. }
  718. }
  719. class B extends React.Component {
  720. render() {
  721. return <em>111</em>
  722. }
  723. }
  724. var s = React.render(<App />, div)
  725. expect(div.getElementsByTagName('strong').length).toBe(1)
  726. s.handleClick()
  727. expect(div.getElementsByTagName('em').length).toBe(1)
  728. //expect(div.getElementsByTagName('p').length).toBe(1)
  729. })
  730. it('复杂的孩子转换', async () => {
  731. var index = 0
  732. var map = [
  733. <div >1111<p>ddd</p><span>333</span><Link /></div>,
  734. <div><em>新的</em><span>111</span>222<span>333</span><b>444</b><Link /></div>,
  735. <div><span>33</span></div>
  736. ]
  737. function Link() {
  738. return index == 1 ? <strong>ddd</strong> : <i>ddd</i>
  739. }
  740. class App extends React.Component {
  741. constructor(props) {
  742. super(props)
  743. this.state = {
  744. aaa: 'aaa'
  745. }
  746. }
  747. change(a) {
  748. this.setState({
  749. aaa: a
  750. })
  751. }
  752. componentDidMount() {
  753. console.log('App componentDidMount')
  754. }
  755. componentWillUpdate() {
  756. console.log('App componentWillUpdate')
  757. }
  758. render() {
  759. return map[index++]
  760. }
  761. }
  762. var s = React.render(<App />, div)
  763. function getString(nodes) {
  764. var str = []
  765. for (var i = 0, node; node = nodes[i++];) {
  766. str.push(node.nodeName.toLowerCase())
  767. }
  768. return str.join(' ')
  769. }
  770. expect(getString(div.firstChild.childNodes)).toBe('#text p span strong')
  771. s.change(100)
  772. expect(getString(div.firstChild.childNodes)).toBe('em span #text span b i')
  773. s.change(100)
  774. expect(getString(div.firstChild.childNodes)).toBe('span')
  775. })
  776. it('对一个容器节点反复渲染组件或元素 ', async () => {
  777. class Comp extends React.Component {
  778. render() {
  779. return <span>span in a component</span>;
  780. }
  781. }
  782. let root;
  783. function test(content) {
  784. root = React.render(content, div);
  785. }
  786. test(<Comp />);
  787. test(<div>just a div</div>);
  788. test(<Comp />);
  789. expect(div.firstChild.innerHTML).toBe('span in a component');
  790. });
  791. it('切换style对象', async () => {
  792. var index = 1
  793. class Comp extends React.Component {
  794. render() {
  795. return <span style={index ? { color: 'red' } : null}>span in a component</span>;
  796. }
  797. }
  798. let root;
  799. function test(content) {
  800. root = React.render(content, div);
  801. }
  802. test(<Comp />);
  803. expect(div.firstChild.style.color).toBe('red');
  804. index = 0
  805. test(<Comp />);
  806. expect(div.firstChild.style.color).toBe('');
  807. });
  808. it('子组件的DOM节点改变了,会同步父节点的DOM', async () => {
  809. var s, s2
  810. class App extends React.Component {
  811. constructor(props) {
  812. super(props);
  813. }
  814. render() {
  815. return <A />
  816. }
  817. }
  818. class A extends React.Component {
  819. constructor(props) {
  820. super(props);
  821. }
  822. render() {
  823. return <B />
  824. }
  825. }
  826. class B extends React.Component {
  827. constructor(props) {
  828. super(props);
  829. this.state = {
  830. value: '3333'
  831. };
  832. }
  833. componentDidMount() {
  834. s2 = this
  835. }
  836. render() {
  837. return this.state.value ? <div>111</div> : <strong>3333</strong>
  838. }
  839. }
  840. var s = React.render(<App />, div);
  841. expect(s.mayInst.hostNode ).toBe(s2.mayInst.rendered.mayInfo.hostNode);
  842. s2.setState({value: 0});//子组件改变后 父组件的ref跟着变动
  843. // expect(s.updater._hostNode ).toBe(s2.updater._hostNode);
  844. // expect(s.updater._hostNode.nodeName).toBe('STRONG');
  845. })
  846. })