@plone/volto 19.0.0-alpha.0 → 19.0.0-alpha.2

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 (188) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +2 -0
  3. package/CHANGELOG.md +63 -2
  4. package/locales/ca/LC_MESSAGES/volto.po +15 -0
  5. package/locales/ca.json +1 -1
  6. package/locales/de/LC_MESSAGES/volto.po +15 -0
  7. package/locales/de.json +1 -1
  8. package/locales/en/LC_MESSAGES/volto.po +15 -0
  9. package/locales/en.json +1 -1
  10. package/locales/es/LC_MESSAGES/volto.po +15 -0
  11. package/locales/es.json +1 -1
  12. package/locales/eu/LC_MESSAGES/volto.po +15 -0
  13. package/locales/eu.json +1 -1
  14. package/locales/fi/LC_MESSAGES/volto.po +15 -0
  15. package/locales/fi.json +1 -1
  16. package/locales/fr/LC_MESSAGES/volto.po +15 -0
  17. package/locales/fr.json +1 -1
  18. package/locales/hi/LC_MESSAGES/volto.po +15 -0
  19. package/locales/hi.json +1 -1
  20. package/locales/it/LC_MESSAGES/volto.po +15 -0
  21. package/locales/it.json +1 -1
  22. package/locales/ja/LC_MESSAGES/volto.po +15 -0
  23. package/locales/ja.json +1 -1
  24. package/locales/nl/LC_MESSAGES/volto.po +15 -0
  25. package/locales/nl.json +1 -1
  26. package/locales/pt/LC_MESSAGES/volto.po +15 -0
  27. package/locales/pt.json +1 -1
  28. package/locales/pt_BR/LC_MESSAGES/volto.po +15 -0
  29. package/locales/pt_BR.json +1 -1
  30. package/locales/ro/LC_MESSAGES/volto.po +15 -0
  31. package/locales/ro.json +1 -1
  32. package/locales/ru/LC_MESSAGES/volto.po +15 -0
  33. package/locales/ru.json +1 -1
  34. package/locales/volto.pot +15 -0
  35. package/locales/zh_CN/LC_MESSAGES/volto.po +15 -0
  36. package/locales/zh_CN.json +1 -1
  37. package/package.json +15 -8
  38. package/src/actions/actions/actions.test.js +3 -3
  39. package/src/actions/addons/addons.test.js +15 -12
  40. package/src/actions/aliases/aliases.test.js +1 -1
  41. package/src/actions/querystring/querystring.test.js +2 -2
  42. package/src/actions/types/types.test.js +1 -1
  43. package/src/components/manage/Actions/Actions.test.jsx +5 -1
  44. package/src/components/manage/Add/Add.jsx +22 -20
  45. package/src/components/manage/Add/Add.test.jsx +6 -3
  46. package/src/components/manage/Aliases/Aliases.test.jsx +7 -7
  47. package/src/components/manage/Blocks/Block/BlocksForm.jsx +1 -0
  48. package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +48 -16
  49. package/src/components/manage/Blocks/Block/Edit.jsx +2 -1
  50. package/src/components/manage/Blocks/Block/Settings.test.jsx +5 -1
  51. package/src/components/manage/Blocks/Block/StyleWrapper.jsx +11 -3
  52. package/src/components/manage/Blocks/Description/View.test.jsx +1 -1
  53. package/src/components/manage/Blocks/HTML/Edit.test.jsx +12 -5
  54. package/src/components/manage/Blocks/HTML/View.test.jsx +1 -1
  55. package/src/components/manage/Blocks/Image/ImageSidebar.test.jsx +6 -2
  56. package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -1
  57. package/src/components/manage/Blocks/Listing/View.test.jsx +3 -1
  58. package/src/components/manage/Blocks/Maps/MapsSidebar.test.jsx +5 -1
  59. package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +13 -7
  60. package/src/components/manage/Blocks/Search/components/SelectFacet.test.jsx +12 -6
  61. package/src/components/manage/Blocks/Title/Edit.jsx +8 -2
  62. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +11 -1
  63. package/src/components/manage/Blocks/Video/VideoSidebar.test.jsx +5 -1
  64. package/src/components/manage/ConditionalLink/ConditionalLink.test.tsx +109 -0
  65. package/src/components/manage/ConditionalLink/ConditionalLink.tsx +36 -0
  66. package/src/components/manage/Contents/Contents.test.jsx +29 -13
  67. package/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +5 -1
  68. package/src/components/manage/Contents/ContentsRenameModal.test.jsx +5 -1
  69. package/src/components/manage/Contents/ContentsTagsModal.test.jsx +5 -1
  70. package/src/components/manage/Contents/ContentsWorkflowModal.test.jsx +5 -1
  71. package/src/components/manage/Contents/__mocks__/index.tsx +16 -0
  72. package/src/components/manage/Contents/__mocks__/index.vitest.tsx +5 -0
  73. package/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx +28 -3
  74. package/src/components/manage/Controlpanels/Aliases.test.jsx +35 -3
  75. package/src/components/manage/Controlpanels/ContentType.test.jsx +29 -3
  76. package/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx +4 -2
  77. package/src/components/manage/Controlpanels/ContentTypes.test.jsx +25 -2
  78. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +37 -6
  79. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +47 -3
  80. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +15 -9
  81. package/src/components/manage/Controlpanels/ModerateComments.test.jsx +31 -5
  82. package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +13 -4
  83. package/src/components/manage/Controlpanels/Rules/ConfigureRule.test.jsx +9 -5
  84. package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +12 -4
  85. package/src/components/manage/Controlpanels/Rules/Rules.test.jsx +7 -3
  86. package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +33 -4
  87. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +3 -1
  88. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +15 -9
  89. package/src/components/manage/Delete/Delete.test.jsx +45 -4
  90. package/src/components/manage/Diff/Diff.test.jsx +15 -6
  91. package/src/components/manage/Diff/DiffField.test.jsx +12 -6
  92. package/src/components/manage/Display/Display.test.jsx +17 -6
  93. package/src/components/manage/Edit/Edit.test.jsx +11 -3
  94. package/src/components/manage/Form/BlockDataForm.test.jsx +5 -1
  95. package/src/components/manage/Form/Form.jsx +32 -0
  96. package/src/components/manage/Form/Form.test.jsx +27 -19
  97. package/src/components/manage/Form/InlineForm.test.jsx +5 -1
  98. package/src/components/manage/Form/ModalForm.test.jsx +5 -1
  99. package/src/components/manage/Form/__mocks__/index.tsx +17 -0
  100. package/src/components/manage/Form/__mocks__/index.vitest.tsx +73 -0
  101. package/src/components/manage/History/History.test.jsx +3 -1
  102. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +6 -4
  103. package/src/components/manage/MaybeWrap/MaybeWrap.tsx +15 -0
  104. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +3 -2
  105. package/src/components/manage/Preferences/ChangePassword.test.jsx +9 -2
  106. package/src/components/manage/Preferences/PersonalInformation.test.jsx +3 -1
  107. package/src/components/manage/Preferences/PersonalPreferences.test.jsx +20 -7
  108. package/src/components/manage/Rules/Rules.test.jsx +6 -3
  109. package/src/components/manage/Sharing/Sharing.test.jsx +3 -1
  110. package/src/components/manage/Sidebar/ObjectBrowserNav.test.jsx +3 -3
  111. package/src/components/manage/Toolbar/More.test.jsx +6 -7
  112. package/src/components/manage/UniversalLink/UniversalLink.test.jsx +196 -14
  113. package/src/components/manage/UniversalLink/UniversalLink.tsx +214 -0
  114. package/src/components/manage/Widgets/ArrayWidget.test.jsx +22 -5
  115. package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +12 -5
  116. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +21 -6
  117. package/src/components/manage/Widgets/ImageWidget.jsx +5 -2
  118. package/src/components/manage/Widgets/NumberWidget.test.jsx +8 -7
  119. package/src/components/manage/Widgets/ObjectListWidget.jsx +11 -1
  120. package/src/components/manage/Widgets/ObjectListWidget.test.jsx +18 -8
  121. package/src/components/manage/Widgets/ObjectWidget.test.jsx +5 -1
  122. package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +12 -5
  123. package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.test.jsx +12 -6
  124. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +43 -41
  125. package/src/components/manage/Widgets/SchemaWidget.test.jsx +12 -5
  126. package/src/components/manage/Widgets/SchemaWidgetFieldset.test.jsx +12 -5
  127. package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +12 -6
  128. package/src/components/manage/Widgets/SelectWidget.jsx +3 -1
  129. package/src/components/manage/Widgets/SelectWidget.test.jsx +12 -6
  130. package/src/components/manage/Widgets/TimeWidget.test.jsx +13 -5
  131. package/src/components/manage/Widgets/TokenWidget.test.jsx +12 -6
  132. package/src/components/manage/Widgets/VocabularyTermsWidget.test.jsx +18 -9
  133. package/src/components/manage/Widgets/__mocks__/index.tsx +16 -0
  134. package/src/components/manage/Widgets/__mocks__/index.vitest.tsx +41 -0
  135. package/src/components/manage/Workflow/Workflow.test.jsx +17 -7
  136. package/src/components/theme/App/App.test.jsx +21 -17
  137. package/src/components/theme/AppExtras/AppExtras.test.jsx +6 -6
  138. package/src/components/theme/Comments/CommentEditModal.test.jsx +5 -1
  139. package/src/components/theme/Comments/Comments.test.jsx +29 -12
  140. package/src/components/theme/ContactForm/ContactForm.test.jsx +8 -4
  141. package/src/components/theme/Header/Header.test.jsx +19 -13
  142. package/src/components/theme/Logout/Logout.test.jsx +1 -1
  143. package/src/components/theme/PasswordReset/PasswordReset.test.jsx +10 -1
  144. package/src/components/theme/PasswordReset/RequestPasswordReset.test.jsx +5 -1
  145. package/src/components/theme/Register/Register.test.jsx +5 -1
  146. package/src/components/theme/Search/Search.test.jsx +6 -4
  147. package/src/components/theme/TsTest/TsTest.test.tsx +0 -1
  148. package/src/components/theme/View/EventDatesInfo.test.jsx +12 -5
  149. package/src/components/theme/View/EventView.test.jsx +12 -5
  150. package/src/components/theme/View/ListingView.test.jsx +2 -0
  151. package/src/components/theme/View/SummaryView.test.jsx +10 -0
  152. package/src/components/theme/View/TabularView.test.jsx +1 -0
  153. package/src/components/theme/View/View.test.jsx +42 -23
  154. package/src/helpers/Api/Api.plone.rest.test.js +11 -9
  155. package/src/helpers/Api/Api.test.js +11 -14
  156. package/src/helpers/AsyncConnect/AsyncConnect.test.jsx +145 -189
  157. package/src/helpers/AuthToken/AuthToken.test.js +60 -22
  158. package/src/helpers/Blocks/Blocks.test.js +1 -1
  159. package/src/helpers/Html/Html.test.jsx +32 -28
  160. package/src/helpers/Loadable/__mocks__/Loadable.jsx +16 -1
  161. package/src/helpers/Loadable/__mocks__/Loadable.vitest.jsx +39 -0
  162. package/src/helpers/Utils/withSaveAsDraft.jsx +241 -0
  163. package/src/middleware/Api.test.js +47 -0
  164. package/src/middleware/api.js +1 -1
  165. package/src/middleware/storeProtectLoadUtils.test.js +90 -78
  166. package/test-setup-globals-vitest.js +46 -0
  167. package/theme/themes/pastanaga/collections/table.overrides +9 -0
  168. package/theme/themes/pastanaga/extras/main.less +15 -0
  169. package/tsconfig.declarations.json +12 -1
  170. package/tsconfig.json +2 -1
  171. package/types/components/manage/ConditionalLink/ConditionalLink.d.ts +11 -15
  172. package/types/components/manage/Contents/__mocks__/index.vitest.d.ts +2 -0
  173. package/types/components/manage/Form/__mocks__/index.vitest.d.ts +8 -0
  174. package/types/components/manage/MaybeWrap/MaybeWrap.d.ts +7 -5
  175. package/types/components/manage/UniversalLink/UniversalLink.d.ts +54 -20
  176. package/types/components/manage/Widgets/__mocks__/index.vitest.d.ts +33 -0
  177. package/types/helpers/Loadable/__mocks__/Loadable.vitest.d.ts +3 -0
  178. package/types/helpers/Utils/withSaveAsDraft.d.ts +1 -0
  179. package/types/react-router-hash-link.d.ts +12 -0
  180. package/types/routes.d.ts +4 -0
  181. package/types/server.d.ts +1 -1
  182. package/vite-plugins/svg.mjs +81 -0
  183. package/vitest.config.mjs +77 -0
  184. package/src/components/manage/ConditionalLink/ConditionalLink.jsx +0 -27
  185. package/src/components/manage/ConditionalLink/ConditionalLink.test.jsx +0 -30
  186. package/src/components/manage/MaybeWrap/MaybeWrap.jsx +0 -9
  187. package/src/components/manage/UniversalLink/UniversalLink.jsx +0 -154
  188. package/src/components/manage/Widgets/FileWidget.test.jsx +0 -91
@@ -3,25 +3,50 @@ import { Provider } from 'react-intl-redux';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import BlocksForm from './BlocksForm';
5
5
  import { render } from '@testing-library/react';
6
-
7
6
  import config from '@plone/volto/registry';
8
7
 
9
8
  config.experimental = { addBlockButton: { enabled: false } };
10
9
 
11
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
12
- beforeAll(
13
- async () =>
14
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
15
- );
10
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
11
+ return await import(
12
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
13
+ );
14
+ });
16
15
 
17
- let mockSerial = 0;
16
+ beforeAll(async () => {
17
+ const { __setLoadables } = await import(
18
+ '@plone/volto/helpers/Loadable/Loadable'
19
+ );
20
+ await __setLoadables();
21
+ });
18
22
 
19
- jest.mock('uuid', () => {
23
+ let mockSerial = 0;
24
+ vi.mock('uuid', () => {
20
25
  return {
21
- v4: jest.fn().mockImplementation(() => `id-${mockSerial++}`),
26
+ v4: vi.fn().mockImplementation(() => `id-${mockSerial++}`),
22
27
  };
23
28
  });
24
29
 
30
+ vi.mock('react-beautiful-dnd', () => ({
31
+ DragDropContext: ({ children }) => <div>{children}</div>,
32
+ Droppable: ({ children }) =>
33
+ children({
34
+ innerRef: () => {},
35
+ droppableProps: {},
36
+ placeholder: <div />,
37
+ }),
38
+ Draggable: ({ children }) =>
39
+ children({
40
+ innerRef: () => {},
41
+ draggableProps: {},
42
+ dragHandleProps: {},
43
+ }),
44
+ }));
45
+
46
+ vi.mock('./Order/Order', () => ({
47
+ default: () => <div>Order Component</div>,
48
+ }));
49
+
25
50
  const mockStore = configureStore();
26
51
 
27
52
  test('Allow override of blocksConfig', () => {
@@ -70,10 +95,13 @@ test('Allow override of blocksConfig', () => {
70
95
 
71
96
  const { container } = render(
72
97
  <Provider store={store}>
73
- <BlocksForm {...data} />
74
- <div id="sidebar-order"></div>
98
+ <div>
99
+ <BlocksForm {...data} />
100
+ <div id="sidebar-order"></div>
101
+ </div>
75
102
  </Provider>,
76
103
  );
104
+
77
105
  expect(container).toMatchSnapshot();
78
106
  });
79
107
 
@@ -88,7 +116,7 @@ test('Removes invalid blocks on saving', () => {
88
116
  },
89
117
  });
90
118
 
91
- const onChangeFormData = jest.fn(() => {});
119
+ const onChangeFormData = vi.fn(() => {});
92
120
 
93
121
  const data = {
94
122
  pathname: '/test',
@@ -126,18 +154,22 @@ test('Removes invalid blocks on saving', () => {
126
154
 
127
155
  render(
128
156
  <Provider store={store}>
129
- <BlocksForm {...data} />
130
- <div id="sidebar-order"></div>
157
+ <div>
158
+ <BlocksForm {...data} />
159
+ <div id="sidebar-order"></div>
160
+ </div>
131
161
  </Provider>,
132
162
  );
133
- expect(onChangeFormData).toBeCalledWith({
163
+
164
+ expect(onChangeFormData).toHaveBeenCalledWith({
134
165
  blocks: {
135
166
  a: { '@type': 'custom', text: 'a' },
136
167
  b: { '@type': 'custom', text: 'b' },
137
168
  },
138
169
  blocks_layout: { items: ['a', 'b', 'MISSING-YOU-1'] },
139
170
  });
140
- expect(onChangeFormData).toBeCalledWith({
171
+
172
+ expect(onChangeFormData).toHaveBeenCalledWith({
141
173
  blocks: {
142
174
  a: { '@type': 'custom', text: 'a' },
143
175
  b: { '@type': 'custom', text: 'b' },
@@ -122,7 +122,7 @@ export class Edit extends Component {
122
122
  */
123
123
  render() {
124
124
  const { blocksConfig = config.blocks.blocksConfig } = this.props;
125
- const { editable, type } = this.props;
125
+ const { editable, type, isContainer: parentIsContainer } = this.props;
126
126
 
127
127
  const disableNewBlocks = this.props.data?.disableNewBlocks;
128
128
 
@@ -198,6 +198,7 @@ export class Edit extends Component {
198
198
  {...this.props}
199
199
  blockNode={this.blockNode}
200
200
  data={this.props.data}
201
+ className={cx({ contained: parentIsContainer })}
201
202
  />
202
203
  {this.props.manage && (
203
204
  <SidebarPortal
@@ -5,7 +5,11 @@ import configureStore from 'redux-mock-store';
5
5
  import config from '@plone/volto/registry';
6
6
  import { Provider } from 'react-intl-redux';
7
7
 
8
- jest.mock('@plone/volto/components/manage/Form');
8
+ vi.mock('@plone/volto/components/manage/Form', async () => {
9
+ return await import(
10
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
11
+ );
12
+ });
9
13
 
10
14
  const mockStore = configureStore();
11
15
 
@@ -9,7 +9,13 @@ import {
9
9
  const StyleWrapper = (props) => {
10
10
  let classNames,
11
11
  style = [];
12
- const { block, children, content, data = {}, isContainer } = props;
12
+ const {
13
+ block,
14
+ children,
15
+ content,
16
+ data = {},
17
+ isContainer: parentIsContainer,
18
+ } = props;
13
19
  classNames = buildStyleClassNamesFromData(data.styles);
14
20
 
15
21
  classNames = buildStyleClassNamesExtenders({
@@ -24,14 +30,16 @@ const StyleWrapper = (props) => {
24
30
  '',
25
31
  // If we are rendering blocks inside a container, then pass also the data from the container
26
32
  // This is needed in order to calculate properly the styles for the blocks inside the container
27
- isContainer && content.blocks ? content : {},
33
+ parentIsContainer && content.blocks ? content : {},
28
34
  );
29
35
 
30
36
  const rewrittenChildren = React.Children.map(children, (child) => {
31
37
  if (React.isValidElement(child)) {
32
38
  const childProps = {
33
39
  ...props,
34
- className: cx([child.props.className, ...classNames]),
40
+ className: cx([child.props.className, ...classNames], {
41
+ contained: parentIsContainer,
42
+ }),
35
43
  style: { ...child.props.style, ...style },
36
44
  };
37
45
  return React.cloneElement(child, childProps);
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import renderer from 'react-test-renderer';
3
3
  import View from './View';
4
4
 
5
- test('renders a view description component', () => {
5
+ it('renders a view description component', () => {
6
6
  const component = renderer.create(
7
7
  <View properties={{ description: 'My Description' }} />,
8
8
  );
@@ -7,11 +7,18 @@ import Edit from './Edit';
7
7
 
8
8
  const mockStore = configureStore();
9
9
 
10
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
11
- beforeAll(
12
- async () =>
13
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
14
- );
10
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
11
+ return await import(
12
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
13
+ );
14
+ });
15
+
16
+ beforeAll(async () => {
17
+ const { __setLoadables } = await import(
18
+ '@plone/volto/helpers/Loadable/Loadable'
19
+ );
20
+ await __setLoadables();
21
+ });
15
22
 
16
23
  test('renders an edit html block component', async () => {
17
24
  const store = mockStore({
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import renderer from 'react-test-renderer';
3
3
  import View from './View';
4
4
 
5
- test('renders a view html component', () => {
5
+ it('renders a view html component', () => {
6
6
  const component = renderer.create(<View data={{ html: '<h1></h1>' }} />);
7
7
  const json = component.toJSON();
8
8
  expect(json).toMatchSnapshot();
@@ -5,11 +5,15 @@ import { Provider } from 'react-intl-redux';
5
5
 
6
6
  import ImageSidebar from './ImageSidebar';
7
7
 
8
- jest.mock('@plone/volto/components/manage/Form');
8
+ vi.mock('@plone/volto/components/manage/Form', async () => {
9
+ return await import(
10
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
11
+ );
12
+ });
9
13
 
10
14
  const mockStore = configureStore();
11
15
 
12
- test('renders an Image Block Sidebar component', () => {
16
+ it('renders an Image Block Sidebar component', () => {
13
17
  const store = mockStore({
14
18
  content: {
15
19
  create: {},
@@ -5,7 +5,12 @@ import { Provider } from 'react-intl-redux';
5
5
 
6
6
  import LeadImageSidebar from './LeadImageSidebar';
7
7
 
8
- jest.mock('@plone/volto/components/manage/Widgets');
8
+ vi.mock('@plone/volto/components/manage/Widgets');
9
+ vi.mock('@plone/volto/components/manage/Widgets', async () => {
10
+ return await import(
11
+ '@plone/volto/components/manage/Widgets/__mocks__/index.vitest.tsx'
12
+ );
13
+ });
9
14
 
10
15
  const mockStore = configureStore();
11
16
 
@@ -16,6 +21,7 @@ test('renders a Lead Image block Sidebar component', () => {
16
21
  messages: {},
17
22
  },
18
23
  });
24
+
19
25
  const component = renderer.create(
20
26
  <Provider store={store}>
21
27
  <LeadImageSidebar
@@ -45,6 +51,7 @@ test('renders a Lead Image block Sidebar component', () => {
45
51
  />
46
52
  </Provider>,
47
53
  );
54
+
48
55
  const json = component.toJSON();
49
56
  expect(json).toMatchSnapshot();
50
57
  });
@@ -2,7 +2,9 @@ import React from 'react';
2
2
  import renderer from 'react-test-renderer';
3
3
  import View from './View';
4
4
 
5
- jest.mock('./ListingBody', () => jest.fn(() => <div className="theblock" />));
5
+ vi.mock('./ListingBody', () => ({
6
+ default: () => <div className="theblock" />,
7
+ }));
6
8
 
7
9
  test('renders a view image component for the listing block', () => {
8
10
  const component = renderer.create(
@@ -5,7 +5,11 @@ import { Provider } from 'react-intl-redux';
5
5
 
6
6
  import MapsSidebar from './MapsSidebar';
7
7
 
8
- jest.mock('@plone/volto/components/manage/Form');
8
+ vi.mock('@plone/volto/components/manage/Form', async () => {
9
+ return await import(
10
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
11
+ );
12
+ });
9
13
 
10
14
  const mockStore = configureStore();
11
15
 
@@ -2,18 +2,24 @@ import React from 'react';
2
2
  import configureStore from 'redux-mock-store';
3
3
  import { Provider } from 'react-intl-redux';
4
4
  import { waitFor, render, screen } from '@testing-library/react';
5
-
6
5
  import DateRangeFacet from './DateRangeFacet';
7
6
 
8
7
  const mockStore = configureStore();
9
8
 
10
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
11
- beforeAll(
12
- async () =>
13
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
14
- );
9
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
10
+ return await import(
11
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
12
+ );
13
+ });
14
+
15
+ beforeAll(async () => {
16
+ const { __setLoadables } = await import(
17
+ '@plone/volto/helpers/Loadable/Loadable'
18
+ );
19
+ await __setLoadables();
20
+ });
15
21
 
16
- describe('DateRangeFaceg', () => {
22
+ describe('DateRangeFacet', () => {
17
23
  it('renders a facet component with a date range widget', async () => {
18
24
  const store = mockStore({
19
25
  userSession: { token: null },
@@ -2,16 +2,22 @@ import React from 'react';
2
2
  import configureStore from 'redux-mock-store';
3
3
  import { Provider } from 'react-intl-redux';
4
4
  import { waitFor, render, screen } from '@testing-library/react';
5
-
6
5
  import SelectFacet from './SelectFacet';
7
6
 
8
7
  const mockStore = configureStore();
9
8
 
10
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
11
- beforeAll(
12
- async () =>
13
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
14
- );
9
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
10
+ return await import(
11
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
12
+ );
13
+ });
14
+
15
+ beforeAll(async () => {
16
+ const { __setLoadables } = await import(
17
+ '@plone/volto/helpers/Loadable/Loadable'
18
+ );
19
+ await __setLoadables();
20
+ });
15
21
 
16
22
  describe('SelectFacet', () => {
17
23
  it('renders a facet component with select dropdown', async () => {
@@ -77,8 +77,14 @@ export const TitleBlockEdit = (props) => {
77
77
  ReactEditor.focus(editor);
78
78
  } else {
79
79
  // nothing is selected, move focus to end
80
- ReactEditor.focus(editor);
81
- Transforms.select(editor, Editor.end(editor, []));
80
+ // make sure that the editor is focused
81
+ setTimeout(() => {
82
+ const focused = ReactEditor.focus(editor);
83
+ if (!focused) {
84
+ ReactEditor.focus(editor);
85
+ Transforms.select(editor, Editor.end(editor, []));
86
+ }
87
+ }, 0);
82
88
  }
83
89
  }
84
90
  }, [prevSelected, selected, editor]);
@@ -8,6 +8,12 @@ const mockStore = configureStore();
8
8
 
9
9
  const data = { '@type': 'toc', variation: 'default' };
10
10
 
11
+ const properties = {
12
+ title: 'Table of Contents',
13
+ hide_title: false,
14
+ ordered: true,
15
+ };
16
+
11
17
  const tocEntries = [
12
18
  {
13
19
  level: 2,
@@ -35,7 +41,11 @@ test('renders a default toc renderer component', () => {
35
41
  const component = renderer.create(
36
42
  <Provider store={store}>
37
43
  <MemoryRouter>
38
- <DefaultTocRenderer data={data} tocEntries={tocEntries} />
44
+ <DefaultTocRenderer
45
+ properties={properties}
46
+ data={data}
47
+ tocEntries={tocEntries}
48
+ />
39
49
  </MemoryRouter>
40
50
  </Provider>,
41
51
  );
@@ -5,7 +5,11 @@ import { Provider } from 'react-intl-redux';
5
5
 
6
6
  import VideoSidebar from './VideoSidebar';
7
7
 
8
- jest.mock('@plone/volto/components/manage/Form');
8
+ vi.mock('@plone/volto/components/manage/Form', async () => {
9
+ return await import(
10
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
11
+ );
12
+ });
9
13
 
10
14
  const mockStore = configureStore();
11
15
 
@@ -0,0 +1,109 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { MemoryRouter } from 'react-router-dom';
4
+ import { Provider } from 'react-intl-redux';
5
+ import configureStore from 'redux-mock-store';
6
+ import '@testing-library/jest-dom';
7
+
8
+ import ConditionalLink from './ConditionalLink';
9
+
10
+ const mockStore = configureStore();
11
+ const store = mockStore({
12
+ userSession: {
13
+ token: null,
14
+ },
15
+ intl: {
16
+ locale: 'en',
17
+ messages: {},
18
+ },
19
+ });
20
+
21
+ describe('ConditionalLink', () => {
22
+ it('renders a link when condition is true', () => {
23
+ render(
24
+ <Provider store={store}>
25
+ <MemoryRouter>
26
+ <ConditionalLink to="/test" condition={true}>
27
+ Link Text
28
+ </ConditionalLink>
29
+ </MemoryRouter>
30
+ </Provider>,
31
+ );
32
+
33
+ const link = screen.getByText('Link Text');
34
+ expect(link.tagName).toBe('A');
35
+ expect(link).toHaveAttribute('href', '/test');
36
+ });
37
+
38
+ it('renders a link when condition is true', () => {
39
+ render(
40
+ <Provider store={store}>
41
+ <MemoryRouter>
42
+ <ConditionalLink href="/test" condition={true}>
43
+ Link Text
44
+ </ConditionalLink>
45
+ </MemoryRouter>
46
+ </Provider>,
47
+ );
48
+
49
+ const link = screen.getByText('Link Text');
50
+ expect(link.tagName).toBe('A');
51
+ expect(link).toHaveAttribute('href', '/test');
52
+ });
53
+
54
+ it('renders a span when condition is false', () => {
55
+ render(
56
+ <Provider store={store}>
57
+ <MemoryRouter>
58
+ <ConditionalLink to="/test" condition={false}>
59
+ Link Text
60
+ </ConditionalLink>
61
+ </MemoryRouter>
62
+ </Provider>,
63
+ );
64
+
65
+ const span = screen.getByText('Link Text');
66
+ expect(span.tagName).toBe('DIV');
67
+ });
68
+
69
+ it('passes additional props when rendering a link', () => {
70
+ render(
71
+ <Provider store={store}>
72
+ <MemoryRouter>
73
+ <ConditionalLink
74
+ to="/test"
75
+ condition={true}
76
+ className="custom-class"
77
+ data-test="test-id"
78
+ >
79
+ Link Text
80
+ </ConditionalLink>
81
+ </MemoryRouter>
82
+ </Provider>,
83
+ );
84
+
85
+ const link = screen.getByText('Link Text');
86
+ expect(link).toHaveClass('custom-class');
87
+ expect(link).toHaveAttribute('data-test', 'test-id');
88
+ });
89
+
90
+ it('renders a component if no external (href) link is passed', () => {
91
+ render(
92
+ <Provider store={store}>
93
+ <MemoryRouter>
94
+ <ConditionalLink
95
+ condition={true}
96
+ item={{
97
+ '@id': 'http://localhost:3000/en/welcome-to-volto',
98
+ }}
99
+ >
100
+ <h1>Title</h1>
101
+ </ConditionalLink>
102
+ </MemoryRouter>
103
+ </Provider>,
104
+ );
105
+
106
+ const title = screen.getByText('Title');
107
+ expect(title.tagName).toBe('H1');
108
+ });
109
+ });
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
3
+ import type { UniversalLinkProps } from '@plone/volto/components/manage/UniversalLink/UniversalLink';
4
+
5
+ type ConditionalLinkProps = {
6
+ condition?: boolean;
7
+ to?: string; // Alias for href
8
+ children: React.ReactNode;
9
+ } & Omit<UniversalLinkProps, 'href' | 'item'> & {
10
+ href?: string;
11
+ item?: UniversalLinkProps['item'];
12
+ };
13
+
14
+ const ConditionalLink = React.forwardRef<
15
+ HTMLAnchorElement | HTMLDivElement,
16
+ ConditionalLinkProps
17
+ >(function ConditionalLink(
18
+ { condition = true, to, href, item, children, ...rest },
19
+ ref,
20
+ ) {
21
+ if (!condition) {
22
+ return <>{children}</>;
23
+ }
24
+
25
+ // Normalize: prefer explicit href over "to"
26
+ const finalHref = href ?? to;
27
+
28
+ // Rebuild props safely to satisfy UniversalLinkProps union
29
+ const universalLinkProps: UniversalLinkProps = finalHref
30
+ ? { ...rest, href: finalHref, children }
31
+ : { ...rest, item: item!, children }; // assume item is defined if href isn't
32
+
33
+ return <UniversalLink ref={ref} {...universalLinkProps} />;
34
+ });
35
+
36
+ export default React.memo(ConditionalLink);
@@ -8,20 +8,29 @@ import { __test__ as Contents } from './Contents';
8
8
 
9
9
  const mockStore = configureStore();
10
10
 
11
- jest.mock('@plone/volto/helpers/Loadable/Loadable');
12
- beforeAll(
13
- async () =>
14
- await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
15
- );
11
+ vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
12
+ return await import(
13
+ '@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
14
+ );
15
+ });
16
+
17
+ beforeAll(async () => {
18
+ const { __setLoadables } = await import(
19
+ '@plone/volto/helpers/Loadable/Loadable'
20
+ );
21
+ await __setLoadables();
22
+ });
16
23
 
17
- jest.mock('../Toolbar/Toolbar', () => jest.fn(() => <div id="Portal" />));
24
+ vi.mock('../Toolbar/Toolbar', () => ({
25
+ default: vi.fn(() => <div id="Portal" />),
26
+ }));
18
27
 
19
- jest.mock('../../theme/Pagination/Pagination', () =>
20
- jest.fn(() => <div className="Pagination" />),
21
- );
22
- jest.mock('./ContentsUploadModal', () =>
23
- jest.fn(() => <div className="UploadModal" />),
24
- );
28
+ vi.mock('../../theme/Pagination/Pagination', () => ({
29
+ default: vi.fn(() => <div className="Pagination" />),
30
+ }));
31
+ vi.mock('./ContentsUploadModal', () => ({
32
+ default: vi.fn(() => <div className="UploadModal" />),
33
+ }));
25
34
 
26
35
  describe('Contents', () => {
27
36
  it('renders a folder contents view component', () => {
@@ -87,7 +96,14 @@ describe('Contents', () => {
87
96
  },
88
97
  intl: {
89
98
  locale: 'en',
90
- messages: {},
99
+ messages: {
100
+ ID: 'ID',
101
+ Title: 'Title',
102
+ 'Publication date': 'Publication date',
103
+ 'Created on': 'Created on',
104
+ 'Last modified': 'Last modified',
105
+ Type: 'Type',
106
+ },
91
107
  },
92
108
  });
93
109
  const { container } = render(
@@ -7,7 +7,11 @@ import ContentsPropertiesModal from './ContentsPropertiesModal';
7
7
 
8
8
  const mockStore = configureStore();
9
9
 
10
- jest.mock('@plone/volto/components/manage/Form');
10
+ vi.mock('@plone/volto/components/manage/Form', async () => {
11
+ return await import(
12
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
13
+ );
14
+ });
11
15
 
12
16
  describe('ContentsPropertiesModal', () => {
13
17
  it('renders a contents properties modal component', () => {
@@ -7,7 +7,11 @@ import ContentsRenameModal from './ContentsRenameModal';
7
7
 
8
8
  const mockStore = configureStore();
9
9
 
10
- jest.mock('@plone/volto/components/manage/Form');
10
+ vi.mock('@plone/volto/components/manage/Form', async () => {
11
+ return await import(
12
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
13
+ );
14
+ });
11
15
 
12
16
  describe('ContentsRenameModal', () => {
13
17
  it('renders a contents rename modal component', () => {
@@ -7,7 +7,11 @@ import ContentsTagsModal from './ContentsTagsModal';
7
7
 
8
8
  const mockStore = configureStore();
9
9
 
10
- jest.mock('@plone/volto/components/manage/Form');
10
+ vi.mock('@plone/volto/components/manage/Form', async () => {
11
+ return await import(
12
+ '@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
13
+ );
14
+ });
11
15
 
12
16
  describe('ContentsTagsModal', () => {
13
17
  it('renders a contents tags modal component', () => {