@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.
- package/README.md +9 -0
- package/dist/@pranaysahith/decap-cms-core.js +52 -0
- package/dist/@pranaysahith/decap-cms-core.js.LICENSE.txt +141 -0
- package/dist/@pranaysahith/decap-cms-core.js.map +1 -0
- package/dist/decap-cms-core.js +47 -0
- package/dist/decap-cms-core.js.LICENSE.txt +116 -0
- package/dist/decap-cms-core.js.map +1 -0
- package/dist/esm/actions/auth.js +97 -0
- package/dist/esm/actions/collections.js +15 -0
- package/dist/esm/actions/config.js +493 -0
- package/dist/esm/actions/deploys.js +79 -0
- package/dist/esm/actions/editorialWorkflow.js +480 -0
- package/dist/esm/actions/entries.js +865 -0
- package/dist/esm/actions/media.js +147 -0
- package/dist/esm/actions/mediaLibrary.js +552 -0
- package/dist/esm/actions/notifications.js +21 -0
- package/dist/esm/actions/search.js +149 -0
- package/dist/esm/actions/status.js +74 -0
- package/dist/esm/actions/waitUntil.js +32 -0
- package/dist/esm/backend.js +1082 -0
- package/dist/esm/bootstrap.js +101 -0
- package/dist/esm/components/App/App.js +289 -0
- package/dist/esm/components/App/Header.js +172 -0
- package/dist/esm/components/App/NotFoundPage.js +19 -0
- package/dist/esm/components/Collection/Collection.js +198 -0
- package/dist/esm/components/Collection/CollectionControls.js +46 -0
- package/dist/esm/components/Collection/CollectionSearch.js +222 -0
- package/dist/esm/components/Collection/CollectionTop.js +68 -0
- package/dist/esm/components/Collection/ControlButton.js +17 -0
- package/dist/esm/components/Collection/Entries/Entries.js +73 -0
- package/dist/esm/components/Collection/Entries/EntriesCollection.js +241 -0
- package/dist/esm/components/Collection/Entries/EntriesSearch.js +113 -0
- package/dist/esm/components/Collection/Entries/EntryCard.js +177 -0
- package/dist/esm/components/Collection/Entries/EntryListing.js +143 -0
- package/dist/esm/components/Collection/FilterControl.js +33 -0
- package/dist/esm/components/Collection/FolderRenameControl.js +403 -0
- package/dist/esm/components/Collection/GroupControl.js +33 -0
- package/dist/esm/components/Collection/NestedCollection.js +308 -0
- package/dist/esm/components/Collection/Sidebar.js +91 -0
- package/dist/esm/components/Collection/SortControl.js +59 -0
- package/dist/esm/components/Collection/ViewStyleControl.js +38 -0
- package/dist/esm/components/Editor/Editor.js +466 -0
- package/dist/esm/components/Editor/EditorControlPane/EditorControl.js +395 -0
- package/dist/esm/components/Editor/EditorControlPane/EditorControlPane.js +254 -0
- package/dist/esm/components/Editor/EditorControlPane/Widget.js +374 -0
- package/dist/esm/components/Editor/EditorInterface.js +386 -0
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreview.js +47 -0
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewContent.js +66 -0
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewPane.js +288 -0
- package/dist/esm/components/Editor/EditorPreviewPane/PreviewHOC.js +27 -0
- package/dist/esm/components/Editor/EditorToolbar.js +536 -0
- package/dist/esm/components/Editor/EntryPathEditor.js +272 -0
- package/dist/esm/components/Editor/withWorkflow.js +56 -0
- package/dist/esm/components/EditorWidgets/Unknown/UnknownControl.js +18 -0
- package/dist/esm/components/EditorWidgets/Unknown/UnknownPreview.js +20 -0
- package/dist/esm/components/EditorWidgets/index.js +4 -0
- package/dist/esm/components/MediaLibrary/EmptyMessage.js +22 -0
- package/dist/esm/components/MediaLibrary/MediaLibrary.js +446 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryButtons.js +93 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryCard.js +99 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryCardGrid.js +198 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryHeader.js +32 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryModal.js +156 -0
- package/dist/esm/components/MediaLibrary/MediaLibrarySearch.js +51 -0
- package/dist/esm/components/MediaLibrary/MediaLibraryTop.js +123 -0
- package/dist/esm/components/UI/DragDrop.js +67 -0
- package/dist/esm/components/UI/ErrorBoundary.js +173 -0
- package/dist/esm/components/UI/FileUploadButton.js +27 -0
- package/dist/esm/components/UI/Modal.js +104 -0
- package/dist/esm/components/UI/Notifications.js +62 -0
- package/dist/esm/components/UI/SettingsDropdown.js +107 -0
- package/dist/esm/components/UI/index.js +6 -0
- package/dist/esm/components/Workflow/Workflow.js +133 -0
- package/dist/esm/components/Workflow/WorkflowCard.js +128 -0
- package/dist/esm/components/Workflow/WorkflowList.js +204 -0
- package/dist/esm/constants/collectionTypes.js +2 -0
- package/dist/esm/constants/collectionViews.js +2 -0
- package/dist/esm/constants/commitProps.js +2 -0
- package/dist/esm/constants/configSchema.js +644 -0
- package/dist/esm/constants/fieldInference.js +57 -0
- package/dist/esm/constants/publishModes.js +18 -0
- package/dist/esm/constants/validationErrorTypes.js +6 -0
- package/dist/esm/formats/formats.js +83 -0
- package/dist/esm/formats/frontmatter.js +146 -0
- package/dist/esm/formats/helpers.js +12 -0
- package/dist/esm/formats/json.js +8 -0
- package/dist/esm/formats/toml.js +32 -0
- package/dist/esm/formats/yaml.js +51 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/integrations/index.js +28 -0
- package/dist/esm/integrations/providers/algolia/implementation.js +174 -0
- package/dist/esm/integrations/providers/assetStore/implementation.js +165 -0
- package/dist/esm/lib/consoleError.js +3 -0
- package/dist/esm/lib/formatters.js +191 -0
- package/dist/esm/lib/i18n.js +367 -0
- package/dist/esm/lib/phrases.js +6 -0
- package/dist/esm/lib/polyfill.js +8 -0
- package/dist/esm/lib/registry.js +329 -0
- package/dist/esm/lib/serializeEntryValues.js +67 -0
- package/dist/esm/lib/stega.js +142 -0
- package/dist/esm/lib/textHelper.js +9 -0
- package/dist/esm/lib/urlHelper.js +111 -0
- package/dist/esm/mediaLibrary.js +37 -0
- package/dist/esm/reducers/auth.js +27 -0
- package/dist/esm/reducers/collections.js +428 -0
- package/dist/esm/reducers/combinedReducer.js +8 -0
- package/dist/esm/reducers/config.js +29 -0
- package/dist/esm/reducers/cursors.js +31 -0
- package/dist/esm/reducers/deploys.js +45 -0
- package/dist/esm/reducers/editorialWorkflow.js +83 -0
- package/dist/esm/reducers/entries.js +568 -0
- package/dist/esm/reducers/entryDraft.js +212 -0
- package/dist/esm/reducers/globalUI.js +25 -0
- package/dist/esm/reducers/index.js +66 -0
- package/dist/esm/reducers/integrations.js +53 -0
- package/dist/esm/reducers/mediaLibrary.js +252 -0
- package/dist/esm/reducers/medias.js +68 -0
- package/dist/esm/reducers/notifications.js +23 -0
- package/dist/esm/reducers/search.js +92 -0
- package/dist/esm/reducers/status.js +30 -0
- package/dist/esm/redux/index.js +7 -0
- package/dist/esm/redux/middleware/waitUntilAction.js +48 -0
- package/dist/esm/routing/history.js +12 -0
- package/dist/esm/types/diacritics.d.js +0 -0
- package/dist/esm/types/global.d.js +1 -0
- package/dist/esm/types/immutable.js +7 -0
- package/dist/esm/types/redux.js +14 -0
- package/dist/esm/types/tomlify-j0.4.d.js +0 -0
- package/dist/esm/valueObjects/AssetProxy.js +44 -0
- package/dist/esm/valueObjects/EditorComponent.js +34 -0
- package/dist/esm/valueObjects/Entry.js +20 -0
- package/index.d.ts +618 -0
- package/package.json +106 -0
- package/src/__tests__/backend.spec.js +1161 -0
- package/src/actions/__tests__/config.spec.js +1009 -0
- package/src/actions/__tests__/editorialWorkflow.spec.js +216 -0
- package/src/actions/__tests__/entries.spec.js +596 -0
- package/src/actions/__tests__/media.spec.ts +171 -0
- package/src/actions/__tests__/mediaLibrary.spec.js +327 -0
- package/src/actions/__tests__/search.spec.js +209 -0
- package/src/actions/auth.ts +127 -0
- package/src/actions/collections.ts +18 -0
- package/src/actions/config.ts +565 -0
- package/src/actions/deploys.ts +104 -0
- package/src/actions/editorialWorkflow.ts +567 -0
- package/src/actions/entries.ts +1055 -0
- package/src/actions/media.ts +139 -0
- package/src/actions/mediaLibrary.ts +574 -0
- package/src/actions/notifications.ts +36 -0
- package/src/actions/search.ts +221 -0
- package/src/actions/status.ts +99 -0
- package/src/actions/waitUntil.ts +49 -0
- package/src/backend.ts +1400 -0
- package/src/bootstrap.js +104 -0
- package/src/components/App/App.js +286 -0
- package/src/components/App/Header.js +266 -0
- package/src/components/App/NotFoundPage.js +23 -0
- package/src/components/Collection/Collection.js +210 -0
- package/src/components/Collection/CollectionControls.js +58 -0
- package/src/components/Collection/CollectionSearch.js +243 -0
- package/src/components/Collection/CollectionTop.js +81 -0
- package/src/components/Collection/ControlButton.js +27 -0
- package/src/components/Collection/Entries/Entries.js +82 -0
- package/src/components/Collection/Entries/EntriesCollection.js +277 -0
- package/src/components/Collection/Entries/EntriesSearch.js +102 -0
- package/src/components/Collection/Entries/EntryCard.js +246 -0
- package/src/components/Collection/Entries/EntryListing.js +151 -0
- package/src/components/Collection/Entries/__tests__/EntriesCollection.spec.js +163 -0
- package/src/components/Collection/Entries/__tests__/__snapshots__/EntriesCollection.spec.js.snap +46 -0
- package/src/components/Collection/FilterControl.js +39 -0
- package/src/components/Collection/GroupControl.js +39 -0
- package/src/components/Collection/NestedCollection.js +330 -0
- package/src/components/Collection/Sidebar.js +136 -0
- package/src/components/Collection/SortControl.js +68 -0
- package/src/components/Collection/ViewStyleControl.js +50 -0
- package/src/components/Collection/__tests__/Collection.spec.js +75 -0
- package/src/components/Collection/__tests__/NestedCollection.spec.js +445 -0
- package/src/components/Collection/__tests__/Sidebar.spec.js +87 -0
- package/src/components/Collection/__tests__/__snapshots__/Collection.spec.js.snap +144 -0
- package/src/components/Collection/__tests__/__snapshots__/NestedCollection.spec.js.snap +550 -0
- package/src/components/Collection/__tests__/__snapshots__/Sidebar.spec.js.snap +312 -0
- package/src/components/Editor/Editor.js +497 -0
- package/src/components/Editor/EditorControlPane/EditorControl.js +452 -0
- package/src/components/Editor/EditorControlPane/EditorControlPane.js +269 -0
- package/src/components/Editor/EditorControlPane/Widget.js +384 -0
- package/src/components/Editor/EditorInterface.js +444 -0
- package/src/components/Editor/EditorPreviewPane/EditorPreview.js +40 -0
- package/src/components/Editor/EditorPreviewPane/EditorPreviewContent.js +74 -0
- package/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +333 -0
- package/src/components/Editor/EditorPreviewPane/PreviewHOC.js +33 -0
- package/src/components/Editor/EditorToolbar.js +691 -0
- package/src/components/Editor/__tests__/Editor.spec.js +221 -0
- package/src/components/Editor/__tests__/EditorToolbar.spec.js +120 -0
- package/src/components/Editor/__tests__/__snapshots__/Editor.spec.js.snap +45 -0
- package/src/components/Editor/__tests__/__snapshots__/EditorToolbar.spec.js.snap +4233 -0
- package/src/components/Editor/withWorkflow.js +61 -0
- package/src/components/EditorWidgets/Unknown/UnknownControl.js +17 -0
- package/src/components/EditorWidgets/Unknown/UnknownPreview.js +19 -0
- package/src/components/EditorWidgets/index.js +5 -0
- package/src/components/MediaLibrary/EmptyMessage.js +28 -0
- package/src/components/MediaLibrary/MediaLibrary.js +411 -0
- package/src/components/MediaLibrary/MediaLibraryButtons.js +136 -0
- package/src/components/MediaLibrary/MediaLibraryCard.js +128 -0
- package/src/components/MediaLibrary/MediaLibraryCardGrid.js +199 -0
- package/src/components/MediaLibrary/MediaLibraryHeader.js +48 -0
- package/src/components/MediaLibrary/MediaLibraryModal.js +200 -0
- package/src/components/MediaLibrary/MediaLibrarySearch.js +61 -0
- package/src/components/MediaLibrary/MediaLibraryTop.js +143 -0
- package/src/components/MediaLibrary/__tests__/MediaLibraryButtons.spec.js +45 -0
- package/src/components/MediaLibrary/__tests__/MediaLibraryCard.spec.js +49 -0
- package/src/components/MediaLibrary/__tests__/__snapshots__/MediaLibraryCard.spec.js.snap +264 -0
- package/src/components/UI/DragDrop.js +66 -0
- package/src/components/UI/ErrorBoundary.js +214 -0
- package/src/components/UI/FileUploadButton.js +24 -0
- package/src/components/UI/Modal.js +112 -0
- package/src/components/UI/Notifications.tsx +83 -0
- package/src/components/UI/SettingsDropdown.js +103 -0
- package/src/components/UI/__tests__/ErrorBoundary.spec.js +57 -0
- package/src/components/UI/index.js +6 -0
- package/src/components/Workflow/Workflow.js +169 -0
- package/src/components/Workflow/WorkflowCard.js +177 -0
- package/src/components/Workflow/WorkflowList.js +272 -0
- package/src/constants/__tests__/configSchema.spec.js +611 -0
- package/src/constants/collectionTypes.ts +2 -0
- package/src/constants/collectionViews.js +2 -0
- package/src/constants/commitProps.ts +2 -0
- package/src/constants/configSchema.js +441 -0
- package/src/constants/fieldInference.tsx +78 -0
- package/src/constants/publishModes.ts +22 -0
- package/src/constants/validationErrorTypes.js +6 -0
- package/src/formats/__tests__/formats.spec.js +87 -0
- package/src/formats/__tests__/frontmatter.spec.js +429 -0
- package/src/formats/__tests__/toml.spec.js +9 -0
- package/src/formats/__tests__/yaml.spec.js +162 -0
- package/src/formats/formats.ts +97 -0
- package/src/formats/frontmatter.ts +150 -0
- package/src/formats/helpers.ts +14 -0
- package/src/formats/json.ts +9 -0
- package/src/formats/toml.ts +33 -0
- package/src/formats/yaml.ts +58 -0
- package/src/index.js +8 -0
- package/src/integrations/index.js +35 -0
- package/src/integrations/providers/algolia/implementation.js +176 -0
- package/src/integrations/providers/assetStore/implementation.js +148 -0
- package/src/lib/__tests__/formatters.spec.js +751 -0
- package/src/lib/__tests__/i18n.spec.js +792 -0
- package/src/lib/__tests__/phrases.spec.js +119 -0
- package/src/lib/__tests__/registry.spec.js +261 -0
- package/src/lib/__tests__/serializeEntryValues.spec.js +22 -0
- package/src/lib/__tests__/urlHelper.spec.js +138 -0
- package/src/lib/consoleError.js +7 -0
- package/src/lib/formatters.ts +286 -0
- package/src/lib/i18n.ts +454 -0
- package/src/lib/phrases.js +8 -0
- package/src/lib/polyfill.js +9 -0
- package/src/lib/registry.js +312 -0
- package/src/lib/serializeEntryValues.js +75 -0
- package/src/lib/stega.ts +145 -0
- package/src/lib/textHelper.js +11 -0
- package/src/lib/urlHelper.ts +128 -0
- package/src/mediaLibrary.ts +51 -0
- package/src/reducers/__tests__/auth.spec.ts +38 -0
- package/src/reducers/__tests__/collections.spec.js +610 -0
- package/src/reducers/__tests__/config.spec.js +38 -0
- package/src/reducers/__tests__/entries.spec.js +694 -0
- package/src/reducers/__tests__/entryDraft.spec.js +297 -0
- package/src/reducers/__tests__/globalUI.js +43 -0
- package/src/reducers/__tests__/integrations.spec.ts +76 -0
- package/src/reducers/__tests__/mediaLibrary.spec.js +154 -0
- package/src/reducers/__tests__/medias.spec.ts +49 -0
- package/src/reducers/auth.ts +46 -0
- package/src/reducers/collections.ts +535 -0
- package/src/reducers/combinedReducer.ts +11 -0
- package/src/reducers/config.ts +38 -0
- package/src/reducers/cursors.js +36 -0
- package/src/reducers/deploys.ts +52 -0
- package/src/reducers/editorialWorkflow.ts +163 -0
- package/src/reducers/entries.ts +819 -0
- package/src/reducers/entryDraft.js +260 -0
- package/src/reducers/globalUI.ts +45 -0
- package/src/reducers/index.ts +82 -0
- package/src/reducers/integrations.ts +59 -0
- package/src/reducers/mediaLibrary.ts +296 -0
- package/src/reducers/medias.ts +66 -0
- package/src/reducers/notifications.ts +52 -0
- package/src/reducers/search.ts +111 -0
- package/src/reducers/status.ts +40 -0
- package/src/redux/index.ts +18 -0
- package/src/redux/middleware/waitUntilAction.ts +64 -0
- package/src/routing/__tests__/history.spec.ts +49 -0
- package/src/routing/history.ts +17 -0
- package/src/types/diacritics.d.ts +1 -0
- package/src/types/global.d.ts +8 -0
- package/src/types/immutable.ts +49 -0
- package/src/types/redux.ts +827 -0
- package/src/types/tomlify-j0.4.d.ts +13 -0
- package/src/valueObjects/AssetProxy.ts +48 -0
- package/src/valueObjects/EditorComponent.js +38 -0
- package/src/valueObjects/Entry.ts +63 -0
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
import merge from 'lodash/merge';
|
|
2
|
+
|
|
3
|
+
import { validateConfig } from '../configSchema';
|
|
4
|
+
|
|
5
|
+
jest.mock('../../lib/registry');
|
|
6
|
+
|
|
7
|
+
describe('config', () => {
|
|
8
|
+
/**
|
|
9
|
+
* Suppress error logging to reduce noise during testing. Jest will still
|
|
10
|
+
* log test failures and associated errors as expected.
|
|
11
|
+
*/
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const { getWidgets } = require('../../lib/registry');
|
|
17
|
+
getWidgets.mockImplementation(() => [{}]);
|
|
18
|
+
|
|
19
|
+
describe('validateConfig', () => {
|
|
20
|
+
const validConfig = {
|
|
21
|
+
foo: 'bar',
|
|
22
|
+
backend: { name: 'bar' },
|
|
23
|
+
media_folder: 'baz',
|
|
24
|
+
collections: [
|
|
25
|
+
{
|
|
26
|
+
name: 'posts',
|
|
27
|
+
label: 'Posts',
|
|
28
|
+
folder: '_posts',
|
|
29
|
+
fields: [{ name: 'title', label: 'title', widget: 'string' }],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
it('should not throw if no errors', () => {
|
|
35
|
+
expect(() => {
|
|
36
|
+
validateConfig(validConfig);
|
|
37
|
+
}).not.toThrowError();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should throw if backend is not defined in config', () => {
|
|
41
|
+
expect(() => {
|
|
42
|
+
validateConfig({ foo: 'bar' });
|
|
43
|
+
}).toThrowError("config must have required property 'backend'");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should throw if backend name is not defined in config', () => {
|
|
47
|
+
expect(() => {
|
|
48
|
+
validateConfig({ foo: 'bar', backend: {} });
|
|
49
|
+
}).toThrowError("'backend' must have required property 'name'");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should throw if backend name is not a string in config', () => {
|
|
53
|
+
expect(() => {
|
|
54
|
+
validateConfig({ foo: 'bar', backend: { name: {} } });
|
|
55
|
+
}).toThrowError("'backend.name' must be string");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should throw if backend.open_authoring is not a boolean in config', () => {
|
|
59
|
+
expect(() => {
|
|
60
|
+
validateConfig(merge(validConfig, { backend: { open_authoring: 'true' } }));
|
|
61
|
+
}).toThrowError("'backend.open_authoring' must be boolean");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should not throw if backend.open_authoring is boolean in config', () => {
|
|
65
|
+
expect(() => {
|
|
66
|
+
validateConfig(merge(validConfig, { backend: { open_authoring: true } }));
|
|
67
|
+
}).not.toThrowError();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should throw if backend.auth_scope is not "repo" or "public_repo" in config', () => {
|
|
71
|
+
expect(() => {
|
|
72
|
+
validateConfig(merge(validConfig, { backend: { auth_scope: 'user' } }));
|
|
73
|
+
}).toThrowError("'backend.auth_scope' must be equal to one of the allowed values");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should not throw if backend.auth_scope is one of "repo" or "public_repo" in config', () => {
|
|
77
|
+
expect(() => {
|
|
78
|
+
validateConfig(merge(validConfig, { backend: { auth_scope: 'repo' } }));
|
|
79
|
+
}).not.toThrowError();
|
|
80
|
+
expect(() => {
|
|
81
|
+
validateConfig(merge(validConfig, { backend: { auth_scope: 'public_repo' } }));
|
|
82
|
+
}).not.toThrowError();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should throw if media_folder is not defined in config', () => {
|
|
86
|
+
expect(() => {
|
|
87
|
+
validateConfig({ foo: 'bar', backend: { name: 'bar' } });
|
|
88
|
+
}).toThrowError("config must have required property 'media_folder'");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should throw if media_folder is not a string in config', () => {
|
|
92
|
+
expect(() => {
|
|
93
|
+
validateConfig({ foo: 'bar', backend: { name: 'bar' }, media_folder: {} });
|
|
94
|
+
}).toThrowError("'media_folder' must be string");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should throw if collections is not defined in config', () => {
|
|
98
|
+
expect(() => {
|
|
99
|
+
validateConfig({ foo: 'bar', backend: { name: 'bar' }, media_folder: 'baz' });
|
|
100
|
+
}).toThrowError("config must have required property 'collections'");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should throw if collections not an array in config', () => {
|
|
104
|
+
expect(() => {
|
|
105
|
+
validateConfig({
|
|
106
|
+
foo: 'bar',
|
|
107
|
+
backend: { name: 'bar' },
|
|
108
|
+
media_folder: 'baz',
|
|
109
|
+
collections: {},
|
|
110
|
+
});
|
|
111
|
+
}).toThrowError("'collections' must be array");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should throw if collections is an empty array in config', () => {
|
|
115
|
+
expect(() => {
|
|
116
|
+
validateConfig({
|
|
117
|
+
foo: 'bar',
|
|
118
|
+
backend: { name: 'bar' },
|
|
119
|
+
media_folder: 'baz',
|
|
120
|
+
collections: [],
|
|
121
|
+
});
|
|
122
|
+
}).toThrowError("'collections' must NOT have fewer than 1 items");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should throw if collections is an array with a single null element in config', () => {
|
|
126
|
+
expect(() => {
|
|
127
|
+
validateConfig({
|
|
128
|
+
foo: 'bar',
|
|
129
|
+
backend: { name: 'bar' },
|
|
130
|
+
media_folder: 'baz',
|
|
131
|
+
collections: [null],
|
|
132
|
+
});
|
|
133
|
+
}).toThrowError("'collections[0]' must be object");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should throw if local_backend is not a boolean or plain object', () => {
|
|
137
|
+
expect(() => {
|
|
138
|
+
validateConfig({ ...validConfig, local_backend: [] });
|
|
139
|
+
}).toThrowError("'local_backend' must be boolean");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should throw if local_backend url is not a string', () => {
|
|
143
|
+
expect(() => {
|
|
144
|
+
validateConfig({ ...validConfig, local_backend: { url: [] } });
|
|
145
|
+
}).toThrowError("'local_backend.url' must be string");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should throw if local_backend allowed_hosts is not a string array', () => {
|
|
149
|
+
expect(() => {
|
|
150
|
+
validateConfig({ ...validConfig, local_backend: { allowed_hosts: [true] } });
|
|
151
|
+
}).toThrowError("'local_backend.allowed_hosts[0]' must be string");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should not throw if local_backend is a boolean', () => {
|
|
155
|
+
expect(() => {
|
|
156
|
+
validateConfig({ ...validConfig, local_backend: true });
|
|
157
|
+
}).not.toThrowError();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should not throw if local_backend is a plain object with url string property', () => {
|
|
161
|
+
expect(() => {
|
|
162
|
+
validateConfig({ ...validConfig, local_backend: { url: 'http://localhost:8081/api/v1' } });
|
|
163
|
+
}).not.toThrowError();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should not throw if local_backend is a plain object with allowed_hosts string array property', () => {
|
|
167
|
+
expect(() => {
|
|
168
|
+
validateConfig({
|
|
169
|
+
...validConfig,
|
|
170
|
+
local_backend: { allowed_hosts: ['192.168.0.1'] },
|
|
171
|
+
});
|
|
172
|
+
}).not.toThrowError();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should throw if collection publish is not a boolean', () => {
|
|
176
|
+
expect(() => {
|
|
177
|
+
validateConfig(merge({}, validConfig, { collections: [{ publish: 'false' }] }));
|
|
178
|
+
}).toThrowError("'collections[0].publish' must be boolean");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should not throw if collection publish is a boolean', () => {
|
|
182
|
+
expect(() => {
|
|
183
|
+
validateConfig(merge({}, validConfig, { collections: [{ publish: false }] }));
|
|
184
|
+
}).not.toThrowError();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should throw if collections sortable_fields is not a boolean or a string array', () => {
|
|
188
|
+
expect(() => {
|
|
189
|
+
validateConfig(merge({}, validConfig, { collections: [{ sortable_fields: 'title' }] }));
|
|
190
|
+
}).toThrowError("'collections[0].sortable_fields' must be array");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should allow sortable_fields to be a string array', () => {
|
|
194
|
+
expect(() => {
|
|
195
|
+
validateConfig(merge({}, validConfig, { collections: [{ sortable_fields: ['title'] }] }));
|
|
196
|
+
}).not.toThrow();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should allow sortable_fields to be a an empty array', () => {
|
|
200
|
+
expect(() => {
|
|
201
|
+
validateConfig(merge({}, validConfig, { collections: [{ sortable_fields: [] }] }));
|
|
202
|
+
}).not.toThrow();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should allow sortableFields instead of sortable_fields', () => {
|
|
206
|
+
expect(() => {
|
|
207
|
+
validateConfig(merge({}, validConfig, { collections: [{ sortableFields: [] }] }));
|
|
208
|
+
}).not.toThrow();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should throw if both sortable_fields and sortableFields exist', () => {
|
|
212
|
+
expect(() => {
|
|
213
|
+
validateConfig(
|
|
214
|
+
merge({}, validConfig, { collections: [{ sortable_fields: [], sortableFields: [] }] }),
|
|
215
|
+
);
|
|
216
|
+
}).toThrowError("'collections[0]' must NOT be valid");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should allow sortable_fields to have object format with field property', () => {
|
|
220
|
+
expect(() => {
|
|
221
|
+
validateConfig(
|
|
222
|
+
merge({}, validConfig, {
|
|
223
|
+
collections: [{ sortable_fields: [{ field: 'title' }] }],
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
226
|
+
}).not.toThrow();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should allow sortable_fields with default_sort as boolean', () => {
|
|
230
|
+
expect(() => {
|
|
231
|
+
validateConfig(
|
|
232
|
+
merge({}, validConfig, {
|
|
233
|
+
collections: [{ sortable_fields: [{ field: 'title', default_sort: true }] }],
|
|
234
|
+
}),
|
|
235
|
+
);
|
|
236
|
+
}).not.toThrow();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should allow sortable_fields with default_sort as asc/desc', () => {
|
|
240
|
+
expect(() => {
|
|
241
|
+
validateConfig(
|
|
242
|
+
merge({}, validConfig, {
|
|
243
|
+
collections: [{ sortable_fields: ['title', { field: 'date', default_sort: 'desc' }] }],
|
|
244
|
+
}),
|
|
245
|
+
);
|
|
246
|
+
}).not.toThrow();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should allow sortable_fields with custom label', () => {
|
|
250
|
+
expect(() => {
|
|
251
|
+
validateConfig(
|
|
252
|
+
merge({}, validConfig, {
|
|
253
|
+
collections: [{ sortable_fields: [{ field: 'date', label: 'Publish Date' }] }],
|
|
254
|
+
}),
|
|
255
|
+
);
|
|
256
|
+
}).not.toThrow();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should allow sortable_fields with label and default_sort', () => {
|
|
260
|
+
expect(() => {
|
|
261
|
+
validateConfig(
|
|
262
|
+
merge({}, validConfig, {
|
|
263
|
+
collections: [
|
|
264
|
+
{
|
|
265
|
+
sortable_fields: [
|
|
266
|
+
'title',
|
|
267
|
+
{ field: 'date', label: 'Publish Date', default_sort: 'desc' },
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
}).not.toThrow();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should allow mixed string and object format in sortable_fields', () => {
|
|
277
|
+
expect(() => {
|
|
278
|
+
validateConfig(
|
|
279
|
+
merge({}, validConfig, {
|
|
280
|
+
collections: [{ sortable_fields: ['title', { field: 'date', default_sort: true }] }],
|
|
281
|
+
}),
|
|
282
|
+
);
|
|
283
|
+
}).not.toThrow();
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('should throw if more than one sortable field has default_sort property', () => {
|
|
287
|
+
expect(() => {
|
|
288
|
+
validateConfig(
|
|
289
|
+
merge({}, validConfig, {
|
|
290
|
+
collections: [
|
|
291
|
+
{
|
|
292
|
+
sortable_fields: [
|
|
293
|
+
{ field: 'title', default_sort: true },
|
|
294
|
+
{ field: 'date', default_sort: true },
|
|
295
|
+
],
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
}),
|
|
299
|
+
);
|
|
300
|
+
}).toThrowError('only one sortable field can have the default_sort property');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should throw if collection names are not unique', () => {
|
|
304
|
+
expect(() => {
|
|
305
|
+
validateConfig(
|
|
306
|
+
merge({}, validConfig, {
|
|
307
|
+
collections: [validConfig.collections[0], validConfig.collections[0]],
|
|
308
|
+
}),
|
|
309
|
+
);
|
|
310
|
+
}).toThrowError("'collections' collections names must be unique");
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should throw if collection file names are not unique', () => {
|
|
314
|
+
expect(() => {
|
|
315
|
+
validateConfig(
|
|
316
|
+
merge({}, validConfig, {
|
|
317
|
+
collections: [
|
|
318
|
+
{},
|
|
319
|
+
{
|
|
320
|
+
files: [
|
|
321
|
+
{
|
|
322
|
+
name: 'a',
|
|
323
|
+
label: 'a',
|
|
324
|
+
file: 'a.md',
|
|
325
|
+
fields: [{ name: 'title', label: 'title', widget: 'string' }],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: 'a',
|
|
329
|
+
label: 'b',
|
|
330
|
+
file: 'b.md',
|
|
331
|
+
fields: [{ name: 'title', label: 'title', widget: 'string' }],
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
},
|
|
335
|
+
],
|
|
336
|
+
}),
|
|
337
|
+
);
|
|
338
|
+
}).toThrowError("'collections[1].files' files names must be unique");
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('should throw if collection fields names are not unique', () => {
|
|
342
|
+
expect(() => {
|
|
343
|
+
validateConfig(
|
|
344
|
+
merge({}, validConfig, {
|
|
345
|
+
collections: [
|
|
346
|
+
{
|
|
347
|
+
fields: [
|
|
348
|
+
{ name: 'title', label: 'title', widget: 'string' },
|
|
349
|
+
{ name: 'title', label: 'other title', widget: 'string' },
|
|
350
|
+
],
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
}),
|
|
354
|
+
);
|
|
355
|
+
}).toThrowError("'collections[0].fields' fields names must be unique");
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('should not throw if collection fields are unique across nesting levels', () => {
|
|
359
|
+
expect(() => {
|
|
360
|
+
validateConfig(
|
|
361
|
+
merge({}, validConfig, {
|
|
362
|
+
collections: [
|
|
363
|
+
{
|
|
364
|
+
fields: [
|
|
365
|
+
{ name: 'title', label: 'title', widget: 'string' },
|
|
366
|
+
{
|
|
367
|
+
name: 'object',
|
|
368
|
+
label: 'Object',
|
|
369
|
+
widget: 'object',
|
|
370
|
+
fields: [{ name: 'title', label: 'title', widget: 'string' }],
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
}),
|
|
376
|
+
);
|
|
377
|
+
}).not.toThrow();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
describe('nested validation', () => {
|
|
381
|
+
const { getWidgets } = require('../../lib/registry');
|
|
382
|
+
getWidgets.mockImplementation(() => [
|
|
383
|
+
{
|
|
384
|
+
name: 'relation',
|
|
385
|
+
schema: {
|
|
386
|
+
properties: {
|
|
387
|
+
search_fields: { type: 'array', items: { type: 'string' } },
|
|
388
|
+
display_fields: { type: 'array', items: { type: 'string' } },
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
]);
|
|
393
|
+
|
|
394
|
+
it('should throw if nested relation display_fields and search_fields are not arrays', () => {
|
|
395
|
+
expect(() => {
|
|
396
|
+
validateConfig(
|
|
397
|
+
merge({}, validConfig, {
|
|
398
|
+
collections: [
|
|
399
|
+
{
|
|
400
|
+
fields: [
|
|
401
|
+
{ name: 'title', label: 'title', widget: 'string' },
|
|
402
|
+
{
|
|
403
|
+
name: 'object',
|
|
404
|
+
label: 'Object',
|
|
405
|
+
widget: 'object',
|
|
406
|
+
fields: [
|
|
407
|
+
{ name: 'title', label: 'title', widget: 'string' },
|
|
408
|
+
{
|
|
409
|
+
name: 'relation',
|
|
410
|
+
label: 'relation',
|
|
411
|
+
widget: 'relation',
|
|
412
|
+
display_fields: 'title',
|
|
413
|
+
search_fields: 'title',
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
},
|
|
419
|
+
],
|
|
420
|
+
}),
|
|
421
|
+
);
|
|
422
|
+
}).toThrowError(
|
|
423
|
+
"'collections[0].fields[1].fields[1].search_fields' must be array\n'collections[0].fields[1].fields[1].display_fields' must be array",
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('should not throw if nested relation display_fields and search_fields are arrays', () => {
|
|
428
|
+
expect(() => {
|
|
429
|
+
validateConfig(
|
|
430
|
+
merge({}, validConfig, {
|
|
431
|
+
collections: [
|
|
432
|
+
{
|
|
433
|
+
fields: [
|
|
434
|
+
{ name: 'title', label: 'title', widget: 'string' },
|
|
435
|
+
{
|
|
436
|
+
name: 'object',
|
|
437
|
+
label: 'Object',
|
|
438
|
+
widget: 'object',
|
|
439
|
+
fields: [
|
|
440
|
+
{ name: 'title', label: 'title', widget: 'string' },
|
|
441
|
+
{
|
|
442
|
+
name: 'relation',
|
|
443
|
+
label: 'relation',
|
|
444
|
+
widget: 'relation',
|
|
445
|
+
display_fields: ['title'],
|
|
446
|
+
search_fields: ['title'],
|
|
447
|
+
},
|
|
448
|
+
],
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
}),
|
|
454
|
+
);
|
|
455
|
+
}).not.toThrow();
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('should throw if collection meta is not a plain object', () => {
|
|
460
|
+
expect(() => {
|
|
461
|
+
validateConfig(merge({}, validConfig, { collections: [{ meta: [] }] }));
|
|
462
|
+
}).toThrowError("'collections[0].meta' must be object");
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it('should throw if collection meta is an empty object', () => {
|
|
466
|
+
expect(() => {
|
|
467
|
+
validateConfig(merge({}, validConfig, { collections: [{ meta: {} }] }));
|
|
468
|
+
}).toThrowError("'collections[0].meta' must NOT have fewer than 1 properties");
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it('should throw if collection meta is an empty object', () => {
|
|
472
|
+
expect(() => {
|
|
473
|
+
validateConfig(merge({}, validConfig, { collections: [{ meta: { path: {} } }] }));
|
|
474
|
+
}).toThrowError("'collections[0].meta.path' must have required property 'label'");
|
|
475
|
+
expect(() => {
|
|
476
|
+
validateConfig(
|
|
477
|
+
merge({}, validConfig, { collections: [{ meta: { path: { label: 'Label' } } }] }),
|
|
478
|
+
);
|
|
479
|
+
}).toThrowError("'collections[0].meta.path' must have required property 'widget'");
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it('should allow collection meta to have a path configuration with index_file', () => {
|
|
483
|
+
expect(() => {
|
|
484
|
+
validateConfig(
|
|
485
|
+
merge({}, validConfig, {
|
|
486
|
+
collections: [
|
|
487
|
+
{ meta: { path: { label: 'Path', widget: 'string', index_file: 'index' } } },
|
|
488
|
+
],
|
|
489
|
+
}),
|
|
490
|
+
);
|
|
491
|
+
}).not.toThrow();
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('should allow collection meta to have a path configuration without index_file', () => {
|
|
495
|
+
expect(() => {
|
|
496
|
+
validateConfig(
|
|
497
|
+
merge({}, validConfig, {
|
|
498
|
+
collections: [{ meta: { path: { label: 'Path', widget: 'string' } } }],
|
|
499
|
+
}),
|
|
500
|
+
);
|
|
501
|
+
}).not.toThrow();
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should throw if collection field pattern is not an array', () => {
|
|
505
|
+
expect(() => {
|
|
506
|
+
validateConfig(merge({}, validConfig, { collections: [{ fields: [{ pattern: '' }] }] }));
|
|
507
|
+
}).toThrowError("'collections[0].fields[0].pattern' must be array");
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('should throw if collection field pattern is not an array of [string|regex, string]', () => {
|
|
511
|
+
expect(() => {
|
|
512
|
+
validateConfig(
|
|
513
|
+
merge({}, validConfig, { collections: [{ fields: [{ pattern: [1, ''] }] }] }),
|
|
514
|
+
);
|
|
515
|
+
}).toThrowError(
|
|
516
|
+
"'collections[0].fields[0].pattern[0]' must be string\n'collections[0].fields[0].pattern[0]' must be a regular expression",
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
expect(() => {
|
|
520
|
+
validateConfig(
|
|
521
|
+
merge({}, validConfig, { collections: [{ fields: [{ pattern: ['', 1] }] }] }),
|
|
522
|
+
);
|
|
523
|
+
}).toThrowError("'collections[0].fields[0].pattern[1]' must be string");
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('should allow collection field pattern to be an array of [string|regex, string]', () => {
|
|
527
|
+
expect(() => {
|
|
528
|
+
validateConfig(
|
|
529
|
+
merge({}, validConfig, {
|
|
530
|
+
collections: [{ fields: [{ pattern: ['pattern', 'error'] }] }],
|
|
531
|
+
}),
|
|
532
|
+
);
|
|
533
|
+
}).not.toThrow();
|
|
534
|
+
|
|
535
|
+
expect(() => {
|
|
536
|
+
validateConfig(
|
|
537
|
+
merge({}, validConfig, {
|
|
538
|
+
collections: [{ fields: [{ pattern: [/pattern/, 'error'] }] }],
|
|
539
|
+
}),
|
|
540
|
+
);
|
|
541
|
+
}).not.toThrow();
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
describe('i18n', () => {
|
|
545
|
+
it('should throw error when locale has invalid characters', () => {
|
|
546
|
+
expect(() => {
|
|
547
|
+
validateConfig(
|
|
548
|
+
merge({}, validConfig, {
|
|
549
|
+
i18n: {
|
|
550
|
+
structure: 'multiple_folders',
|
|
551
|
+
locales: ['en', 'tr.TR'],
|
|
552
|
+
},
|
|
553
|
+
}),
|
|
554
|
+
);
|
|
555
|
+
}).toThrowError(`'i18n.locales[1]' must match pattern "^[a-zA-Z-_]+$"`);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it('should throw error when locale is less than 2 characters', () => {
|
|
559
|
+
expect(() => {
|
|
560
|
+
validateConfig(
|
|
561
|
+
merge({}, validConfig, {
|
|
562
|
+
i18n: {
|
|
563
|
+
structure: 'multiple_folders',
|
|
564
|
+
locales: ['en', 't'],
|
|
565
|
+
},
|
|
566
|
+
}),
|
|
567
|
+
);
|
|
568
|
+
}).toThrowError(`'i18n.locales[1]' must NOT have fewer than 2 characters`);
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it('should throw error when locale is more than 10 characters', () => {
|
|
572
|
+
expect(() => {
|
|
573
|
+
validateConfig(
|
|
574
|
+
merge({}, validConfig, {
|
|
575
|
+
i18n: {
|
|
576
|
+
structure: 'multiple_folders',
|
|
577
|
+
locales: ['en', 'a_very_long_locale'],
|
|
578
|
+
},
|
|
579
|
+
}),
|
|
580
|
+
);
|
|
581
|
+
}).toThrowError(`'i18n.locales[1]' must NOT have more than 10 characters`);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it('should throw error when locales is less than 1 items', () => {
|
|
585
|
+
expect(() => {
|
|
586
|
+
validateConfig(
|
|
587
|
+
merge({}, validConfig, {
|
|
588
|
+
i18n: {
|
|
589
|
+
structure: 'multiple_folders',
|
|
590
|
+
locales: [],
|
|
591
|
+
},
|
|
592
|
+
}),
|
|
593
|
+
);
|
|
594
|
+
}).toThrowError(`'i18n.locales' must NOT have fewer than 1 items`);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
it('should allow valid locales strings', () => {
|
|
598
|
+
expect(() => {
|
|
599
|
+
validateConfig(
|
|
600
|
+
merge({}, validConfig, {
|
|
601
|
+
i18n: {
|
|
602
|
+
structure: 'multiple_folders',
|
|
603
|
+
locales: ['en', 'tr-TR', 'zh_CHS'],
|
|
604
|
+
},
|
|
605
|
+
}),
|
|
606
|
+
);
|
|
607
|
+
}).not.toThrow();
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
});
|