@pranaysahith/decap-cms-core 3.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (299) hide show
  1. package/README.md +9 -0
  2. package/dist/@pranaysahith/decap-cms-core.js +52 -0
  3. package/dist/@pranaysahith/decap-cms-core.js.LICENSE.txt +141 -0
  4. package/dist/@pranaysahith/decap-cms-core.js.map +1 -0
  5. package/dist/decap-cms-core.js +47 -0
  6. package/dist/decap-cms-core.js.LICENSE.txt +116 -0
  7. package/dist/decap-cms-core.js.map +1 -0
  8. package/dist/esm/actions/auth.js +97 -0
  9. package/dist/esm/actions/collections.js +15 -0
  10. package/dist/esm/actions/config.js +493 -0
  11. package/dist/esm/actions/deploys.js +79 -0
  12. package/dist/esm/actions/editorialWorkflow.js +480 -0
  13. package/dist/esm/actions/entries.js +865 -0
  14. package/dist/esm/actions/media.js +147 -0
  15. package/dist/esm/actions/mediaLibrary.js +552 -0
  16. package/dist/esm/actions/notifications.js +21 -0
  17. package/dist/esm/actions/search.js +149 -0
  18. package/dist/esm/actions/status.js +74 -0
  19. package/dist/esm/actions/waitUntil.js +32 -0
  20. package/dist/esm/backend.js +1082 -0
  21. package/dist/esm/bootstrap.js +101 -0
  22. package/dist/esm/components/App/App.js +289 -0
  23. package/dist/esm/components/App/Header.js +172 -0
  24. package/dist/esm/components/App/NotFoundPage.js +19 -0
  25. package/dist/esm/components/Collection/Collection.js +198 -0
  26. package/dist/esm/components/Collection/CollectionControls.js +46 -0
  27. package/dist/esm/components/Collection/CollectionSearch.js +222 -0
  28. package/dist/esm/components/Collection/CollectionTop.js +68 -0
  29. package/dist/esm/components/Collection/ControlButton.js +17 -0
  30. package/dist/esm/components/Collection/Entries/Entries.js +73 -0
  31. package/dist/esm/components/Collection/Entries/EntriesCollection.js +241 -0
  32. package/dist/esm/components/Collection/Entries/EntriesSearch.js +113 -0
  33. package/dist/esm/components/Collection/Entries/EntryCard.js +177 -0
  34. package/dist/esm/components/Collection/Entries/EntryListing.js +143 -0
  35. package/dist/esm/components/Collection/FilterControl.js +33 -0
  36. package/dist/esm/components/Collection/FolderRenameControl.js +403 -0
  37. package/dist/esm/components/Collection/GroupControl.js +33 -0
  38. package/dist/esm/components/Collection/NestedCollection.js +308 -0
  39. package/dist/esm/components/Collection/Sidebar.js +91 -0
  40. package/dist/esm/components/Collection/SortControl.js +59 -0
  41. package/dist/esm/components/Collection/ViewStyleControl.js +38 -0
  42. package/dist/esm/components/Editor/Editor.js +466 -0
  43. package/dist/esm/components/Editor/EditorControlPane/EditorControl.js +395 -0
  44. package/dist/esm/components/Editor/EditorControlPane/EditorControlPane.js +254 -0
  45. package/dist/esm/components/Editor/EditorControlPane/Widget.js +374 -0
  46. package/dist/esm/components/Editor/EditorInterface.js +386 -0
  47. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreview.js +47 -0
  48. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewContent.js +66 -0
  49. package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewPane.js +288 -0
  50. package/dist/esm/components/Editor/EditorPreviewPane/PreviewHOC.js +27 -0
  51. package/dist/esm/components/Editor/EditorToolbar.js +536 -0
  52. package/dist/esm/components/Editor/EntryPathEditor.js +272 -0
  53. package/dist/esm/components/Editor/withWorkflow.js +56 -0
  54. package/dist/esm/components/EditorWidgets/Unknown/UnknownControl.js +18 -0
  55. package/dist/esm/components/EditorWidgets/Unknown/UnknownPreview.js +20 -0
  56. package/dist/esm/components/EditorWidgets/index.js +4 -0
  57. package/dist/esm/components/MediaLibrary/EmptyMessage.js +22 -0
  58. package/dist/esm/components/MediaLibrary/MediaLibrary.js +446 -0
  59. package/dist/esm/components/MediaLibrary/MediaLibraryButtons.js +93 -0
  60. package/dist/esm/components/MediaLibrary/MediaLibraryCard.js +99 -0
  61. package/dist/esm/components/MediaLibrary/MediaLibraryCardGrid.js +198 -0
  62. package/dist/esm/components/MediaLibrary/MediaLibraryHeader.js +32 -0
  63. package/dist/esm/components/MediaLibrary/MediaLibraryModal.js +156 -0
  64. package/dist/esm/components/MediaLibrary/MediaLibrarySearch.js +51 -0
  65. package/dist/esm/components/MediaLibrary/MediaLibraryTop.js +123 -0
  66. package/dist/esm/components/UI/DragDrop.js +67 -0
  67. package/dist/esm/components/UI/ErrorBoundary.js +173 -0
  68. package/dist/esm/components/UI/FileUploadButton.js +27 -0
  69. package/dist/esm/components/UI/Modal.js +104 -0
  70. package/dist/esm/components/UI/Notifications.js +62 -0
  71. package/dist/esm/components/UI/SettingsDropdown.js +107 -0
  72. package/dist/esm/components/UI/index.js +6 -0
  73. package/dist/esm/components/Workflow/Workflow.js +133 -0
  74. package/dist/esm/components/Workflow/WorkflowCard.js +128 -0
  75. package/dist/esm/components/Workflow/WorkflowList.js +204 -0
  76. package/dist/esm/constants/collectionTypes.js +2 -0
  77. package/dist/esm/constants/collectionViews.js +2 -0
  78. package/dist/esm/constants/commitProps.js +2 -0
  79. package/dist/esm/constants/configSchema.js +644 -0
  80. package/dist/esm/constants/fieldInference.js +57 -0
  81. package/dist/esm/constants/publishModes.js +18 -0
  82. package/dist/esm/constants/validationErrorTypes.js +6 -0
  83. package/dist/esm/formats/formats.js +83 -0
  84. package/dist/esm/formats/frontmatter.js +146 -0
  85. package/dist/esm/formats/helpers.js +12 -0
  86. package/dist/esm/formats/json.js +8 -0
  87. package/dist/esm/formats/toml.js +32 -0
  88. package/dist/esm/formats/yaml.js +51 -0
  89. package/dist/esm/index.js +7 -0
  90. package/dist/esm/integrations/index.js +28 -0
  91. package/dist/esm/integrations/providers/algolia/implementation.js +174 -0
  92. package/dist/esm/integrations/providers/assetStore/implementation.js +165 -0
  93. package/dist/esm/lib/consoleError.js +3 -0
  94. package/dist/esm/lib/formatters.js +191 -0
  95. package/dist/esm/lib/i18n.js +367 -0
  96. package/dist/esm/lib/phrases.js +6 -0
  97. package/dist/esm/lib/polyfill.js +8 -0
  98. package/dist/esm/lib/registry.js +329 -0
  99. package/dist/esm/lib/serializeEntryValues.js +67 -0
  100. package/dist/esm/lib/stega.js +142 -0
  101. package/dist/esm/lib/textHelper.js +9 -0
  102. package/dist/esm/lib/urlHelper.js +111 -0
  103. package/dist/esm/mediaLibrary.js +37 -0
  104. package/dist/esm/reducers/auth.js +27 -0
  105. package/dist/esm/reducers/collections.js +428 -0
  106. package/dist/esm/reducers/combinedReducer.js +8 -0
  107. package/dist/esm/reducers/config.js +29 -0
  108. package/dist/esm/reducers/cursors.js +31 -0
  109. package/dist/esm/reducers/deploys.js +45 -0
  110. package/dist/esm/reducers/editorialWorkflow.js +83 -0
  111. package/dist/esm/reducers/entries.js +568 -0
  112. package/dist/esm/reducers/entryDraft.js +212 -0
  113. package/dist/esm/reducers/globalUI.js +25 -0
  114. package/dist/esm/reducers/index.js +66 -0
  115. package/dist/esm/reducers/integrations.js +53 -0
  116. package/dist/esm/reducers/mediaLibrary.js +252 -0
  117. package/dist/esm/reducers/medias.js +68 -0
  118. package/dist/esm/reducers/notifications.js +23 -0
  119. package/dist/esm/reducers/search.js +92 -0
  120. package/dist/esm/reducers/status.js +30 -0
  121. package/dist/esm/redux/index.js +7 -0
  122. package/dist/esm/redux/middleware/waitUntilAction.js +48 -0
  123. package/dist/esm/routing/history.js +12 -0
  124. package/dist/esm/types/diacritics.d.js +0 -0
  125. package/dist/esm/types/global.d.js +1 -0
  126. package/dist/esm/types/immutable.js +7 -0
  127. package/dist/esm/types/redux.js +14 -0
  128. package/dist/esm/types/tomlify-j0.4.d.js +0 -0
  129. package/dist/esm/valueObjects/AssetProxy.js +44 -0
  130. package/dist/esm/valueObjects/EditorComponent.js +34 -0
  131. package/dist/esm/valueObjects/Entry.js +20 -0
  132. package/index.d.ts +618 -0
  133. package/package.json +106 -0
  134. package/src/__tests__/backend.spec.js +1161 -0
  135. package/src/actions/__tests__/config.spec.js +1009 -0
  136. package/src/actions/__tests__/editorialWorkflow.spec.js +216 -0
  137. package/src/actions/__tests__/entries.spec.js +596 -0
  138. package/src/actions/__tests__/media.spec.ts +171 -0
  139. package/src/actions/__tests__/mediaLibrary.spec.js +327 -0
  140. package/src/actions/__tests__/search.spec.js +209 -0
  141. package/src/actions/auth.ts +127 -0
  142. package/src/actions/collections.ts +18 -0
  143. package/src/actions/config.ts +565 -0
  144. package/src/actions/deploys.ts +104 -0
  145. package/src/actions/editorialWorkflow.ts +567 -0
  146. package/src/actions/entries.ts +1055 -0
  147. package/src/actions/media.ts +139 -0
  148. package/src/actions/mediaLibrary.ts +574 -0
  149. package/src/actions/notifications.ts +36 -0
  150. package/src/actions/search.ts +221 -0
  151. package/src/actions/status.ts +99 -0
  152. package/src/actions/waitUntil.ts +49 -0
  153. package/src/backend.ts +1400 -0
  154. package/src/bootstrap.js +104 -0
  155. package/src/components/App/App.js +286 -0
  156. package/src/components/App/Header.js +266 -0
  157. package/src/components/App/NotFoundPage.js +23 -0
  158. package/src/components/Collection/Collection.js +210 -0
  159. package/src/components/Collection/CollectionControls.js +58 -0
  160. package/src/components/Collection/CollectionSearch.js +243 -0
  161. package/src/components/Collection/CollectionTop.js +81 -0
  162. package/src/components/Collection/ControlButton.js +27 -0
  163. package/src/components/Collection/Entries/Entries.js +82 -0
  164. package/src/components/Collection/Entries/EntriesCollection.js +277 -0
  165. package/src/components/Collection/Entries/EntriesSearch.js +102 -0
  166. package/src/components/Collection/Entries/EntryCard.js +246 -0
  167. package/src/components/Collection/Entries/EntryListing.js +151 -0
  168. package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +163 -0
  169. package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +46 -0
  170. package/src/components/Collection/FilterControl.js +39 -0
  171. package/src/components/Collection/GroupControl.js +39 -0
  172. package/src/components/Collection/NestedCollection.js +330 -0
  173. package/src/components/Collection/Sidebar.js +136 -0
  174. package/src/components/Collection/SortControl.js +68 -0
  175. package/src/components/Collection/ViewStyleControl.js +50 -0
  176. package/src/components/Collection/__tests__/Collection.spec.js +75 -0
  177. package/src/components/Collection/__tests__/NestedCollection.spec.js +445 -0
  178. package/src/components/Collection/__tests__/Sidebar.spec.js +87 -0
  179. package/src/components/Collection/__tests__/__snapshots__/Collection.spec.js.snap +144 -0
  180. package/src/components/Collection/__tests__/__snapshots__/NestedCollection.spec.js.snap +550 -0
  181. package/src/components/Collection/__tests__/__snapshots__/Sidebar.spec.js.snap +312 -0
  182. package/src/components/Editor/Editor.js +497 -0
  183. package/src/components/Editor/EditorControlPane/EditorControl.js +452 -0
  184. package/src/components/Editor/EditorControlPane/EditorControlPane.js +269 -0
  185. package/src/components/Editor/EditorControlPane/Widget.js +384 -0
  186. package/src/components/Editor/EditorInterface.js +444 -0
  187. package/src/components/Editor/EditorPreviewPane/EditorPreview.js +40 -0
  188. package/src/components/Editor/EditorPreviewPane/EditorPreviewContent.js +74 -0
  189. package/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +333 -0
  190. package/src/components/Editor/EditorPreviewPane/PreviewHOC.js +33 -0
  191. package/src/components/Editor/EditorToolbar.js +691 -0
  192. package/src/components/Editor/__tests__/Editor.spec.js +221 -0
  193. package/src/components/Editor/__tests__/EditorToolbar.spec.js +120 -0
  194. package/src/components/Editor/__tests__/__snapshots__/Editor.spec.js.snap +45 -0
  195. package/src/components/Editor/__tests__/__snapshots__/EditorToolbar.spec.js.snap +4233 -0
  196. package/src/components/Editor/withWorkflow.js +61 -0
  197. package/src/components/EditorWidgets/Unknown/UnknownControl.js +17 -0
  198. package/src/components/EditorWidgets/Unknown/UnknownPreview.js +19 -0
  199. package/src/components/EditorWidgets/index.js +5 -0
  200. package/src/components/MediaLibrary/EmptyMessage.js +28 -0
  201. package/src/components/MediaLibrary/MediaLibrary.js +411 -0
  202. package/src/components/MediaLibrary/MediaLibraryButtons.js +136 -0
  203. package/src/components/MediaLibrary/MediaLibraryCard.js +128 -0
  204. package/src/components/MediaLibrary/MediaLibraryCardGrid.js +199 -0
  205. package/src/components/MediaLibrary/MediaLibraryHeader.js +48 -0
  206. package/src/components/MediaLibrary/MediaLibraryModal.js +200 -0
  207. package/src/components/MediaLibrary/MediaLibrarySearch.js +61 -0
  208. package/src/components/MediaLibrary/MediaLibraryTop.js +143 -0
  209. package/src/components/MediaLibrary/__tests__/MediaLibraryButtons.spec.js +45 -0
  210. package/src/components/MediaLibrary/__tests__/MediaLibraryCard.spec.js +49 -0
  211. package/src/components/MediaLibrary/__tests__/__snapshots__/MediaLibraryCard.spec.js.snap +264 -0
  212. package/src/components/UI/DragDrop.js +66 -0
  213. package/src/components/UI/ErrorBoundary.js +214 -0
  214. package/src/components/UI/FileUploadButton.js +24 -0
  215. package/src/components/UI/Modal.js +112 -0
  216. package/src/components/UI/Notifications.tsx +83 -0
  217. package/src/components/UI/SettingsDropdown.js +103 -0
  218. package/src/components/UI/__tests__/ErrorBoundary.spec.js +57 -0
  219. package/src/components/UI/index.js +6 -0
  220. package/src/components/Workflow/Workflow.js +169 -0
  221. package/src/components/Workflow/WorkflowCard.js +177 -0
  222. package/src/components/Workflow/WorkflowList.js +272 -0
  223. package/src/constants/__tests__/configSchema.spec.js +611 -0
  224. package/src/constants/collectionTypes.ts +2 -0
  225. package/src/constants/collectionViews.js +2 -0
  226. package/src/constants/commitProps.ts +2 -0
  227. package/src/constants/configSchema.js +441 -0
  228. package/src/constants/fieldInference.tsx +78 -0
  229. package/src/constants/publishModes.ts +22 -0
  230. package/src/constants/validationErrorTypes.js +6 -0
  231. package/src/formats/__tests__/formats.spec.js +87 -0
  232. package/src/formats/__tests__/frontmatter.spec.js +429 -0
  233. package/src/formats/__tests__/toml.spec.js +9 -0
  234. package/src/formats/__tests__/yaml.spec.js +162 -0
  235. package/src/formats/formats.ts +97 -0
  236. package/src/formats/frontmatter.ts +150 -0
  237. package/src/formats/helpers.ts +14 -0
  238. package/src/formats/json.ts +9 -0
  239. package/src/formats/toml.ts +33 -0
  240. package/src/formats/yaml.ts +58 -0
  241. package/src/index.js +8 -0
  242. package/src/integrations/index.js +35 -0
  243. package/src/integrations/providers/algolia/implementation.js +176 -0
  244. package/src/integrations/providers/assetStore/implementation.js +148 -0
  245. package/src/lib/__tests__/formatters.spec.js +751 -0
  246. package/src/lib/__tests__/i18n.spec.js +792 -0
  247. package/src/lib/__tests__/phrases.spec.js +119 -0
  248. package/src/lib/__tests__/registry.spec.js +261 -0
  249. package/src/lib/__tests__/serializeEntryValues.spec.js +22 -0
  250. package/src/lib/__tests__/urlHelper.spec.js +138 -0
  251. package/src/lib/consoleError.js +7 -0
  252. package/src/lib/formatters.ts +286 -0
  253. package/src/lib/i18n.ts +454 -0
  254. package/src/lib/phrases.js +8 -0
  255. package/src/lib/polyfill.js +9 -0
  256. package/src/lib/registry.js +312 -0
  257. package/src/lib/serializeEntryValues.js +75 -0
  258. package/src/lib/stega.ts +145 -0
  259. package/src/lib/textHelper.js +11 -0
  260. package/src/lib/urlHelper.ts +128 -0
  261. package/src/mediaLibrary.ts +51 -0
  262. package/src/reducers/__tests__/auth.spec.ts +38 -0
  263. package/src/reducers/__tests__/collections.spec.js +610 -0
  264. package/src/reducers/__tests__/config.spec.js +38 -0
  265. package/src/reducers/__tests__/entries.spec.js +694 -0
  266. package/src/reducers/__tests__/entryDraft.spec.js +297 -0
  267. package/src/reducers/__tests__/globalUI.js +43 -0
  268. package/src/reducers/__tests__/integrations.spec.ts +76 -0
  269. package/src/reducers/__tests__/mediaLibrary.spec.js +154 -0
  270. package/src/reducers/__tests__/medias.spec.ts +49 -0
  271. package/src/reducers/auth.ts +46 -0
  272. package/src/reducers/collections.ts +535 -0
  273. package/src/reducers/combinedReducer.ts +11 -0
  274. package/src/reducers/config.ts +38 -0
  275. package/src/reducers/cursors.js +36 -0
  276. package/src/reducers/deploys.ts +52 -0
  277. package/src/reducers/editorialWorkflow.ts +163 -0
  278. package/src/reducers/entries.ts +819 -0
  279. package/src/reducers/entryDraft.js +260 -0
  280. package/src/reducers/globalUI.ts +45 -0
  281. package/src/reducers/index.ts +82 -0
  282. package/src/reducers/integrations.ts +59 -0
  283. package/src/reducers/mediaLibrary.ts +296 -0
  284. package/src/reducers/medias.ts +66 -0
  285. package/src/reducers/notifications.ts +52 -0
  286. package/src/reducers/search.ts +111 -0
  287. package/src/reducers/status.ts +40 -0
  288. package/src/redux/index.ts +18 -0
  289. package/src/redux/middleware/waitUntilAction.ts +64 -0
  290. package/src/routing/__tests__/history.spec.ts +49 -0
  291. package/src/routing/history.ts +17 -0
  292. package/src/types/diacritics.d.ts +1 -0
  293. package/src/types/global.d.ts +8 -0
  294. package/src/types/immutable.ts +49 -0
  295. package/src/types/redux.ts +827 -0
  296. package/src/types/tomlify-j0.4.d.ts +13 -0
  297. package/src/valueObjects/AssetProxy.ts +48 -0
  298. package/src/valueObjects/EditorComponent.js +38 -0
  299. package/src/valueObjects/Entry.ts +63 -0
@@ -0,0 +1,445 @@
1
+ import React from 'react';
2
+ import { MemoryRouter } from 'react-router-dom';
3
+ import { render, fireEvent } from '@testing-library/react';
4
+ import { fromJS } from 'immutable';
5
+ import configureStore from 'redux-mock-store';
6
+ import { Provider } from 'react-redux';
7
+
8
+ import ConnectedNestedCollection, {
9
+ NestedCollection,
10
+ getTreeData,
11
+ walk,
12
+ updateNode,
13
+ } from '../NestedCollection';
14
+
15
+ jest.mock('decap-cms-ui-default', () => {
16
+ const actual = jest.requireActual('decap-cms-ui-default');
17
+ return {
18
+ ...actual,
19
+ Icon: 'mocked-icon',
20
+ };
21
+ });
22
+
23
+ const middlewares = [];
24
+ const mockStore = configureStore(middlewares);
25
+
26
+ function renderWithRedux(component, { store } = {}) {
27
+ function Wrapper({ children }) {
28
+ return <Provider store={store}>{children}</Provider>;
29
+ }
30
+
31
+ return render(component, { wrapper: Wrapper });
32
+ }
33
+
34
+ describe('NestedCollection', () => {
35
+ const collection = fromJS({
36
+ name: 'pages',
37
+ label: 'Pages',
38
+ folder: 'src/pages',
39
+ fields: [{ name: 'title', widget: 'string' }],
40
+ nested: {
41
+ subfolders: true,
42
+ },
43
+ });
44
+
45
+ it('should render correctly with no entries', () => {
46
+ const entries = fromJS([]);
47
+ const { asFragment, getByTestId } = render(
48
+ <MemoryRouter>
49
+ <NestedCollection collection={collection} entries={entries} />
50
+ </MemoryRouter>,
51
+ );
52
+
53
+ expect(getByTestId('/')).toHaveTextContent('Pages');
54
+ expect(getByTestId('/')).toHaveAttribute('href', '/collections/pages');
55
+ expect(asFragment()).toMatchSnapshot();
56
+ });
57
+
58
+ it('should render correctly with nested entries', () => {
59
+ const entries = fromJS([
60
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
61
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
62
+ { path: 'src/pages/b/index.md', data: { title: 'File 2' } },
63
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 3' } },
64
+ { path: 'src/pages/b/a/index.md', data: { title: 'File 4' } },
65
+ ]);
66
+ const { asFragment, getByTestId } = render(
67
+ <MemoryRouter>
68
+ <NestedCollection collection={collection} entries={entries} />
69
+ </MemoryRouter>,
70
+ );
71
+
72
+ // expand the tree
73
+ fireEvent.click(getByTestId('/'));
74
+
75
+ expect(getByTestId('/a')).toHaveTextContent('File 1');
76
+ expect(getByTestId('/a')).toHaveAttribute('href', '/collections/pages/filter/a');
77
+
78
+ expect(getByTestId('/b')).toHaveTextContent('File 2');
79
+ expect(getByTestId('/b')).toHaveAttribute('href', '/collections/pages/filter/b');
80
+
81
+ expect(asFragment()).toMatchSnapshot();
82
+ });
83
+
84
+ it('should keep expanded nodes on re-render', () => {
85
+ const entries = fromJS([
86
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
87
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
88
+ { path: 'src/pages/b/index.md', data: { title: 'File 2' } },
89
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 3' } },
90
+ { path: 'src/pages/b/a/index.md', data: { title: 'File 4' } },
91
+ ]);
92
+ const { getByTestId, rerender } = render(
93
+ <MemoryRouter>
94
+ <NestedCollection collection={collection} entries={entries} />
95
+ </MemoryRouter>,
96
+ );
97
+
98
+ fireEvent.click(getByTestId('/'));
99
+ fireEvent.click(getByTestId('/a'));
100
+
101
+ expect(getByTestId('/a')).toHaveTextContent('File 1');
102
+
103
+ const newEntries = fromJS([
104
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
105
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
106
+ { path: 'src/pages/b/index.md', data: { title: 'File 2' } },
107
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 3' } },
108
+ { path: 'src/pages/b/a/index.md', data: { title: 'File 4' } },
109
+ { path: 'src/pages/c/index.md', data: { title: 'File 5' } },
110
+ { path: 'src/pages/c/a/index.md', data: { title: 'File 6' } },
111
+ ]);
112
+
113
+ rerender(
114
+ <MemoryRouter>
115
+ <NestedCollection collection={collection} entries={newEntries} />
116
+ </MemoryRouter>,
117
+ );
118
+
119
+ expect(getByTestId('/a')).toHaveTextContent('File 1');
120
+ });
121
+
122
+ it('should expand nodes based on filterTerm', () => {
123
+ const entries = fromJS([
124
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
125
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
126
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 2' } },
127
+ { path: 'src/pages/a/a/a/index.md', data: { title: 'File 3' } },
128
+ ]);
129
+
130
+ const { getByTestId, queryByTestId, rerender } = render(
131
+ <MemoryRouter>
132
+ <NestedCollection collection={collection} entries={entries} />
133
+ </MemoryRouter>,
134
+ );
135
+
136
+ expect(queryByTestId('/a/a')).toBeNull();
137
+
138
+ rerender(
139
+ <MemoryRouter>
140
+ <NestedCollection collection={collection} entries={entries} filterTerm={'a/a'} />
141
+ </MemoryRouter>,
142
+ );
143
+
144
+ expect(getByTestId('/a/a')).toHaveTextContent('File 2');
145
+ });
146
+
147
+ it('should ignore filterTerm once a user toggles an node', () => {
148
+ const entries = fromJS([
149
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
150
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
151
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 2' } },
152
+ { path: 'src/pages/a/a/a/index.md', data: { title: 'File 3' } },
153
+ ]);
154
+
155
+ const { getByTestId, queryByTestId, rerender } = render(
156
+ <MemoryRouter>
157
+ <NestedCollection collection={collection} entries={entries} />
158
+ </MemoryRouter>,
159
+ );
160
+
161
+ rerender(
162
+ <MemoryRouter>
163
+ <NestedCollection collection={collection} entries={entries} filterTerm={'a/a'} />
164
+ </MemoryRouter>,
165
+ );
166
+
167
+ expect(getByTestId('/a/a')).toHaveTextContent('File 2');
168
+
169
+ fireEvent.click(getByTestId('/a'));
170
+
171
+ rerender(
172
+ <MemoryRouter>
173
+ <NestedCollection
174
+ collection={collection}
175
+ entries={fromJS(entries.toJS())}
176
+ filterTerm={'a/a'}
177
+ />
178
+ </MemoryRouter>,
179
+ );
180
+
181
+ expect(queryByTestId('/a/a')).toBeNull();
182
+ });
183
+
184
+ it('should not collapse an unselected node when clicked', () => {
185
+ const entries = fromJS([
186
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
187
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
188
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 2' } },
189
+ { path: 'src/pages/a/a/a/index.md', data: { title: 'File 3' } },
190
+ { path: 'src/pages/a/a/a/a/index.md', data: { title: 'File 4' } },
191
+ ]);
192
+
193
+ const { getByTestId } = render(
194
+ <MemoryRouter>
195
+ <NestedCollection collection={collection} entries={entries} />
196
+ </MemoryRouter>,
197
+ );
198
+
199
+ fireEvent.click(getByTestId('/'));
200
+ fireEvent.click(getByTestId('/a'));
201
+ fireEvent.click(getByTestId('/a/a'));
202
+
203
+ expect(getByTestId('/a/a')).toHaveTextContent('File 2');
204
+ fireEvent.click(getByTestId('/a'));
205
+ expect(getByTestId('/a/a')).toHaveTextContent('File 2');
206
+ });
207
+
208
+ it('should collapse a selected node when clicked', () => {
209
+ const entries = fromJS([
210
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
211
+ { path: 'src/pages/a/index.md', data: { title: 'File 1' } },
212
+ { path: 'src/pages/a/a/index.md', data: { title: 'File 2' } },
213
+ { path: 'src/pages/a/a/a/index.md', data: { title: 'File 3' } },
214
+ { path: 'src/pages/a/a/a/a/index.md', data: { title: 'File 4' } },
215
+ ]);
216
+
217
+ const { getByTestId, queryByTestId } = render(
218
+ <MemoryRouter>
219
+ <NestedCollection collection={collection} entries={entries} />
220
+ </MemoryRouter>,
221
+ );
222
+
223
+ fireEvent.click(getByTestId('/'));
224
+ fireEvent.click(getByTestId('/a'));
225
+ fireEvent.click(getByTestId('/a/a'));
226
+
227
+ expect(getByTestId('/a/a/a')).toHaveTextContent('File 3');
228
+ fireEvent.click(getByTestId('/a/a'));
229
+ expect(queryByTestId('/a/a/a')).toBeNull();
230
+ });
231
+
232
+ it('should render connected component', () => {
233
+ const entriesArray = [
234
+ { slug: 'index', path: 'src/pages/index.md', data: { title: 'Root' } },
235
+ { slug: 'a/index', path: 'src/pages/a/index.md', data: { title: 'File 1' } },
236
+ { slug: 'b/index', path: 'src/pages/b/index.md', data: { title: 'File 2' } },
237
+ { slug: 'a/a/index', path: 'src/pages/a/a/index.md', data: { title: 'File 3' } },
238
+ { slug: 'b/a/index', path: 'src/pages/b/a/index.md', data: { title: 'File 4' } },
239
+ ];
240
+ const entries = entriesArray.reduce(
241
+ (acc, entry) => {
242
+ acc.entities[`${collection.get('name')}.${entry.slug}`] = entry;
243
+ acc.pages[collection.get('name')].ids.push(entry.slug);
244
+ return acc;
245
+ },
246
+ { pages: { [collection.get('name')]: { ids: [] } }, entities: {} },
247
+ );
248
+
249
+ const store = mockStore({ entries: fromJS(entries) });
250
+
251
+ const { asFragment, getByTestId } = renderWithRedux(
252
+ <MemoryRouter>
253
+ <ConnectedNestedCollection collection={collection} entries={entries} />
254
+ </MemoryRouter>,
255
+ { store },
256
+ );
257
+
258
+ // expand the root
259
+ fireEvent.click(getByTestId('/'));
260
+
261
+ expect(getByTestId('/a')).toHaveTextContent('File 1');
262
+ expect(getByTestId('/a')).toHaveAttribute('href', '/collections/pages/filter/a');
263
+
264
+ expect(getByTestId('/b')).toHaveTextContent('File 2');
265
+ expect(getByTestId('/b')).toHaveAttribute('href', '/collections/pages/filter/b');
266
+
267
+ expect(asFragment()).toMatchSnapshot();
268
+ });
269
+
270
+ describe('getTreeData', () => {
271
+ it('should return nested tree data from entries', () => {
272
+ const entries = fromJS([
273
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
274
+ { path: 'src/pages/intro/index.md', data: { title: 'intro index' } },
275
+ { path: 'src/pages/intro/category/index.md', data: { title: 'intro category index' } },
276
+ { path: 'src/pages/compliance/index.md', data: { title: 'compliance index' } },
277
+ ]);
278
+
279
+ const treeData = getTreeData(collection, entries);
280
+
281
+ expect(treeData).toEqual([
282
+ {
283
+ title: 'Pages',
284
+ path: '/',
285
+ isDir: true,
286
+ isRoot: true,
287
+ children: [
288
+ {
289
+ title: 'intro',
290
+ path: '/intro',
291
+ isDir: true,
292
+ isRoot: false,
293
+ children: [
294
+ {
295
+ title: 'category',
296
+ path: '/intro/category',
297
+ isDir: true,
298
+ isRoot: false,
299
+ children: [
300
+ {
301
+ path: '/intro/category/index.md',
302
+ data: { title: 'intro category index' },
303
+ title: 'intro category index',
304
+ isDir: false,
305
+ isRoot: false,
306
+ children: [],
307
+ },
308
+ ],
309
+ },
310
+ {
311
+ path: '/intro/index.md',
312
+ data: { title: 'intro index' },
313
+ title: 'intro index',
314
+ isDir: false,
315
+ isRoot: false,
316
+ children: [],
317
+ },
318
+ ],
319
+ },
320
+ {
321
+ title: 'compliance',
322
+ path: '/compliance',
323
+ isDir: true,
324
+ isRoot: false,
325
+ children: [
326
+ {
327
+ path: '/compliance/index.md',
328
+ data: { title: 'compliance index' },
329
+ title: 'compliance index',
330
+ isDir: false,
331
+ isRoot: false,
332
+ children: [],
333
+ },
334
+ ],
335
+ },
336
+ {
337
+ path: '/index.md',
338
+ data: { title: 'Root' },
339
+ title: 'Root',
340
+ isDir: false,
341
+ isRoot: false,
342
+ children: [],
343
+ },
344
+ ],
345
+ },
346
+ ]);
347
+ });
348
+
349
+ it('should ignore collection summary', () => {
350
+ const entries = fromJS([{ path: 'src/pages/index.md', data: { title: 'Root' } }]);
351
+
352
+ const treeData = getTreeData(collection, entries);
353
+
354
+ expect(treeData).toEqual([
355
+ {
356
+ title: 'Pages',
357
+ path: '/',
358
+ isDir: true,
359
+ isRoot: true,
360
+ children: [
361
+ {
362
+ path: '/index.md',
363
+ data: { title: 'Root' },
364
+ title: 'Root',
365
+ isDir: false,
366
+ isRoot: false,
367
+ children: [],
368
+ },
369
+ ],
370
+ },
371
+ ]);
372
+ });
373
+
374
+ it('should use nested collection summary for title', () => {
375
+ const entries = fromJS([{ path: 'src/pages/index.md', data: { title: 'Root' } }]);
376
+
377
+ const treeData = getTreeData(
378
+ collection.setIn(['nested', 'summary'], '{{filename}}'),
379
+ entries,
380
+ );
381
+
382
+ expect(treeData).toEqual([
383
+ {
384
+ title: 'Pages',
385
+ path: '/',
386
+ isDir: true,
387
+ isRoot: true,
388
+ children: [
389
+ {
390
+ path: '/index.md',
391
+ data: { title: 'Root' },
392
+ title: 'index',
393
+ isDir: false,
394
+ isRoot: false,
395
+ children: [],
396
+ },
397
+ ],
398
+ },
399
+ ]);
400
+ });
401
+ });
402
+
403
+ describe('walk', () => {
404
+ it('should visit every tree node', () => {
405
+ const entries = fromJS([
406
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
407
+ { path: 'src/pages/dir1/index.md', data: { title: 'Dir1 File' } },
408
+ { path: 'src/pages/dir2/index.md', data: { title: 'Dir2 File' } },
409
+ ]);
410
+
411
+ const treeData = getTreeData(collection, entries);
412
+ const callback = jest.fn();
413
+ walk(treeData, callback);
414
+
415
+ expect(callback).toHaveBeenCalledTimes(6);
416
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ path: '/' }));
417
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ path: '/index.md' }));
418
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ path: '/dir1' }));
419
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ path: '/dir2' }));
420
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ path: '/dir1/index.md' }));
421
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ path: '/dir2/index.md' }));
422
+ });
423
+ });
424
+
425
+ describe('updateNode', () => {
426
+ it('should update node', () => {
427
+ const entries = fromJS([
428
+ { path: 'src/pages/index.md', data: { title: 'Root' } },
429
+ { path: 'src/pages/dir1/index.md', data: { title: 'Dir1 File' } },
430
+ { path: 'src/pages/dir2/index.md', data: { title: 'Dir2 File' } },
431
+ ]);
432
+
433
+ const treeData = getTreeData(collection, entries);
434
+ expect(treeData[0].children[0].children[0].expanded).toBeUndefined();
435
+
436
+ const callback = jest.fn(node => ({ ...node, expanded: true }));
437
+ const node = { path: '/dir1/index.md' };
438
+ updateNode(treeData, node, callback);
439
+
440
+ expect(callback).toHaveBeenCalledTimes(1);
441
+ expect(callback).toHaveBeenCalledWith(node);
442
+ expect(treeData[0].children[0].children[0].expanded).toEqual(true);
443
+ });
444
+ });
445
+ });
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { MemoryRouter } from 'react-router-dom';
3
+ import { render } from '@testing-library/react';
4
+ import { fromJS } from 'immutable';
5
+
6
+ import { Sidebar } from '../Sidebar';
7
+
8
+ jest.mock('decap-cms-ui-default', () => {
9
+ const actual = jest.requireActual('decap-cms-ui-default');
10
+ return {
11
+ ...actual,
12
+ Icon: 'mocked-icon',
13
+ };
14
+ });
15
+
16
+ jest.mock('../NestedCollection', () => 'nested-collection');
17
+ jest.mock('../CollectionSearch', () => 'collection-search');
18
+ jest.mock('../../../actions/collections');
19
+
20
+ describe('Sidebar', () => {
21
+ const props = {
22
+ searchTerm: '',
23
+ isSearchEnabled: true,
24
+ t: jest.fn(key => key),
25
+ };
26
+ it('should render sidebar with a simple collection', () => {
27
+ const collections = fromJS([{ name: 'posts', label: 'Posts' }]).toOrderedMap();
28
+ const { asFragment, getByTestId } = render(
29
+ <MemoryRouter>
30
+ <Sidebar {...props} collections={collections} />
31
+ </MemoryRouter>,
32
+ );
33
+
34
+ expect(getByTestId('posts')).toHaveTextContent('Posts');
35
+ expect(getByTestId('posts')).toHaveAttribute('href', '/collections/posts');
36
+
37
+ expect(asFragment()).toMatchSnapshot();
38
+ });
39
+
40
+ it('should not render a hidden collection', () => {
41
+ const collections = fromJS([{ name: 'posts', label: 'Posts', hide: true }]).toOrderedMap();
42
+ const { queryByTestId } = render(
43
+ <MemoryRouter>
44
+ <Sidebar {...props} collections={collections} />
45
+ </MemoryRouter>,
46
+ );
47
+
48
+ expect(queryByTestId('posts')).toBeNull();
49
+ });
50
+
51
+ it('should render sidebar with a nested collection', () => {
52
+ const collections = fromJS([
53
+ { name: 'posts', label: 'Posts', nested: { depth: 10 } },
54
+ ]).toOrderedMap();
55
+ const { asFragment } = render(
56
+ <MemoryRouter>
57
+ <Sidebar {...props} collections={collections} />
58
+ </MemoryRouter>,
59
+ );
60
+
61
+ expect(asFragment()).toMatchSnapshot();
62
+ });
63
+
64
+ it('should render nested collection with filterTerm', () => {
65
+ const collections = fromJS([
66
+ { name: 'posts', label: 'Posts', nested: { depth: 10 } },
67
+ ]).toOrderedMap();
68
+ const { asFragment } = render(
69
+ <MemoryRouter>
70
+ <Sidebar {...props} collections={collections} filterTerm="dir1/dir2" />
71
+ </MemoryRouter>,
72
+ );
73
+
74
+ expect(asFragment()).toMatchSnapshot();
75
+ });
76
+
77
+ it('should render sidebar without search', () => {
78
+ const collections = fromJS([{ name: 'posts', label: 'Posts' }]).toOrderedMap();
79
+ const { asFragment } = render(
80
+ <MemoryRouter>
81
+ <Sidebar {...props} collections={collections} isSearchEnabled={false} />
82
+ </MemoryRouter>,
83
+ );
84
+
85
+ expect(asFragment()).toMatchSnapshot();
86
+ });
87
+ });
@@ -0,0 +1,144 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Collection should render connected component 1`] = `
4
+ <DocumentFragment>
5
+ .emotion-0 {
6
+ margin: 28px 18px;
7
+ }
8
+
9
+ .emotion-2 {
10
+ padding-left: 280px;
11
+ }
12
+
13
+ <div
14
+ class="emotion-0 emotion-1"
15
+ >
16
+ <mock-sidebar
17
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] }"
18
+ collections="OrderedMap { 0: Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] } }"
19
+ filterterm=""
20
+ searchterm=""
21
+ />
22
+ <main
23
+ class="emotion-2 emotion-3"
24
+ >
25
+ <mock-collection-top
26
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] }"
27
+ newentryurl=""
28
+ />
29
+ <mock-collection-controls
30
+ filter="Map {}"
31
+ group="Map {}"
32
+ sortablefields=""
33
+ viewfilters=""
34
+ viewgroups=""
35
+ />
36
+ <mock-entries-collection
37
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] }"
38
+ filterterm=""
39
+ />
40
+ </main>
41
+ </div>
42
+ </DocumentFragment>
43
+ `;
44
+
45
+ exports[`Collection should render with collection with create url 1`] = `
46
+ <DocumentFragment>
47
+ .emotion-0 {
48
+ margin: 28px 18px;
49
+ }
50
+
51
+ .emotion-2 {
52
+ padding-left: 280px;
53
+ }
54
+
55
+ <div
56
+ class="emotion-0 emotion-1"
57
+ >
58
+ <mock-sidebar
59
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": true }"
60
+ collections="OrderedMap { 0: Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] } }"
61
+ />
62
+ <main
63
+ class="emotion-2 emotion-3"
64
+ >
65
+ <mock-collection-top
66
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": true }"
67
+ newentryurl="/collections/pages/new"
68
+ />
69
+ <mock-collection-controls />
70
+ <mock-entries-collection
71
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": true }"
72
+ />
73
+ </main>
74
+ </div>
75
+ </DocumentFragment>
76
+ `;
77
+
78
+ exports[`Collection should render with collection with create url and path 1`] = `
79
+ <DocumentFragment>
80
+ .emotion-0 {
81
+ margin: 28px 18px;
82
+ }
83
+
84
+ .emotion-2 {
85
+ padding-left: 280px;
86
+ }
87
+
88
+ <div
89
+ class="emotion-0 emotion-1"
90
+ >
91
+ <mock-sidebar
92
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": true }"
93
+ collections="OrderedMap { 0: Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] } }"
94
+ filterterm="dir1/dir2"
95
+ />
96
+ <main
97
+ class="emotion-2 emotion-3"
98
+ >
99
+ <mock-collection-top
100
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": true }"
101
+ newentryurl="/collections/pages/new?path=dir1/dir2"
102
+ />
103
+ <mock-collection-controls />
104
+ <mock-entries-collection
105
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": true }"
106
+ filterterm="dir1/dir2"
107
+ />
108
+ </main>
109
+ </div>
110
+ </DocumentFragment>
111
+ `;
112
+
113
+ exports[`Collection should render with collection without create url 1`] = `
114
+ <DocumentFragment>
115
+ .emotion-0 {
116
+ margin: 28px 18px;
117
+ }
118
+
119
+ .emotion-2 {
120
+ padding-left: 280px;
121
+ }
122
+
123
+ <div
124
+ class="emotion-0 emotion-1"
125
+ >
126
+ <mock-sidebar
127
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": false }"
128
+ collections="OrderedMap { 0: Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [] } }"
129
+ />
130
+ <main
131
+ class="emotion-2 emotion-3"
132
+ >
133
+ <mock-collection-top
134
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": false }"
135
+ newentryurl=""
136
+ />
137
+ <mock-collection-controls />
138
+ <mock-entries-collection
139
+ collection="Map { \\"name\\": \\"pages\\", \\"sortable_fields\\": List [], \\"view_filters\\": List [], \\"view_groups\\": List [], \\"create\\": false }"
140
+ />
141
+ </main>
142
+ </div>
143
+ </DocumentFragment>
144
+ `;