@plone/volto 19.0.0-alpha.0 → 19.0.0-alpha.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/.eslintignore +1 -0
- package/.eslintrc +2 -0
- package/CHANGELOG.md +46 -2
- package/package.json +14 -7
- package/src/actions/actions/actions.test.js +3 -3
- package/src/actions/addons/addons.test.js +15 -12
- package/src/actions/aliases/aliases.test.js +1 -1
- package/src/actions/querystring/querystring.test.js +2 -2
- package/src/actions/types/types.test.js +1 -1
- package/src/components/manage/Actions/Actions.test.jsx +5 -1
- package/src/components/manage/Add/Add.jsx +22 -20
- package/src/components/manage/Add/Add.test.jsx +6 -3
- package/src/components/manage/Aliases/Aliases.test.jsx +7 -7
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +1 -0
- package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +48 -16
- package/src/components/manage/Blocks/Block/Edit.jsx +2 -1
- package/src/components/manage/Blocks/Block/Settings.test.jsx +5 -1
- package/src/components/manage/Blocks/Block/StyleWrapper.jsx +11 -3
- package/src/components/manage/Blocks/Description/View.test.jsx +1 -1
- package/src/components/manage/Blocks/HTML/Edit.test.jsx +12 -5
- package/src/components/manage/Blocks/HTML/View.test.jsx +1 -1
- package/src/components/manage/Blocks/Image/ImageSidebar.test.jsx +6 -2
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -1
- package/src/components/manage/Blocks/Listing/View.test.jsx +3 -1
- package/src/components/manage/Blocks/Maps/MapsSidebar.test.jsx +5 -1
- package/src/components/manage/Blocks/Search/components/DateRangeFacet.test.jsx +13 -7
- package/src/components/manage/Blocks/Search/components/SelectFacet.test.jsx +12 -6
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +11 -1
- package/src/components/manage/Blocks/Video/VideoSidebar.test.jsx +5 -1
- package/src/components/manage/ConditionalLink/ConditionalLink.test.tsx +109 -0
- package/src/components/manage/ConditionalLink/ConditionalLink.tsx +36 -0
- package/src/components/manage/Contents/Contents.test.jsx +29 -13
- package/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +5 -1
- package/src/components/manage/Contents/ContentsRenameModal.test.jsx +5 -1
- package/src/components/manage/Contents/ContentsTagsModal.test.jsx +5 -1
- package/src/components/manage/Contents/ContentsWorkflowModal.test.jsx +5 -1
- package/src/components/manage/Contents/__mocks__/index.tsx +16 -0
- package/src/components/manage/Contents/__mocks__/index.vitest.tsx +5 -0
- package/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx +28 -3
- package/src/components/manage/Controlpanels/Aliases.test.jsx +35 -3
- package/src/components/manage/Controlpanels/ContentType.test.jsx +29 -3
- package/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx +4 -2
- package/src/components/manage/Controlpanels/ContentTypes.test.jsx +25 -2
- package/src/components/manage/Controlpanels/Controlpanel.test.jsx +37 -6
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +47 -3
- package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +15 -9
- package/src/components/manage/Controlpanels/ModerateComments.test.jsx +31 -5
- package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +13 -4
- package/src/components/manage/Controlpanels/Rules/ConfigureRule.test.jsx +9 -5
- package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +12 -4
- package/src/components/manage/Controlpanels/Rules/Rules.test.jsx +7 -3
- package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +33 -4
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +3 -1
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +15 -9
- package/src/components/manage/Delete/Delete.test.jsx +45 -4
- package/src/components/manage/Diff/Diff.test.jsx +15 -6
- package/src/components/manage/Diff/DiffField.test.jsx +12 -6
- package/src/components/manage/Display/Display.test.jsx +17 -6
- package/src/components/manage/Edit/Edit.test.jsx +11 -3
- package/src/components/manage/Form/BlockDataForm.test.jsx +5 -1
- package/src/components/manage/Form/Form.test.jsx +5 -1
- package/src/components/manage/Form/InlineForm.test.jsx +5 -1
- package/src/components/manage/Form/ModalForm.test.jsx +5 -1
- package/src/components/manage/Form/__mocks__/index.tsx +17 -0
- package/src/components/manage/Form/__mocks__/index.vitest.tsx +73 -0
- package/src/components/manage/History/History.test.jsx +3 -1
- package/src/components/manage/LinksToItem/LinksToItem.test.jsx +6 -4
- package/src/components/manage/MaybeWrap/MaybeWrap.tsx +15 -0
- package/src/components/manage/Multilingual/ManageTranslations.test.jsx +3 -2
- package/src/components/manage/Preferences/ChangePassword.test.jsx +9 -2
- package/src/components/manage/Preferences/PersonalInformation.test.jsx +3 -1
- package/src/components/manage/Preferences/PersonalPreferences.test.jsx +20 -7
- package/src/components/manage/Rules/Rules.test.jsx +6 -3
- package/src/components/manage/Sharing/Sharing.test.jsx +3 -1
- package/src/components/manage/Sidebar/ObjectBrowserNav.test.jsx +3 -3
- package/src/components/manage/Toolbar/More.test.jsx +6 -7
- package/src/components/manage/UniversalLink/UniversalLink.test.jsx +196 -14
- package/src/components/manage/UniversalLink/UniversalLink.tsx +214 -0
- package/src/components/manage/Widgets/ArrayWidget.test.jsx +22 -5
- package/src/components/manage/Widgets/CheckboxGroupWidget.test.jsx +12 -5
- package/src/components/manage/Widgets/DatetimeWidget.test.jsx +21 -6
- package/src/components/manage/Widgets/ImageWidget.jsx +5 -2
- package/src/components/manage/Widgets/NumberWidget.test.jsx +8 -7
- package/src/components/manage/Widgets/ObjectListWidget.jsx +11 -1
- package/src/components/manage/Widgets/ObjectListWidget.test.jsx +18 -8
- package/src/components/manage/Widgets/ObjectWidget.test.jsx +5 -1
- package/src/components/manage/Widgets/RadioGroupWidget.test.jsx +12 -5
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.test.jsx +12 -6
- package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +43 -41
- package/src/components/manage/Widgets/SchemaWidget.test.jsx +12 -5
- package/src/components/manage/Widgets/SchemaWidgetFieldset.test.jsx +12 -5
- package/src/components/manage/Widgets/SelectAutoComplete.test.jsx +12 -6
- package/src/components/manage/Widgets/SelectWidget.test.jsx +12 -6
- package/src/components/manage/Widgets/TimeWidget.test.jsx +13 -5
- package/src/components/manage/Widgets/TokenWidget.test.jsx +12 -6
- package/src/components/manage/Widgets/VocabularyTermsWidget.test.jsx +18 -9
- package/src/components/manage/Widgets/__mocks__/index.tsx +16 -0
- package/src/components/manage/Widgets/__mocks__/index.vitest.tsx +41 -0
- package/src/components/manage/Workflow/Workflow.test.jsx +17 -7
- package/src/components/theme/App/App.test.jsx +21 -17
- package/src/components/theme/AppExtras/AppExtras.test.jsx +6 -6
- package/src/components/theme/Comments/CommentEditModal.test.jsx +5 -1
- package/src/components/theme/Comments/Comments.test.jsx +29 -12
- package/src/components/theme/ContactForm/ContactForm.test.jsx +8 -4
- package/src/components/theme/Header/Header.test.jsx +19 -13
- package/src/components/theme/Logout/Logout.test.jsx +1 -1
- package/src/components/theme/PasswordReset/PasswordReset.test.jsx +10 -1
- package/src/components/theme/PasswordReset/RequestPasswordReset.test.jsx +5 -1
- package/src/components/theme/Register/Register.test.jsx +5 -1
- package/src/components/theme/Search/Search.test.jsx +6 -4
- package/src/components/theme/TsTest/TsTest.test.tsx +0 -1
- package/src/components/theme/View/EventDatesInfo.test.jsx +12 -5
- package/src/components/theme/View/EventView.test.jsx +12 -5
- package/src/components/theme/View/ListingView.test.jsx +2 -0
- package/src/components/theme/View/SummaryView.test.jsx +10 -0
- package/src/components/theme/View/TabularView.test.jsx +1 -0
- package/src/components/theme/View/View.test.jsx +42 -23
- package/src/helpers/Api/Api.plone.rest.test.js +11 -9
- package/src/helpers/Api/Api.test.js +11 -14
- package/src/helpers/AsyncConnect/AsyncConnect.test.jsx +145 -189
- package/src/helpers/AuthToken/AuthToken.test.js +60 -22
- package/src/helpers/Blocks/Blocks.test.js +1 -1
- package/src/helpers/Html/Html.test.jsx +32 -28
- package/src/helpers/Loadable/__mocks__/Loadable.jsx +16 -1
- package/src/helpers/Loadable/__mocks__/Loadable.vitest.jsx +39 -0
- package/src/middleware/Api.test.js +47 -0
- package/src/middleware/api.js +1 -1
- package/src/middleware/storeProtectLoadUtils.test.js +90 -78
- package/test-setup-globals-vitest.js +46 -0
- package/tsconfig.declarations.json +12 -1
- package/tsconfig.json +2 -1
- package/types/components/manage/ConditionalLink/ConditionalLink.d.ts +11 -15
- package/types/components/manage/Contents/__mocks__/index.vitest.d.ts +2 -0
- package/types/components/manage/Form/__mocks__/index.vitest.d.ts +8 -0
- package/types/components/manage/MaybeWrap/MaybeWrap.d.ts +7 -5
- package/types/components/manage/UniversalLink/UniversalLink.d.ts +54 -20
- package/types/components/manage/Widgets/__mocks__/index.vitest.d.ts +33 -0
- package/types/helpers/Loadable/__mocks__/Loadable.vitest.d.ts +3 -0
- package/types/react-router-hash-link.d.ts +12 -0
- package/types/routes.d.ts +4 -0
- package/types/server.d.ts +1 -1
- package/vite-plugins/svg.mjs +81 -0
- package/vitest.config.mjs +77 -0
- package/src/components/manage/ConditionalLink/ConditionalLink.jsx +0 -27
- package/src/components/manage/ConditionalLink/ConditionalLink.test.jsx +0 -30
- package/src/components/manage/MaybeWrap/MaybeWrap.jsx +0 -9
- package/src/components/manage/UniversalLink/UniversalLink.jsx +0 -154
- package/src/components/manage/Widgets/FileWidget.test.jsx +0 -91
|
@@ -8,12 +8,23 @@ import Display from './Display';
|
|
|
8
8
|
|
|
9
9
|
const mockStore = configureStore();
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
)
|
|
11
|
+
vi.mock('@plone/volto/components/manage/Widgets', async () => {
|
|
12
|
+
return await import(
|
|
13
|
+
'@plone/volto/components/manage/Widgets/__mocks__/index.vitest.tsx'
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
|
|
17
|
+
return await import(
|
|
18
|
+
'@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
beforeAll(async () => {
|
|
23
|
+
const { __setLoadables } = await import(
|
|
24
|
+
'@plone/volto/helpers/Loadable/Loadable'
|
|
25
|
+
);
|
|
26
|
+
await __setLoadables();
|
|
27
|
+
});
|
|
17
28
|
|
|
18
29
|
beforeEach(() => {
|
|
19
30
|
config.views.layoutViewsNamesMapping = {
|
|
@@ -8,9 +8,17 @@ import { __test__ as Edit } from './Edit';
|
|
|
8
8
|
|
|
9
9
|
const mockStore = configureStore();
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
12
|
+
return await import(
|
|
13
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
17
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
18
|
+
}));
|
|
19
|
+
vi.mock('../Sidebar/Sidebar', () => ({
|
|
20
|
+
default: vi.fn(() => <div id="Sidebar" />),
|
|
21
|
+
}));
|
|
14
22
|
|
|
15
23
|
describe('Edit', () => {
|
|
16
24
|
it('renders an empty edit component', () => {
|
|
@@ -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
|
-
|
|
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,11 @@ const mockStore = configureStore();
|
|
|
9
9
|
const errorMessage =
|
|
10
10
|
"[{'message': 'The specified email is not valid.', 'field': 'contact_email', 'error': 'ValidationError'}";
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
13
|
+
return await import(
|
|
14
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
15
|
+
);
|
|
16
|
+
});
|
|
13
17
|
|
|
14
18
|
describe('Form', () => {
|
|
15
19
|
it('renders a form component', () => {
|
|
@@ -6,7 +6,11 @@ import config from '@plone/volto/registry';
|
|
|
6
6
|
|
|
7
7
|
import InlineForm from './InlineForm';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
10
|
+
return await import(
|
|
11
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
12
|
+
);
|
|
13
|
+
});
|
|
10
14
|
|
|
11
15
|
const mockStore = configureStore();
|
|
12
16
|
|
|
@@ -8,7 +8,11 @@ import ModalForm from './ModalForm';
|
|
|
8
8
|
|
|
9
9
|
const mockStore = configureStore();
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
12
|
+
return await import(
|
|
13
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
14
|
+
);
|
|
15
|
+
});
|
|
12
16
|
|
|
13
17
|
describe('ModalForm', () => {
|
|
14
18
|
it('renders a modal form component', () => {
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/* TODO: When the Volto Team removes Jest configuration support from Volto core, update this file with the Vitest version of the mock.
|
|
2
|
+
Then, in the tests, we need to replace:
|
|
3
|
+
|
|
4
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
5
|
+
return await import(
|
|
6
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
7
|
+
);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
with the following:
|
|
12
|
+
|
|
13
|
+
vi.mock('@plone/volto/components/manage/Form');
|
|
14
|
+
|
|
15
|
+
Finally, remove this comment.
|
|
16
|
+
*/
|
|
17
|
+
|
|
1
18
|
import type { JSONSchema } from '@plone/types';
|
|
2
19
|
import type { Ref } from 'react';
|
|
3
20
|
const { forwardRef } = jest.requireActual('react');
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { JSONSchema } from '@plone/types';
|
|
2
|
+
import type { Ref } from 'react';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
|
|
5
|
+
const cleanupSchema = (schema: JSONSchema | null): JSONSchema | null => {
|
|
6
|
+
if (!schema || !schema.properties) return schema;
|
|
7
|
+
return {
|
|
8
|
+
...schema,
|
|
9
|
+
properties: Object.entries(schema.properties).reduce<Record<string, any>>(
|
|
10
|
+
(acc, [key, value]) => {
|
|
11
|
+
acc[key] = {
|
|
12
|
+
...value,
|
|
13
|
+
description:
|
|
14
|
+
typeof value.description === 'string'
|
|
15
|
+
? value.description
|
|
16
|
+
: undefined,
|
|
17
|
+
};
|
|
18
|
+
return acc;
|
|
19
|
+
},
|
|
20
|
+
{},
|
|
21
|
+
),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Field = vi.fn((props) => (
|
|
26
|
+
<div className="Field" id={props.id}>
|
|
27
|
+
{props.title}
|
|
28
|
+
</div>
|
|
29
|
+
));
|
|
30
|
+
|
|
31
|
+
export const InlineForm = vi.fn((props) => (
|
|
32
|
+
<div
|
|
33
|
+
id="InlineForm"
|
|
34
|
+
data-schema={JSON.stringify(cleanupSchema(props.schema), null, 2)}
|
|
35
|
+
/>
|
|
36
|
+
));
|
|
37
|
+
|
|
38
|
+
export const ModalForm = vi.fn((props) => (
|
|
39
|
+
<div
|
|
40
|
+
id="ModalForm"
|
|
41
|
+
data-schema={JSON.stringify(cleanupSchema(props.schema), null, 2)}
|
|
42
|
+
/>
|
|
43
|
+
));
|
|
44
|
+
|
|
45
|
+
export const UndoToolbar = vi.fn(() => <div id="UndoToolbar" />);
|
|
46
|
+
|
|
47
|
+
export const BlocksToolbar = vi.fn(() => <div id="BlocksToolbar" />);
|
|
48
|
+
|
|
49
|
+
export const BlockDataForm = vi.fn((props) => (
|
|
50
|
+
<div
|
|
51
|
+
id="BlockDataForm"
|
|
52
|
+
data-schema={JSON.stringify(cleanupSchema(props.schema), null, 2)}
|
|
53
|
+
/>
|
|
54
|
+
));
|
|
55
|
+
|
|
56
|
+
export const BlocksForm = vi.fn((props) => (
|
|
57
|
+
<div
|
|
58
|
+
id="BlocksForm"
|
|
59
|
+
data-schema={JSON.stringify(cleanupSchema(props.schema), null, 2)}
|
|
60
|
+
/>
|
|
61
|
+
));
|
|
62
|
+
|
|
63
|
+
const MockForm = forwardRef(
|
|
64
|
+
(props: { schema: JSONSchema | null }, ref: Ref<any>) => (
|
|
65
|
+
<div
|
|
66
|
+
id="Form"
|
|
67
|
+
data-schema={JSON.stringify(cleanupSchema(props.schema), null, 2)}
|
|
68
|
+
ref={ref}
|
|
69
|
+
/>
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
export const Form = vi.fn((props) => <MockForm {...props} />);
|
|
@@ -9,7 +9,9 @@ import FakeTimers from '@sinonjs/fake-timers';
|
|
|
9
9
|
import History from './History';
|
|
10
10
|
|
|
11
11
|
const mockStore = configureStore();
|
|
12
|
-
|
|
12
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
13
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
14
|
+
}));
|
|
13
15
|
|
|
14
16
|
const FIXED_SYSTEM_TIME = '2017-04-23T15:38:00.000Z';
|
|
15
17
|
|
|
@@ -10,10 +10,12 @@ import { __test__ as LinksToItem } from './LinksToItem';
|
|
|
10
10
|
const middlewares = [thunk];
|
|
11
11
|
const mockStore = configureMockStore(middlewares);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
14
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
15
|
+
}));
|
|
16
|
+
vi.mock('../Toolbar/More', () => ({
|
|
17
|
+
default: vi.fn(() => <div className="More" />),
|
|
18
|
+
}));
|
|
17
19
|
describe('LinksToItem', () => {
|
|
18
20
|
it('renders "links and references" view', () => {
|
|
19
21
|
const store = mockStore({
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React, { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
|
|
3
|
+
type MaybeWrapProps<T extends React.ElementType> = {
|
|
4
|
+
condition: boolean;
|
|
5
|
+
as: T;
|
|
6
|
+
} & ComponentPropsWithoutRef<React.ElementType extends T ? 'div' : T>;
|
|
7
|
+
|
|
8
|
+
function MaybeWrap<T extends React.ElementType = 'div'>(
|
|
9
|
+
props: MaybeWrapProps<T>,
|
|
10
|
+
) {
|
|
11
|
+
const { as: Component = 'div', condition, ...rest } = props;
|
|
12
|
+
return condition ? <Component {...rest} /> : props.children;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default MaybeWrap;
|
|
@@ -11,8 +11,9 @@ beforeAll(() => {
|
|
|
11
11
|
config.settings.isMultilingual = true;
|
|
12
12
|
config.settings.supportedLanguages = ['de', 'es'];
|
|
13
13
|
});
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
15
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
16
|
+
}));
|
|
16
17
|
|
|
17
18
|
const mockStore = configureStore();
|
|
18
19
|
|
|
@@ -9,8 +9,15 @@ import ChangePassword from './ChangePassword';
|
|
|
9
9
|
|
|
10
10
|
const mockStore = configureStore();
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
13
|
+
return await import(
|
|
14
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
19
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
20
|
+
}));
|
|
14
21
|
|
|
15
22
|
describe('ChangePassword', () => {
|
|
16
23
|
it('renders a change password component', () => {
|
|
@@ -18,7 +18,9 @@ const userSchema = {
|
|
|
18
18
|
loading: false,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
22
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
23
|
+
}));
|
|
22
24
|
|
|
23
25
|
describe('PersonalInformation', () => {
|
|
24
26
|
it('renders a personal information component', async () => {
|
|
@@ -8,14 +8,27 @@ import PersonalPreferences from './PersonalPreferences';
|
|
|
8
8
|
|
|
9
9
|
const mockStore = configureStore();
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
12
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
13
|
+
}));
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
)
|
|
15
|
+
vi.mock('@plone/volto/components/manage/Form', async () => {
|
|
16
|
+
return await import(
|
|
17
|
+
'@plone/volto/components/manage/Form/__mocks__/index.vitest.tsx'
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
vi.mock('@plone/volto/helpers/Loadable/Loadable', async () => {
|
|
21
|
+
return await import(
|
|
22
|
+
'@plone/volto/helpers/Loadable/__mocks__/Loadable.vitest.jsx'
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
beforeAll(async () => {
|
|
27
|
+
const { __setLoadables } = await import(
|
|
28
|
+
'@plone/volto/helpers/Loadable/Loadable'
|
|
29
|
+
);
|
|
30
|
+
await __setLoadables();
|
|
31
|
+
});
|
|
19
32
|
|
|
20
33
|
describe('PersonalPreferences', () => {
|
|
21
34
|
it('renders a personal preferences component', () => {
|
|
@@ -9,9 +9,12 @@ import Rules from './Rules';
|
|
|
9
9
|
const middlewares = [thunk];
|
|
10
10
|
const mockStore = configureMockStore(middlewares);
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
13
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
14
|
+
}));
|
|
15
|
+
vi.mock('../Toolbar/More', () => ({
|
|
16
|
+
default: vi.fn(() => <div className="More" />),
|
|
17
|
+
}));
|
|
15
18
|
|
|
16
19
|
describe('Rules', () => {
|
|
17
20
|
it('renders rules object control', () => {
|
|
@@ -10,7 +10,9 @@ import Sharing from './Sharing';
|
|
|
10
10
|
|
|
11
11
|
const mockStore = configureStore();
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
vi.mock('../Toolbar/Toolbar', () => ({
|
|
14
|
+
default: vi.fn(() => <div id="Portal" />),
|
|
15
|
+
}));
|
|
14
16
|
|
|
15
17
|
describe('Sharing', () => {
|
|
16
18
|
it('renders a sharing component', () => {
|
|
@@ -110,11 +110,11 @@ describe('ObjectBrowserNav', () => {
|
|
|
110
110
|
const baseProps = {
|
|
111
111
|
currentSearchResults,
|
|
112
112
|
isSelectable: () => true,
|
|
113
|
-
handleClickOnItem:
|
|
114
|
-
handleDoubleClickOnItem:
|
|
113
|
+
handleClickOnItem: vi.fn(),
|
|
114
|
+
handleDoubleClickOnItem: vi.fn(),
|
|
115
115
|
mode: 'link',
|
|
116
116
|
view: 'list',
|
|
117
|
-
navigateTo:
|
|
117
|
+
navigateTo: vi.fn(),
|
|
118
118
|
};
|
|
119
119
|
|
|
120
120
|
it('renders a view image component', () => {
|
|
@@ -6,13 +6,12 @@ import { waitFor, render } from '@testing-library/react';
|
|
|
6
6
|
|
|
7
7
|
import More from './More';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
);
|
|
9
|
+
vi.mock('../../manage/Display/Display', () => ({
|
|
10
|
+
default: vi.fn(() => <div id="display-select" />),
|
|
11
|
+
}));
|
|
12
|
+
vi.mock('../../manage/Workflow/Workflow', () => ({
|
|
13
|
+
default: vi.fn(() => <div id="state-select" />),
|
|
14
|
+
}));
|
|
16
15
|
|
|
17
16
|
const mockStore = configureStore();
|
|
18
17
|
|
|
@@ -4,7 +4,7 @@ import { Provider } from 'react-intl-redux';
|
|
|
4
4
|
import configureStore from 'redux-mock-store';
|
|
5
5
|
import { render } from '@testing-library/react';
|
|
6
6
|
import { MemoryRouter } from 'react-router-dom';
|
|
7
|
-
import UniversalLink from './UniversalLink';
|
|
7
|
+
import UniversalLink, { __test } from './UniversalLink';
|
|
8
8
|
import config from '@plone/volto/registry';
|
|
9
9
|
|
|
10
10
|
const mockStore = configureStore();
|
|
@@ -18,7 +18,7 @@ const store = mockStore({
|
|
|
18
18
|
},
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
global.console.error =
|
|
21
|
+
global.console.error = vi.fn();
|
|
22
22
|
|
|
23
23
|
describe('UniversalLink', () => {
|
|
24
24
|
it('renders a UniversalLink component with internal link', () => {
|
|
@@ -39,7 +39,10 @@ describe('UniversalLink', () => {
|
|
|
39
39
|
const component = renderer.create(
|
|
40
40
|
<Provider store={store}>
|
|
41
41
|
<MemoryRouter>
|
|
42
|
-
<UniversalLink
|
|
42
|
+
<UniversalLink
|
|
43
|
+
href="https://github.com/plone/volto"
|
|
44
|
+
className="custom-link"
|
|
45
|
+
>
|
|
43
46
|
<h1>Title</h1>
|
|
44
47
|
</UniversalLink>
|
|
45
48
|
</MemoryRouter>
|
|
@@ -213,18 +216,197 @@ describe('UniversalLink', () => {
|
|
|
213
216
|
expect(json).toMatchSnapshot();
|
|
214
217
|
expect(global.console.error).toHaveBeenCalled();
|
|
215
218
|
});
|
|
216
|
-
});
|
|
217
219
|
|
|
218
|
-
it('renders a UniversalLink component when url ends with @@display-file', () => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
it('renders a UniversalLink component when url ends with @@display-file', () => {
|
|
221
|
+
const component = renderer.create(
|
|
222
|
+
<Provider store={store}>
|
|
223
|
+
<MemoryRouter>
|
|
224
|
+
<UniversalLink href="http://localhost:3000/en/welcome-to-volto/@@display-file">
|
|
225
|
+
<h1>Title</h1>
|
|
226
|
+
</UniversalLink>
|
|
227
|
+
</MemoryRouter>
|
|
228
|
+
</Provider>,
|
|
229
|
+
);
|
|
230
|
+
const json = component.toJSON();
|
|
231
|
+
expect(json).toMatchSnapshot();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('only one UniversalLink re-renders when prop changes (stable references)', () => {
|
|
235
|
+
const renderCounter = vi.fn();
|
|
236
|
+
__test.renderCounter = renderCounter;
|
|
237
|
+
|
|
238
|
+
const itemA = { '@id': '/en/a' };
|
|
239
|
+
const itemB = { '@id': '/en/b' };
|
|
240
|
+
const itemC = { '@id': '/en/c' };
|
|
241
|
+
|
|
242
|
+
const Wrapper = ({ children }) => (
|
|
243
|
+
<Provider store={store}>
|
|
244
|
+
<MemoryRouter>{children}</MemoryRouter>
|
|
245
|
+
</Provider>
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
const { rerender } = render(
|
|
249
|
+
<>
|
|
250
|
+
<UniversalLink item={itemA} />
|
|
251
|
+
<UniversalLink item={itemB} />
|
|
252
|
+
<UniversalLink item={itemC} />
|
|
253
|
+
</>,
|
|
254
|
+
{ wrapper: Wrapper },
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// expect 3 renders
|
|
258
|
+
expect(renderCounter).toHaveBeenCalledTimes(3);
|
|
259
|
+
|
|
260
|
+
const updatedItemB = { '@id': '/en/b-updated' };
|
|
261
|
+
|
|
262
|
+
rerender(
|
|
263
|
+
<>
|
|
264
|
+
<UniversalLink item={itemA} />
|
|
265
|
+
<UniversalLink item={updatedItemB} />
|
|
266
|
+
<UniversalLink item={itemC} />
|
|
267
|
+
</>,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
// expect 4 renders (only one UniversalLink re-renders)
|
|
271
|
+
expect(renderCounter).toHaveBeenCalledTimes(4);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test('only one UniversalLink re-renders when prop changes (with children - stable references)', () => {
|
|
275
|
+
const renderCounter = vi.fn();
|
|
276
|
+
__test.renderCounter = renderCounter;
|
|
277
|
+
|
|
278
|
+
const itemA = { '@id': '/en/a' };
|
|
279
|
+
const itemB = { '@id': '/en/b' };
|
|
280
|
+
const itemC = { '@id': '/en/c' };
|
|
281
|
+
const title = 'Title';
|
|
282
|
+
|
|
283
|
+
const Wrapper = ({ children }) => (
|
|
284
|
+
<Provider store={store}>
|
|
285
|
+
<MemoryRouter>{children}</MemoryRouter>
|
|
286
|
+
</Provider>
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
const { rerender } = render(
|
|
290
|
+
<>
|
|
291
|
+
<UniversalLink item={itemA}>{title}</UniversalLink>
|
|
292
|
+
<UniversalLink item={itemB}>{title}</UniversalLink>
|
|
293
|
+
<UniversalLink item={itemC}>{title}</UniversalLink>
|
|
294
|
+
</>,
|
|
295
|
+
{ wrapper: Wrapper },
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// expect 3 renders
|
|
299
|
+
expect(renderCounter).toHaveBeenCalledTimes(3);
|
|
300
|
+
|
|
301
|
+
const updatedItemB = { '@id': '/en/b-updated' };
|
|
302
|
+
|
|
303
|
+
rerender(
|
|
304
|
+
<>
|
|
305
|
+
<UniversalLink item={itemA}>{title}</UniversalLink>
|
|
306
|
+
<UniversalLink item={updatedItemB}>{title}</UniversalLink>
|
|
307
|
+
<UniversalLink item={itemC}>{title}</UniversalLink>
|
|
308
|
+
</>,
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
// expect 4 renders (only one UniversalLink re-renders)
|
|
312
|
+
expect(renderCounter).toHaveBeenCalledTimes(4);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test('[NEGATIVE TEST] UniversalLink re-renders all instances when children are inline JSX (React.memo ineffective)', () => {
|
|
316
|
+
// NEGATIVE TEST:
|
|
317
|
+
// This test demonstrates that React.memo does NOT prevent re-renders
|
|
318
|
+
// when props like `children` are passed as inline JSX.
|
|
319
|
+
// This is expected behavior due to unstable object references.
|
|
320
|
+
// Do NOT use inline props if render optimization is required.
|
|
321
|
+
const renderCounter = vi.fn();
|
|
322
|
+
__test.renderCounter = renderCounter;
|
|
323
|
+
|
|
324
|
+
const itemA = { '@id': '/en/a' };
|
|
325
|
+
const itemB = { '@id': '/en/b' };
|
|
326
|
+
const itemC = { '@id': '/en/c' };
|
|
327
|
+
|
|
328
|
+
const Wrapper = ({ children }) => (
|
|
329
|
+
<Provider store={store}>
|
|
330
|
+
<MemoryRouter>{children}</MemoryRouter>
|
|
331
|
+
</Provider>
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
const { rerender } = render(
|
|
335
|
+
<>
|
|
336
|
+
<UniversalLink item={itemA}>
|
|
337
|
+
<h1>Title</h1>
|
|
338
|
+
</UniversalLink>
|
|
339
|
+
<UniversalLink item={itemB}>
|
|
340
|
+
<h1>Title</h1>
|
|
341
|
+
</UniversalLink>
|
|
342
|
+
<UniversalLink item={itemC}>
|
|
343
|
+
<h1>Title</h1>
|
|
344
|
+
</UniversalLink>
|
|
345
|
+
</>,
|
|
346
|
+
{ wrapper: Wrapper },
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
// expect 3 renders
|
|
350
|
+
expect(renderCounter).toHaveBeenCalledTimes(3);
|
|
351
|
+
|
|
352
|
+
const updatedItemB = { '@id': '/en/b-updated' };
|
|
353
|
+
|
|
354
|
+
rerender(
|
|
355
|
+
<>
|
|
356
|
+
<UniversalLink item={itemA}>
|
|
223
357
|
<h1>Title</h1>
|
|
224
358
|
</UniversalLink>
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
359
|
+
<UniversalLink item={updatedItemB}>
|
|
360
|
+
<h1>Title</h1>
|
|
361
|
+
</UniversalLink>
|
|
362
|
+
<UniversalLink item={itemC}>
|
|
363
|
+
<h1>Title</h1>
|
|
364
|
+
</UniversalLink>
|
|
365
|
+
</>,
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
// expect 6 renders (React.memo does NOT prevent re-renders when props like `children` are passed as inline JSX.)
|
|
369
|
+
expect(renderCounter).toHaveBeenCalledTimes(6);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test('[NEGATIVE TEST] UniversalLink re-renders all instances when props are inline JSX (React.memo ineffective)', () => {
|
|
373
|
+
// NEGATIVE TEST:
|
|
374
|
+
// This test demonstrates that React.memo does NOT prevent re-renders
|
|
375
|
+
// when props like `item` are passed as inline object.
|
|
376
|
+
// This is expected behavior due to unstable object references.
|
|
377
|
+
// Do NOT use inline props if render optimization is required.
|
|
378
|
+
const renderCounter = vi.fn();
|
|
379
|
+
__test.renderCounter = renderCounter;
|
|
380
|
+
|
|
381
|
+
const title = 'Title';
|
|
382
|
+
|
|
383
|
+
const Wrapper = ({ children }) => (
|
|
384
|
+
<Provider store={store}>
|
|
385
|
+
<MemoryRouter>{children}</MemoryRouter>
|
|
386
|
+
</Provider>
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const { rerender } = render(
|
|
390
|
+
<>
|
|
391
|
+
<UniversalLink item={{ '@id': '/en/a' }}>{title}</UniversalLink>
|
|
392
|
+
<UniversalLink item={{ '@id': '/en/b' }}>{title}</UniversalLink>
|
|
393
|
+
<UniversalLink item={{ '@id': '/en/c' }}>{title}</UniversalLink>
|
|
394
|
+
</>,
|
|
395
|
+
{ wrapper: Wrapper },
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
// expect 3 renders
|
|
399
|
+
expect(renderCounter).toHaveBeenCalledTimes(3);
|
|
400
|
+
|
|
401
|
+
rerender(
|
|
402
|
+
<>
|
|
403
|
+
<UniversalLink item={{ '@id': '/en/a' }}>{title}</UniversalLink>
|
|
404
|
+
<UniversalLink item={{ '@id': '/en/b' }}>{title}</UniversalLink>
|
|
405
|
+
<UniversalLink item={{ '@id': '/en/c' }}>{title}</UniversalLink>
|
|
406
|
+
</>,
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
// expect 6 renders (React.memo does NOT prevent re-renders when props like `children` are passed as inline JSX.)
|
|
410
|
+
expect(renderCounter).toHaveBeenCalledTimes(6);
|
|
411
|
+
});
|
|
230
412
|
});
|