react-native-navigation的迁移库

LayoutTreeParser.test.ts 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. import keys from 'lodash/keys';
  2. import { LayoutTreeParser } from './LayoutTreeParser';
  3. import { LayoutType } from './LayoutType';
  4. import { Options } from '../interfaces/Options';
  5. import { Layout } from '../interfaces/Layout';
  6. import { UniqueIdProvider } from '../adapters/UniqueIdProvider';
  7. import { mock, instance, when, anything } from 'ts-mockito';
  8. describe('LayoutTreeParser', () => {
  9. let uut: LayoutTreeParser;
  10. let mockedUniqueIdProvider: UniqueIdProvider;
  11. beforeEach(() => {
  12. mockedUniqueIdProvider = mock(UniqueIdProvider);
  13. when(mockedUniqueIdProvider.generate(anything())).thenReturn('myUniqueId');
  14. uut = new LayoutTreeParser(instance(mockedUniqueIdProvider));
  15. });
  16. describe('parses into { type, data, children }', () => {
  17. it('unknown type', () => {
  18. expect(() => uut.parse({ wut: {} } as Layout)).toThrowError('unknown LayoutType "wut"');
  19. });
  20. it('single component', () => {
  21. expect(uut.parse(LayoutExamples.singleComponent)).toEqual({
  22. id: 'myUniqueId',
  23. type: LayoutType.Component,
  24. data: {
  25. name: 'MyReactComponent',
  26. options: LayoutExamples.options,
  27. passProps: LayoutExamples.passProps
  28. },
  29. children: []
  30. });
  31. });
  32. it('external component', () => {
  33. expect(uut.parse(LayoutExamples.externalComponent)).toEqual({
  34. id: 'myUniqueId',
  35. type: LayoutType.ExternalComponent,
  36. data: {
  37. name: 'MyReactComponent',
  38. options: LayoutExamples.options,
  39. passProps: LayoutExamples.passProps
  40. },
  41. children: []
  42. });
  43. });
  44. it('pass props', () => {
  45. const result = uut.parse({
  46. component: {
  47. name: 'MyScreen',
  48. passProps: LayoutExamples.passProps
  49. }
  50. });
  51. expect(result).toEqual({
  52. id: 'myUniqueId',
  53. type: LayoutType.Component,
  54. data: { name: 'MyScreen', passProps: LayoutExamples.passProps },
  55. children: []
  56. });
  57. expect(result.data.passProps).toBe(LayoutExamples.passProps);
  58. });
  59. it('stack of components with top bar', () => {
  60. expect(uut.parse(LayoutExamples.stackWithTopBar)).toEqual({
  61. id: 'myUniqueId',
  62. type: LayoutType.Stack,
  63. data: {
  64. options: LayoutExamples.options
  65. },
  66. children: [
  67. {
  68. id: 'myUniqueId',
  69. type: LayoutType.Component,
  70. data: { name: 'MyReactComponent1' },
  71. children: []
  72. },
  73. {
  74. id: 'myUniqueId',
  75. type: LayoutType.Component,
  76. data: { name: 'MyReactComponent2', options: LayoutExamples.options },
  77. children: []
  78. }
  79. ]
  80. });
  81. });
  82. it('bottom tabs', () => {
  83. const result = uut.parse(LayoutExamples.bottomTabs);
  84. expect(keys(result)).toEqual(['id', 'type', 'data', 'children']);
  85. expect(result.id).toEqual('myUniqueId');
  86. expect(result.type).toEqual(LayoutType.BottomTabs);
  87. expect(result.data).toEqual({});
  88. expect(result.children.length).toEqual(3);
  89. expect(result.children[0].type).toEqual(LayoutType.Stack);
  90. expect(result.children[1].type).toEqual(LayoutType.Stack);
  91. expect(result.children[2].type).toEqual(LayoutType.Component);
  92. });
  93. it('side menus', () => {
  94. const result = uut.parse(LayoutExamples.sideMenu);
  95. expect(keys(result)).toEqual(['id', 'type', 'data', 'children']);
  96. expect(result.id).toEqual('myUniqueId');
  97. expect(result.type).toEqual(LayoutType.SideMenuRoot);
  98. expect(result.data).toEqual({});
  99. expect(result.children.length).toEqual(3);
  100. expect(result.children[0].type).toEqual(LayoutType.SideMenuLeft);
  101. expect(result.children[1].type).toEqual(LayoutType.SideMenuCenter);
  102. expect(result.children[2].type).toEqual(LayoutType.SideMenuRight);
  103. expect(result.children[0].children.length).toEqual(1);
  104. expect(result.children[0].children[0].type).toEqual(LayoutType.Component);
  105. expect(result.children[1].children.length).toEqual(1);
  106. expect(result.children[1].children[0].type).toEqual(LayoutType.Stack);
  107. expect(result.children[2].children.length).toEqual(1);
  108. expect(result.children[2].children[0].type).toEqual(LayoutType.Component);
  109. });
  110. it('top tabs', () => {
  111. const result = uut.parse(LayoutExamples.topTabs);
  112. expect(keys(result)).toEqual(['id', 'type', 'data', 'children']);
  113. expect(result.id).toEqual('myUniqueId');
  114. expect(result.type).toEqual(LayoutType.TopTabs);
  115. expect(result.data).toEqual({ options: LayoutExamples.options });
  116. expect(result.children.length).toEqual(5);
  117. expect(result.children[0].type).toEqual(LayoutType.Component);
  118. expect(result.children[1].type).toEqual(LayoutType.Component);
  119. expect(result.children[2].type).toEqual(LayoutType.Component);
  120. expect(result.children[3].type).toEqual(LayoutType.Component);
  121. expect(result.children[4].type).toEqual(LayoutType.Stack);
  122. });
  123. it('complex layout example', () => {
  124. const result = uut.parse(LayoutExamples.complexLayout);
  125. expect(result.type).toEqual('SideMenuRoot');
  126. expect(result.children[1].type).toEqual('SideMenuCenter');
  127. expect(result.children[1].children[0].type).toEqual('BottomTabs');
  128. expect(result.children[1].children[0].children[2].type).toEqual('Stack');
  129. });
  130. it('split view', () => {
  131. const result = uut.parse(LayoutExamples.splitView);
  132. const master = uut.parse(LayoutExamples.splitView.splitView!.master!);
  133. const detail = uut.parse(LayoutExamples.splitView.splitView!.detail!);
  134. expect(result.type).toEqual('SplitView');
  135. expect(result.children[0]).toEqual(master);
  136. expect(result.children[1]).toEqual(detail);
  137. });
  138. });
  139. it('options for all containing types', () => {
  140. expect(uut.parse({ component: { name: 'lol', options } }).data.options).toBe(options);
  141. expect(uut.parse({ stack: { options } }).data.options).toBe(options);
  142. expect(uut.parse({ bottomTabs: { options } }).data.options).toBe(options);
  143. expect(uut.parse({ topTabs: { options } }).data.options).toBe(options);
  144. expect(
  145. uut.parse({ sideMenu: { options, center: { component: { name: 'lool' } } } }).data.options
  146. ).toBe(options);
  147. expect(uut.parse(LayoutExamples.splitView).data.options).toBe(optionsSplitView);
  148. });
  149. it('pass user provided id as is', () => {
  150. const component = { id: 'compId', name: 'loool' };
  151. expect(uut.parse({ component }).id).toEqual('compId');
  152. expect(uut.parse({ stack: { id: 'stackId' } }).id).toEqual('stackId');
  153. expect(uut.parse({ stack: { children: [{ component }] } }).children[0].id).toEqual('compId');
  154. expect(uut.parse({ bottomTabs: { id: 'myId' } }).id).toEqual('myId');
  155. expect(uut.parse({ bottomTabs: { children: [{ component }] } }).children[0].id).toEqual(
  156. 'compId'
  157. );
  158. expect(uut.parse({ topTabs: { id: 'myId' } }).id).toEqual('myId');
  159. expect(uut.parse({ topTabs: { children: [{ component }] } }).children[0].id).toEqual('compId');
  160. expect(uut.parse({ sideMenu: { id: 'myId', center: { component } } }).id).toEqual('myId');
  161. });
  162. });
  163. /* Layout Examples: */
  164. const passProps = {
  165. strProp: 'string prop',
  166. numProp: 12345,
  167. objProp: { inner: { foo: 'bar' } },
  168. fnProp: () => 'Hello from a function'
  169. };
  170. const options: Options = {
  171. topBar: {
  172. title: {
  173. text: 'Hello1'
  174. }
  175. }
  176. };
  177. const optionsSplitView: Options = {
  178. topBar: {
  179. title: {
  180. text: 'Hello1',
  181. }
  182. },
  183. splitView: {
  184. displayMode: 'auto',
  185. primaryEdge: 'leading',
  186. minWidth: 150,
  187. maxWidth: 300
  188. }
  189. };
  190. const singleComponent = {
  191. component: {
  192. name: 'MyReactComponent',
  193. options,
  194. passProps
  195. }
  196. };
  197. const externalComponent = {
  198. externalComponent: {
  199. name: 'MyReactComponent',
  200. options,
  201. passProps
  202. }
  203. };
  204. const stackWithTopBar = {
  205. stack: {
  206. children: [
  207. {
  208. component: {
  209. name: 'MyReactComponent1'
  210. }
  211. },
  212. {
  213. component: {
  214. name: 'MyReactComponent2',
  215. options
  216. }
  217. }
  218. ],
  219. options
  220. }
  221. };
  222. const bottomTabs = {
  223. bottomTabs: {
  224. children: [
  225. stackWithTopBar,
  226. stackWithTopBar,
  227. {
  228. component: {
  229. name: 'MyReactComponent1'
  230. }
  231. }
  232. ]
  233. }
  234. };
  235. const sideMenu = {
  236. sideMenu: {
  237. left: singleComponent,
  238. center: stackWithTopBar,
  239. right: singleComponent
  240. }
  241. };
  242. const topTabs = {
  243. topTabs: {
  244. children: [singleComponent, singleComponent, singleComponent, singleComponent, stackWithTopBar],
  245. options
  246. }
  247. };
  248. const complexLayout: Layout = {
  249. sideMenu: {
  250. left: singleComponent,
  251. center: {
  252. bottomTabs: {
  253. children: [
  254. stackWithTopBar,
  255. stackWithTopBar,
  256. {
  257. stack: {
  258. children: [singleComponent, singleComponent, singleComponent, singleComponent]
  259. }
  260. }
  261. ]
  262. }
  263. }
  264. }
  265. };
  266. const splitView: Layout = {
  267. splitView: {
  268. master: {
  269. stack: {
  270. children: [singleComponent],
  271. options
  272. }
  273. },
  274. detail: stackWithTopBar,
  275. options: optionsSplitView
  276. }
  277. };
  278. const LayoutExamples = {
  279. passProps,
  280. options,
  281. singleComponent,
  282. stackWithTopBar,
  283. bottomTabs,
  284. sideMenu,
  285. topTabs,
  286. complexLayout,
  287. externalComponent,
  288. splitView
  289. };