ReactContextValidator-test.jsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. import React from "../../src/May";
  2. import ReactTestUtils from "../../lib/ReactTestUtils";
  3. import PropTypes from '../../lib/ReactPropTypes';
  4. import { render, unmountComponentAtNode } from '../../src/may-dom/MayDom'
  5. var ReactDOM = {
  6. render: render,
  7. unmountComponentAtNode: unmountComponentAtNode
  8. }
  9. React.render = render;
  10. // import React from "../../dist/ReactANU";
  11. // var ReactDOM = React;
  12. // https://github.com/facebook/react/blob/master/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
  13. describe('ReactContextValidator', function () {
  14. // this.timeout(200000);
  15. function normalizeCodeLocInfo(str) {
  16. return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
  17. }
  18. // TODO: This behavior creates a runtime dependency on propTypes. We should
  19. // ensure that this is not required for ES6 classes with Flow.
  20. it('should filter out context not in contextTypes', () => {
  21. class Component extends React.Component {
  22. render() {
  23. return <div />;
  24. }
  25. }
  26. Component.contextTypes = {
  27. foo: PropTypes.string,
  28. };
  29. class ComponentInFooBarContext extends React.Component {
  30. getChildContext() {
  31. return {
  32. foo: 'abc',
  33. bar: 123,
  34. };
  35. }
  36. render() {
  37. return <Component ref="child" />;
  38. }
  39. }
  40. ComponentInFooBarContext.childContextTypes = {
  41. foo: PropTypes.string,
  42. bar: PropTypes.number,
  43. };
  44. // var instance = ReactTestUtils.renderIntoDocument(
  45. // <ComponentInFooBarContext />,
  46. // );
  47. // expect(instance.refs.child.context).toEqual({ foo: 'abc' });
  48. });
  49. it('should pass next context to lifecycles', () => {
  50. var actualComponentWillReceiveProps;
  51. var actualShouldComponentUpdate;
  52. var actualComponentWillUpdate;
  53. class Parent extends React.Component {
  54. getChildContext() {
  55. return {
  56. foo: this.props.foo,
  57. bar: 'bar',
  58. };
  59. }
  60. render() {
  61. return <Component />;
  62. }
  63. }
  64. Parent.childContextTypes = {
  65. foo: PropTypes.string.isRequired,
  66. bar: PropTypes.string.isRequired,
  67. };
  68. class Component extends React.Component {
  69. componentWillReceiveProps(nextProps, nextContext) {
  70. actualComponentWillReceiveProps = nextContext;
  71. return true;
  72. }
  73. shouldComponentUpdate(nextProps, nextState, nextContext) {
  74. actualShouldComponentUpdate = nextContext;
  75. return true;
  76. }
  77. componentWillUpdate(nextProps, nextState, nextContext) {
  78. actualComponentWillUpdate = nextContext;
  79. }
  80. render() {
  81. return <div />;
  82. }
  83. }
  84. Component.contextTypes = {
  85. foo: PropTypes.string,
  86. };
  87. var container = document.createElement('div');
  88. ReactDOM.render(<Parent foo="abc" />, container);
  89. ReactDOM.render(<Parent foo="def" />, container);
  90. expect(actualComponentWillReceiveProps).toEqual({ foo: 'def' });
  91. expect(actualShouldComponentUpdate).toEqual({ foo: 'def' });
  92. expect(actualComponentWillUpdate).toEqual({ foo: 'def' });
  93. });
  94. it('should not pass previous context to lifecycles', () => {
  95. var actualComponentDidUpdate;
  96. class Parent extends React.Component {
  97. getChildContext() {
  98. return {
  99. foo: this.props.foo,
  100. };
  101. }
  102. render() {
  103. return <Component />;
  104. }
  105. }
  106. Parent.childContextTypes = {
  107. foo: PropTypes.string.isRequired,
  108. };
  109. class Component extends React.Component {
  110. componentDidUpdate(...args) {
  111. actualComponentDidUpdate = args;
  112. }
  113. render() {
  114. return <div />;
  115. }
  116. }
  117. Component.contextTypes = {
  118. foo: PropTypes.string,
  119. };
  120. var container = document.createElement('div');
  121. ReactDOM.render(<Parent foo="abc" />, container);
  122. ReactDOM.render(<Parent foo="def" />, container);
  123. expect(actualComponentDidUpdate.length).toBe(3);
  124. });
  125. it('should check context types', () => {
  126. spyOn(console, 'error')
  127. class Component extends React.Component {
  128. render() {
  129. return <div />;
  130. }
  131. }
  132. Component.contextTypes = {
  133. foo: PropTypes.string.isRequired,
  134. };
  135. ReactTestUtils.renderIntoDocument(<Component />);
  136. // PropTypes 为空实现所以没有报错
  137. expect(console.error.calls.count()).toBe(0);
  138. class ComponentInFooStringContext extends React.Component {
  139. getChildContext() {
  140. return {
  141. foo: this.props.fooValue,
  142. };
  143. }
  144. render() {
  145. return <Component />;
  146. }
  147. }
  148. ComponentInFooStringContext.childContextTypes = {
  149. foo: PropTypes.string,
  150. };
  151. ReactTestUtils.renderIntoDocument(
  152. <ComponentInFooStringContext fooValue={'bar'} />,
  153. );
  154. // PropTypes 为空实现所以没有报错
  155. expect(console.error.calls.count()).toBe(0);
  156. class ComponentInFooNumberContext extends React.Component {
  157. getChildContext() {
  158. return {
  159. foo: this.props.fooValue,
  160. };
  161. }
  162. render() {
  163. return <Component />;
  164. }
  165. }
  166. ComponentInFooNumberContext.childContextTypes = {
  167. foo: PropTypes.number,
  168. };
  169. ReactTestUtils.renderIntoDocument(
  170. <ComponentInFooNumberContext fooValue={123} />,
  171. );
  172. // PropTypes 为空实现所以没有报错
  173. expect(console.error.calls.count()).toBe(0);
  174. });
  175. it('should check child context types', () => {
  176. spyOn(console, 'error')
  177. class Component extends React.Component {
  178. getChildContext() {
  179. return this.props.testContext;
  180. }
  181. render() {
  182. return <div />;
  183. }
  184. }
  185. Component.childContextTypes = {
  186. foo: PropTypes.string.isRequired,
  187. bar: PropTypes.number,
  188. };
  189. ReactTestUtils.renderIntoDocument(<Component testContext={{ bar: 123 }} />);
  190. // PropTypes 为空实现所以没有报错
  191. expect(console.error.calls.count()).toBe(0);
  192. ReactTestUtils.renderIntoDocument(<Component testContext={{ foo: 123 }} />);
  193. // PropTypes 为空实现所以没有报错
  194. expect(console.error.calls.count()).toBe(0);
  195. ReactTestUtils.renderIntoDocument(
  196. <Component testContext={{ foo: 'foo', bar: 123 }} />,
  197. );
  198. ReactTestUtils.renderIntoDocument(<Component testContext={{ foo: 'foo' }} />);
  199. // PropTypes 为空实现所以没有报错
  200. expect(console.error.calls.count()).toBe(0);
  201. });
  202. // TODO (bvaughn) Remove this test and the associated behavior in the future.
  203. // It has only been added in Fiber to match the (unintentional) behavior in Stack.
  204. it('should warn (but not error) if getChildContext method is missing', () => {
  205. spyOn(console, 'error')
  206. class ComponentA extends React.Component {
  207. static childContextTypes = {
  208. foo: PropTypes.string.isRequired,
  209. };
  210. render() {
  211. return <div />;
  212. }
  213. }
  214. class ComponentB extends React.Component {
  215. static childContextTypes = {
  216. foo: PropTypes.string.isRequired,
  217. };
  218. render() {
  219. return <div />;
  220. }
  221. }
  222. ReactTestUtils.renderIntoDocument(<ComponentA />);
  223. // PropTypes 为空实现所以没有报错
  224. expect(console.error.calls.count()).toBe(0);
  225. // Warnings should be deduped by component type
  226. ReactTestUtils.renderIntoDocument(<ComponentA />);
  227. // PropTypes 为空实现所以没有报错
  228. expect(console.error.calls.count()).toBe(0);
  229. // PropTypes 为空实现所以没有报错
  230. ReactTestUtils.renderIntoDocument(<ComponentB />);
  231. // PropTypes 为空实现所以没有报错
  232. expect(console.error.calls.count()).toBe(0);
  233. });
  234. // TODO (bvaughn) Remove this test and the associated behavior in the future.
  235. // It has only been added in Fiber to match the (unintentional) behavior in Stack.
  236. it('should pass parent context if getChildContext method is missing', () => {
  237. class ParentContextProvider extends React.Component {
  238. static childContextTypes = {
  239. foo: PropTypes.number,
  240. };
  241. getChildContext() {
  242. return {
  243. foo: 'FOO',
  244. };
  245. }
  246. render() {
  247. return <MiddleMissingContext />;
  248. }
  249. }
  250. class MiddleMissingContext extends React.Component {
  251. static childContextTypes = {
  252. bar: PropTypes.string.isRequired,
  253. };
  254. render() {
  255. return <ChildContextConsumer />;
  256. }
  257. }
  258. var childContext;
  259. class ChildContextConsumer extends React.Component {
  260. render() {
  261. childContext = this.context;
  262. return <div />;
  263. }
  264. }
  265. ChildContextConsumer.contextTypes = {
  266. bar: PropTypes.string.isRequired,
  267. foo: PropTypes.string.isRequired,
  268. };
  269. ReactTestUtils.renderIntoDocument(<ParentContextProvider />);
  270. expect(childContext.bar).toBeUndefined();
  271. expect(childContext.foo).toBe('FOO');
  272. });
  273. });