redux.spec.jsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. import React from '../../src/May';
  2. import ReactTestUtils from "../../lib/ReactTestUtils";
  3. // import React from "../../dist/ReactANU";
  4. // var ReactDOM = React;
  5. // var ReactTestUtils = {
  6. // renderIntoDocument: function (element) {
  7. // var div = document.createElement("div");
  8. // return React.render(element, div);
  9. // }
  10. // };
  11. var Redux = require("redux");
  12. var ReactRedux = require("react-redux");
  13. describe("Redux", function () {
  14. // this.timeout(200000);
  15. // before(async () => {
  16. // await beforeHook();
  17. // });
  18. // after(async () => {
  19. // await afterHook(false);
  20. // });
  21. var body = document.body,
  22. div;
  23. beforeEach(function () {
  24. div = document.createElement("div");
  25. body.appendChild(div);
  26. });
  27. afterEach(function () {
  28. body.removeChild(div);
  29. });
  30. it("Counter", async () => {
  31. class Counter extends React.Component {
  32. render() {
  33. return (
  34. <div>
  35. <h1 ref="value">{this.props.value}</h1>
  36. <button ref="a" onClick={this.props.onIncrement}>
  37. +
  38. </button>&nbsp;
  39. <button ref="b" onClick={this.props.onDecrement}>
  40. -
  41. </button>
  42. </div>
  43. );
  44. }
  45. }
  46. const reducer = (state = 0, action) => {
  47. switch (action.type) {
  48. case "INCREMENT":
  49. return state + 1;
  50. case "DECREMENT":
  51. return state - 1;
  52. default:
  53. return state;
  54. }
  55. };
  56. const store = Redux.createStore(reducer);
  57. function onIncrement() {
  58. store.dispatch({ type: "INCREMENT" });
  59. }
  60. function onDecrement() {
  61. store.dispatch({ type: "DECREMENT" });
  62. }
  63. const render = () => {
  64. return ReactDOM.render(
  65. <Counter
  66. value={store.getState()}
  67. onIncrement={onIncrement}
  68. onDecrement={onDecrement}
  69. />,
  70. div
  71. );
  72. };
  73. var s = render();
  74. store.subscribe(render);
  75. expect(s.refs.value.innerHTML).toBe("0");
  76. expect(s.refs.a.tagName).toBe("BUTTON");
  77. ReactTestUtils.Simulate.click(s.refs.a);
  78. expect(s.refs.value.innerHTML).toBe("10");//1
  79. // await browser
  80. // .click(s.refs.a)
  81. // .pause(100)
  82. // .$apply();
  83. // expect(s.refs.value.innerHTML).toBe("2");
  84. // await browser
  85. // .click(s.refs.b)
  86. // .pause(100)
  87. // .$apply();
  88. // expect(s.refs.value.innerHTML).toBe("1");
  89. });
  90. /*it("TreeView", async () => {
  91. var idArr = ["tree1", "tree2", "tree3", "tree4", "tree5", "tree6", "tree7"];
  92. var combineReducers = Redux.combineReducers;
  93. var Provider = ReactRedux.Provider;
  94. var connect = ReactRedux.connect;
  95. var createStore = Redux.createStore;
  96. function generateTree() {
  97. let tree = {
  98. 0: {
  99. id: 0,
  100. counter: 0,
  101. childIds: []
  102. }
  103. };
  104. for (let i = 1; i < 3; i++) {
  105. let parentId = 0; //Math.floor(Math.pow(Math.random(), 2) * i)
  106. tree[i] = {
  107. id: i,
  108. counter: 0,
  109. childIds: []
  110. };
  111. tree[parentId].childIds.push(i);
  112. }
  113. return tree;
  114. }
  115. const INCREMENT = "INCREMENT";
  116. const CREATE_NODE = "CREATE_NODE";
  117. const DELETE_NODE = "DELETE_NODE";
  118. const ADD_CHILD = "ADD_CHILD";
  119. const REMOVE_CHILD = "REMOVE_CHILD";
  120. const increment = nodeId => ({
  121. type: INCREMENT,
  122. nodeId
  123. });
  124. let nextId = 0;
  125. const createNode = () => ({
  126. type: CREATE_NODE,
  127. nodeId: `new_${nextId++}`
  128. });
  129. const deleteNode = nodeId => ({
  130. type: DELETE_NODE,
  131. nodeId
  132. });
  133. const addChild = (nodeId, childId) => ({
  134. type: ADD_CHILD,
  135. nodeId,
  136. childId
  137. });
  138. const removeChild = (nodeId, childId) => ({
  139. type: REMOVE_CHILD,
  140. nodeId,
  141. childId
  142. });
  143. var actions = {
  144. increment,
  145. createNode,
  146. deleteNode,
  147. addChild,
  148. removeChild
  149. };
  150. class Node extends React.Component {
  151. constructor(props) {
  152. super(props);
  153. this.handleIncrementClick = this.handleIncrementClick.bind(this);
  154. this.handleAddChildClick = this.handleAddChildClick.bind(this);
  155. this.handleRemoveClick = this.handleRemoveClick.bind(this);
  156. this.renderChild = this.renderChild.bind(this);
  157. }
  158. handleIncrementClick() {
  159. const { increment, id } = this.props;
  160. increment(id);
  161. }
  162. handleAddChildClick(e) {
  163. e.preventDefault();
  164. const { addChild, createNode, id } = this.props;
  165. const childId = createNode().nodeId;
  166. addChild(id, childId);
  167. }
  168. handleRemoveClick(e) {
  169. e.preventDefault();
  170. const { removeChild, deleteNode, parentId, id } = this.props;
  171. removeChild(parentId, id);
  172. deleteNode(id);
  173. }
  174. renderChild(childId) {
  175. const { id } = this.props;
  176. return (
  177. <li key={childId}>
  178. <ConnectedNode id={childId} parentId={id} />
  179. </li>
  180. );
  181. }
  182. render() {
  183. const { counter, parentId, childIds } = this.props;
  184. return (
  185. <div>
  186. Counter: {counter}{" "}
  187. <button onClick={this.handleIncrementClick}>+</button>{" "}
  188. {typeof parentId !== "undefined" && (
  189. <a
  190. href="#"
  191. id={idArr.shift()}
  192. onClick={this.handleRemoveClick}
  193. className="remove"
  194. style={{ color: "lightgray", textDecoration: "none" }}
  195. >
  196. ×
  197. </a>
  198. )}
  199. <ul>
  200. {childIds.map(this.renderChild)}
  201. <li key="add">
  202. <a
  203. href="#"
  204. id={idArr.shift()}
  205. onClick={this.handleAddChildClick}
  206. className="add"
  207. >
  208. Add child
  209. </a>
  210. </li>
  211. </ul>
  212. </div>
  213. );
  214. }
  215. }
  216. function mapStateToProps(state, ownProps) {
  217. return state[ownProps.id];
  218. }
  219. const ConnectedNode = connect(mapStateToProps, actions)(Node);
  220. //import { INCREMENT, ADD_CHILD, REMOVE_CHILD, CREATE_NODE, DELETE_NODE } from '../actions'
  221. const childIds = (state, action) => {
  222. switch (action.type) {
  223. case ADD_CHILD:
  224. return [...state, action.childId];
  225. case REMOVE_CHILD:
  226. return state.filter(id => id !== action.childId);
  227. default:
  228. return state;
  229. }
  230. };
  231. const node = (state, action) => {
  232. switch (action.type) {
  233. case CREATE_NODE:
  234. return {
  235. id: action.nodeId,
  236. counter: 0,
  237. childIds: []
  238. };
  239. case INCREMENT:
  240. return {
  241. ...state,
  242. counter: state.counter + 1
  243. };
  244. case ADD_CHILD:
  245. case REMOVE_CHILD:
  246. return {
  247. ...state,
  248. childIds: childIds(state.childIds, action)
  249. };
  250. default:
  251. return state;
  252. }
  253. };
  254. const getAllDescendantIds = (state, nodeId) =>
  255. state[nodeId].childIds.reduce(
  256. (acc, childId) => [
  257. ...acc,
  258. childId,
  259. ...getAllDescendantIds(state, childId)
  260. ],
  261. []
  262. );
  263. const deleteMany = (state, ids) => {
  264. state = { ...state };
  265. ids.forEach(id => delete state[id]);
  266. return state;
  267. };
  268. function reducers(state = {}, action) {
  269. const { nodeId } = action;
  270. if (typeof nodeId === "undefined") {
  271. return state;
  272. }
  273. if (action.type === DELETE_NODE) {
  274. const descendantIds = getAllDescendantIds(state, nodeId);
  275. return deleteMany(state, [nodeId, ...descendantIds]);
  276. }
  277. return {
  278. ...state,
  279. [nodeId]: node(state[nodeId], action)
  280. };
  281. }
  282. const tree = generateTree();
  283. const store = createStore(reducers, tree);
  284. var s = ReactDOM.render(
  285. <Provider store={store}>
  286. <ConnectedNode id={0} />
  287. </Provider>,
  288. div
  289. );
  290. // var ass = div.getElementsByTagName("a");
  291. // expect(ass.length).toBe(5);
  292. // var el = ass[1];
  293. // await browser
  294. // .click(el)
  295. // .pause(200)
  296. // .$apply();
  297. // expect(ass.length).toBe(el.className === "add" ? 7 : 5);
  298. // await browser
  299. // .click(ass[4])
  300. // .pause(100)
  301. // .$apply();
  302. // expect(ass.length).toBe(5);
  303. });*/
  304. });