@capillarytech/creatives-library 9.0.26 → 9.0.29-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/constants/unified.js +29 -0
- package/global-styles.js +1 -1
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/commonUtils.js +22 -1
- package/utils/rcsPayloadUtils.js +102 -0
- package/utils/templateVarUtils.js +198 -0
- package/utils/tests/rcsPayloadUtils.test.js +295 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +21 -1
- package/v2Components/CapActionButton/index.js +260 -144
- package/v2Components/CapActionButton/index.scss +245 -14
- package/v2Components/CapActionButton/messages.js +32 -3
- package/v2Components/CapActionButton/tests/index.test.js +74 -19
- package/v2Components/CapImageUpload/index.js +2 -2
- package/v2Components/CapTagList/index.js +9 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +58 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +186 -22
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +381 -80
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +35 -2
- package/v2Components/CommonTestAndPreview/index.js +770 -231
- package/v2Components/CommonTestAndPreview/messages.js +45 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +25 -6
- package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +1 -0
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +412 -257
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +337 -63
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +108 -15
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
- package/v2Components/CommonTestAndPreview/tests/utils.test.js +151 -0
- package/v2Components/CommonTestAndPreview/utils.js +84 -0
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +94 -0
- package/v2Components/SmsFallback/index.js +958 -0
- package/v2Components/SmsFallback/index.scss +266 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +120 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +208 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +471 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +45 -25
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +147 -32
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
- package/v2Components/TestAndPreviewSlidebox/index.js +13 -1
- package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +27 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +37 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
- package/v2Containers/CreativesContainer/constants.js +11 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +77 -0
- package/v2Containers/CreativesContainer/index.js +328 -106
- package/v2Containers/CreativesContainer/index.scss +102 -1
- package/v2Containers/CreativesContainer/tests/CreativesSlideBoxWrapper.test.js +58 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.smsDltPreview.test.js +73 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +37 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +103 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +193 -15
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +88 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +549 -57
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/Email/index.js +3 -54
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +4 -9
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/carouselUtils.js +224 -0
- package/v2Containers/Rcs/components/CarouselCard.js +317 -0
- package/v2Containers/Rcs/components/CarouselCardButtons.js +113 -0
- package/v2Containers/Rcs/components/CarouselCardMedia.js +136 -0
- package/v2Containers/Rcs/components/CarouselCharacterCount.js +31 -0
- package/v2Containers/Rcs/components/CarouselDimensionSelection.js +80 -0
- package/v2Containers/Rcs/constants.js +132 -16
- package/v2Containers/Rcs/index.js +1808 -949
- package/v2Containers/Rcs/index.scss +443 -8
- package/v2Containers/Rcs/messages.js +45 -22
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +484 -0
- package/v2Containers/Rcs/tests/CarouselCard.test.js +464 -0
- package/v2Containers/Rcs/tests/CarouselCardButtons.test.js +211 -0
- package/v2Containers/Rcs/tests/CarouselCardMedia.test.js +160 -0
- package/v2Containers/Rcs/tests/CarouselCharacterCount.test.js +50 -0
- package/v2Containers/Rcs/tests/CarouselDimensionSelection.test.js +119 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +74176 -39409
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +10 -74
- package/v2Containers/Rcs/tests/carouselUtils.test.js +916 -0
- package/v2Containers/Rcs/tests/index.test.js +219 -40
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +873 -0
- package/v2Containers/Rcs/tests/utils.test.js +682 -30
- package/v2Containers/Rcs/utils.js +514 -12
- package/v2Containers/Sms/Create/index.js +115 -48
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +678 -169
- package/v2Containers/SmsTrai/Edit/index.scss +126 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +5 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +196 -12
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +131 -59
- package/v2Containers/Templates/sagas.js +57 -13
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +129 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
- package/v2Containers/Templates/tests/sagas.test.js +199 -16
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +88 -25
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
|
@@ -1,83 +1,108 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for CustomValuesEditor component.
|
|
3
|
-
* Covers: loading state, values-missing warning, JSON view, tag table, discard/update buttons.
|
|
4
2
|
* @jest-environment jsdom
|
|
5
3
|
*/
|
|
6
|
-
|
|
7
4
|
import React from 'react';
|
|
8
5
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
9
7
|
import { IntlProvider } from 'react-intl';
|
|
10
8
|
import PropTypes from 'prop-types';
|
|
9
|
+
import CustomValuesEditor from '../CustomValuesEditor';
|
|
11
10
|
|
|
12
|
-
jest.mock('@capillarytech/cap-ui-library/CapRow', () =>
|
|
13
|
-
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
)
|
|
18
|
-
jest.mock('@capillarytech/cap-ui-library/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
data-testid
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
11
|
+
jest.mock('@capillarytech/cap-ui-library/CapRow', () => {
|
|
12
|
+
const React = require('react');
|
|
13
|
+
return function CapRow(props) {
|
|
14
|
+
return React.createElement('div', { className: props?.className, 'data-testid': 'cap-row' }, props?.children);
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
jest.mock('@capillarytech/cap-ui-library/CapSpin', () => {
|
|
18
|
+
const React = require('react');
|
|
19
|
+
return function CapSpin() {
|
|
20
|
+
return React.createElement('div', { 'data-testid': 'cap-spin' }, 'spin');
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
jest.mock('@capillarytech/cap-ui-library/CapSwitch', () => {
|
|
24
|
+
const React = require('react');
|
|
25
|
+
return function CapSwitch(props) {
|
|
26
|
+
return React.createElement('input', {
|
|
27
|
+
type: 'checkbox',
|
|
28
|
+
'data-testid': 'json-switch',
|
|
29
|
+
checked: props?.checked,
|
|
30
|
+
onChange: (e) => props?.onChange?.(e.target.checked),
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
jest.mock('@capillarytech/cap-ui-library/CapButton', () => {
|
|
35
|
+
const React = require('react');
|
|
36
|
+
return function CapButton(props) {
|
|
37
|
+
return React.createElement('button', {
|
|
38
|
+
type: 'button',
|
|
39
|
+
'data-testid': 'cap-button',
|
|
40
|
+
onClick: props?.onClick,
|
|
41
|
+
disabled: props?.disabled,
|
|
42
|
+
'data-loading': props?.loading,
|
|
43
|
+
}, props?.children);
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
jest.mock('@capillarytech/cap-ui-library/CapInput', () => {
|
|
47
|
+
const React = require('react');
|
|
48
|
+
return function CapInput(props) {
|
|
49
|
+
return React.createElement('input', {
|
|
50
|
+
'data-testid': 'tag-input',
|
|
51
|
+
value: props?.value,
|
|
52
|
+
placeholder: props?.placeholder,
|
|
53
|
+
onChange: props?.onChange,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
jest.mock('@capillarytech/cap-ui-library/CapLabel', () => {
|
|
58
|
+
const React = require('react');
|
|
59
|
+
return function CapLabel(props) {
|
|
60
|
+
return React.createElement('div', { className: props?.className, 'data-testid': 'cap-label' }, props?.children);
|
|
61
|
+
};
|
|
62
|
+
});
|
|
53
63
|
|
|
54
|
-
|
|
64
|
+
const formatMessage = (msg) => (typeof msg === 'object' && msg?.id ? msg.id : String(msg));
|
|
55
65
|
|
|
56
|
-
const
|
|
66
|
+
const baseProps = {
|
|
57
67
|
isExtractingTags: false,
|
|
58
68
|
isUpdatePreviewDisabled: false,
|
|
59
69
|
showJSON: false,
|
|
60
70
|
setShowJSON: jest.fn(),
|
|
61
|
-
customValues: { '
|
|
71
|
+
customValues: { 'tag.a': 'v1' },
|
|
62
72
|
handleJSONTextChange: jest.fn(),
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
73
|
+
sections: [
|
|
74
|
+
{
|
|
75
|
+
key: 'sec1',
|
|
76
|
+
title: 'Section A',
|
|
77
|
+
requiredTags: [{ fullPath: 'tag.a', name: 'a' }],
|
|
78
|
+
optionalTags: [{ fullPath: 'tag.b', name: 'b' }],
|
|
79
|
+
},
|
|
66
80
|
],
|
|
67
|
-
requiredTags: [{ fullPath: '{{customer.name}}' }],
|
|
68
|
-
optionalTags: [{ fullPath: '{{customer.email}}' }],
|
|
69
81
|
handleCustomValueChange: jest.fn(),
|
|
70
82
|
handleDiscardCustomValues: jest.fn(),
|
|
71
83
|
handleUpdatePreview: jest.fn(),
|
|
72
84
|
isUpdatingPreview: false,
|
|
73
|
-
formatMessage
|
|
85
|
+
formatMessage,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const defaultProps = {
|
|
89
|
+
...baseProps,
|
|
90
|
+
customValues: {},
|
|
91
|
+
sections: [
|
|
92
|
+
{
|
|
93
|
+
key: 'default-sec',
|
|
94
|
+
title: 'Section',
|
|
95
|
+
requiredTags: [{ fullPath: '{{customer.name}}', name: 'customer.name' }],
|
|
96
|
+
optionalTags: [{ fullPath: '{{customer.email}}', name: 'customer.email' }],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
74
99
|
};
|
|
75
100
|
|
|
76
101
|
// IntlProvider wrapper for incoming tests
|
|
77
102
|
const scope = 'app.v2Components.TestAndPreviewSlidebox';
|
|
78
103
|
const mockMessages = {
|
|
79
104
|
[`${scope}.extractingTags`]: 'Extracting tags...',
|
|
80
|
-
[`${scope}.valuesMissing`]: '
|
|
105
|
+
[`${scope}.valuesMissing`]: 'Some values are missing',
|
|
81
106
|
[`${scope}.showJSON`]: 'Show JSON',
|
|
82
107
|
[`${scope}.personalizationTags`]: 'Personalization Tags',
|
|
83
108
|
[`${scope}.customValues`]: 'Custom Values',
|
|
@@ -97,118 +122,128 @@ TestWrapper.propTypes = {
|
|
|
97
122
|
};
|
|
98
123
|
|
|
99
124
|
describe('CustomValuesEditor', () => {
|
|
100
|
-
beforeEach(() =>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
it('renders a spinner and extracting-tags message when isExtractingTags is true', () => {
|
|
104
|
-
render(
|
|
105
|
-
<TestWrapper>
|
|
106
|
-
<CustomValuesEditor {...defaultProps} isExtractingTags />
|
|
107
|
-
</TestWrapper>
|
|
108
|
-
);
|
|
109
|
-
expect(screen.getByTestId('cap-spin')).toBeTruthy();
|
|
110
|
-
expect(screen.getByText('Extracting tags...')).toBeTruthy();
|
|
111
|
-
});
|
|
125
|
+
beforeEach(() => {
|
|
126
|
+
jest.clearAllMocks();
|
|
127
|
+
});
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
129
|
+
it('shows loading state when isExtractingTags', () => {
|
|
130
|
+
render(
|
|
131
|
+
<IntlProvider locale="en" messages={{}}>
|
|
132
|
+
<CustomValuesEditor {...baseProps} isExtractingTags />
|
|
133
|
+
</IntlProvider>,
|
|
134
|
+
);
|
|
135
|
+
expect(screen.getByTestId('cap-spin')).toBeInTheDocument();
|
|
136
|
+
});
|
|
122
137
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
expect(screen.getByTestId('cap-switch')).toBeTruthy();
|
|
131
|
-
});
|
|
138
|
+
it('shows values missing label when isUpdatePreviewDisabled', () => {
|
|
139
|
+
render(
|
|
140
|
+
<IntlProvider locale="en" messages={{}}>
|
|
141
|
+
<CustomValuesEditor {...baseProps} isUpdatePreviewDisabled />
|
|
142
|
+
</IntlProvider>,
|
|
143
|
+
);
|
|
144
|
+
expect(document.querySelector('.values-missing-message')).toBeTruthy();
|
|
132
145
|
});
|
|
133
146
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
147
|
+
it('toggles JSON mode and calls setShowJSON', () => {
|
|
148
|
+
const setShowJSON = jest.fn();
|
|
149
|
+
render(
|
|
150
|
+
<IntlProvider locale="en" messages={{}}>
|
|
151
|
+
<CustomValuesEditor {...baseProps} setShowJSON={setShowJSON} />
|
|
152
|
+
</IntlProvider>,
|
|
153
|
+
);
|
|
154
|
+
fireEvent.click(screen.getByTestId('json-switch'));
|
|
155
|
+
expect(setShowJSON).toHaveBeenCalled();
|
|
156
|
+
});
|
|
143
157
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
158
|
+
it('renders JSON textarea and fires handleJSONTextChange', () => {
|
|
159
|
+
render(
|
|
160
|
+
<IntlProvider locale="en" messages={{}}>
|
|
161
|
+
<CustomValuesEditor {...baseProps} showJSON />
|
|
162
|
+
</IntlProvider>,
|
|
163
|
+
);
|
|
164
|
+
const ta = document.querySelector('.json-textarea');
|
|
165
|
+
expect(ta).toBeTruthy();
|
|
166
|
+
fireEvent.change(ta, { target: { value: '{}' } });
|
|
167
|
+
expect(baseProps.handleJSONTextChange).toHaveBeenCalledWith('{}');
|
|
154
168
|
});
|
|
155
169
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
170
|
+
it('renders required and optional tag inputs when not JSON', () => {
|
|
171
|
+
render(
|
|
172
|
+
<IntlProvider locale="en" messages={{}}>
|
|
173
|
+
<CustomValuesEditor {...baseProps} />
|
|
174
|
+
</IntlProvider>,
|
|
175
|
+
);
|
|
176
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
177
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
178
|
+
fireEvent.change(inputs[0], { target: { value: 'new' } });
|
|
179
|
+
expect(baseProps.handleCustomValueChange).toHaveBeenCalledWith('tag.a', 'new');
|
|
180
|
+
});
|
|
168
181
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
it('calls discard and update handlers', () => {
|
|
183
|
+
render(
|
|
184
|
+
<IntlProvider locale="en" messages={{}}>
|
|
185
|
+
<CustomValuesEditor {...baseProps} />
|
|
186
|
+
</IntlProvider>,
|
|
187
|
+
);
|
|
188
|
+
const buttons = screen.getAllByTestId('cap-button');
|
|
189
|
+
fireEvent.click(buttons[0]);
|
|
190
|
+
fireEvent.click(buttons[buttons.length - 1]);
|
|
191
|
+
expect(baseProps.handleDiscardCustomValues).toHaveBeenCalled();
|
|
192
|
+
expect(baseProps.handleUpdatePreview).toHaveBeenCalled();
|
|
193
|
+
});
|
|
180
194
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
it('skips sections with no tags', () => {
|
|
196
|
+
render(
|
|
197
|
+
<IntlProvider locale="en" messages={{}}>
|
|
198
|
+
<CustomValuesEditor
|
|
199
|
+
{...baseProps}
|
|
200
|
+
sections={[
|
|
201
|
+
{ key: 'empty', requiredTags: [], optionalTags: [] },
|
|
202
|
+
baseProps.sections[0],
|
|
203
|
+
]}
|
|
204
|
+
/>
|
|
205
|
+
</IntlProvider>,
|
|
206
|
+
);
|
|
207
|
+
expect(screen.getAllByTestId('tag-input').length).toBeGreaterThan(0);
|
|
208
|
+
});
|
|
191
209
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
210
|
+
it('renders section title as FormattedMessage when title is an intl message object (not a string)', () => {
|
|
211
|
+
render(
|
|
212
|
+
<IntlProvider locale="en" messages={{ 'section.title.id': 'Intl Section Title' }}>
|
|
213
|
+
<CustomValuesEditor
|
|
214
|
+
{...baseProps}
|
|
215
|
+
sections={[
|
|
216
|
+
{
|
|
217
|
+
key: 'intl-sec',
|
|
218
|
+
title: { id: 'section.title.id', defaultMessage: 'Intl Section Title' },
|
|
219
|
+
requiredTags: [{ fullPath: 'tag.a', name: 'a' }],
|
|
220
|
+
optionalTags: [],
|
|
221
|
+
},
|
|
222
|
+
]}
|
|
223
|
+
/>
|
|
224
|
+
</IntlProvider>,
|
|
225
|
+
);
|
|
226
|
+
expect(screen.getByText('Intl Section Title')).toBeInTheDocument();
|
|
200
227
|
});
|
|
201
228
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
229
|
+
it('renders section title as plain text when title is a string', () => {
|
|
230
|
+
render(
|
|
231
|
+
<IntlProvider locale="en" messages={{}}>
|
|
232
|
+
<CustomValuesEditor
|
|
233
|
+
{...baseProps}
|
|
234
|
+
sections={[
|
|
235
|
+
{
|
|
236
|
+
key: 'str-sec',
|
|
237
|
+
title: 'Plain String Title',
|
|
238
|
+
requiredTags: [{ fullPath: 'tag.a', name: 'a' }],
|
|
239
|
+
optionalTags: [],
|
|
240
|
+
},
|
|
241
|
+
]}
|
|
242
|
+
/>
|
|
243
|
+
</IntlProvider>,
|
|
244
|
+
);
|
|
245
|
+
expect(screen.getByText('Plain String Title')).toBeInTheDocument();
|
|
246
|
+
});
|
|
212
247
|
|
|
213
248
|
it('renders required tags with a required indicator (*)', () => {
|
|
214
249
|
render(
|
|
@@ -239,124 +274,244 @@ describe('CustomValuesEditor', () => {
|
|
|
239
274
|
expect(screen.getByText('{{customer.email}}')).toBeTruthy();
|
|
240
275
|
});
|
|
241
276
|
|
|
242
|
-
it('
|
|
243
|
-
render(
|
|
244
|
-
<TestWrapper>
|
|
245
|
-
<CustomValuesEditor
|
|
246
|
-
{...defaultProps}
|
|
247
|
-
showJSON={false}
|
|
248
|
-
extractedTags={[]}
|
|
249
|
-
requiredTags={[]}
|
|
250
|
-
optionalTags={[]}
|
|
251
|
-
/>
|
|
252
|
-
</TestWrapper>
|
|
253
|
-
);
|
|
254
|
-
expect(screen.queryByText('Personalization Tags')).toBeNull();
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('calls handleCustomValueChange with the tag path and new value for required tags', () => {
|
|
277
|
+
it('calls handleCustomValueChange with the optional tag key when its input changes', () => {
|
|
258
278
|
render(
|
|
259
279
|
<TestWrapper>
|
|
260
280
|
<CustomValuesEditor {...defaultProps} showJSON={false} />
|
|
261
281
|
</TestWrapper>
|
|
262
282
|
);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
283
|
+
// requiredTags render before optionalTags, so the optional tag is the second input.
|
|
284
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
285
|
+
fireEvent.change(inputs[1], { target: { value: 'someone@test.com' } });
|
|
286
|
+
expect(defaultProps.handleCustomValueChange).toHaveBeenCalledWith('{{customer.email}}', 'someone@test.com');
|
|
266
287
|
});
|
|
267
288
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
289
|
+
it('uses empty string as column label when both fullPath and name are absent', () => {
|
|
290
|
+
render(
|
|
291
|
+
<IntlProvider locale="en" messages={{}}>
|
|
292
|
+
<CustomValuesEditor
|
|
293
|
+
{...baseProps}
|
|
294
|
+
sections={[
|
|
295
|
+
{
|
|
296
|
+
key: 'no-label',
|
|
297
|
+
title: 'Section',
|
|
298
|
+
requiredTags: [{}],
|
|
299
|
+
optionalTags: [],
|
|
300
|
+
},
|
|
301
|
+
]}
|
|
302
|
+
/>
|
|
303
|
+
</IntlProvider>,
|
|
304
|
+
);
|
|
305
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
306
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
281
307
|
});
|
|
282
308
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
<
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
309
|
+
it('renders optional-only section (no requiredTags) correctly', () => {
|
|
310
|
+
render(
|
|
311
|
+
<IntlProvider locale="en" messages={{}}>
|
|
312
|
+
<CustomValuesEditor
|
|
313
|
+
{...baseProps}
|
|
314
|
+
sections={[
|
|
315
|
+
{
|
|
316
|
+
key: 'optional-only',
|
|
317
|
+
title: 'Optional Section',
|
|
318
|
+
requiredTags: [],
|
|
319
|
+
optionalTags: [{ fullPath: 'tag.opt', name: 'opt' }],
|
|
320
|
+
},
|
|
321
|
+
]}
|
|
322
|
+
/>
|
|
323
|
+
</IntlProvider>,
|
|
324
|
+
);
|
|
325
|
+
expect(screen.getByText('Optional Section')).toBeInTheDocument();
|
|
326
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
327
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
328
|
+
});
|
|
293
329
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
330
|
+
it('renders required-only section (no optionalTags) correctly', () => {
|
|
331
|
+
render(
|
|
332
|
+
<IntlProvider locale="en" messages={{}}>
|
|
333
|
+
<CustomValuesEditor
|
|
334
|
+
{...baseProps}
|
|
335
|
+
sections={[
|
|
336
|
+
{
|
|
337
|
+
key: 'required-only',
|
|
338
|
+
title: 'Required Section',
|
|
339
|
+
requiredTags: [{ fullPath: 'tag.req', name: 'req' }],
|
|
340
|
+
optionalTags: [],
|
|
341
|
+
},
|
|
342
|
+
]}
|
|
343
|
+
/>
|
|
344
|
+
</IntlProvider>,
|
|
345
|
+
);
|
|
346
|
+
expect(screen.getByText('Required Section')).toBeInTheDocument();
|
|
347
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
348
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
303
349
|
});
|
|
304
350
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
351
|
+
it('renders line numbers in JSON mode matching JSON line count', () => {
|
|
352
|
+
const multiValueCustomValues = { a: 'val1', b: 'val2', c: 'val3' };
|
|
353
|
+
render(
|
|
354
|
+
<IntlProvider locale="en" messages={{}}>
|
|
355
|
+
<CustomValuesEditor
|
|
356
|
+
{...baseProps}
|
|
357
|
+
showJSON
|
|
358
|
+
customValues={multiValueCustomValues}
|
|
359
|
+
/>
|
|
360
|
+
</IntlProvider>,
|
|
361
|
+
);
|
|
362
|
+
const lineNumbers = document.querySelectorAll('.line-number');
|
|
363
|
+
const expectedLineCount = JSON.stringify(multiValueCustomValues, null, 2).split('\n').length;
|
|
364
|
+
expect(lineNumbers.length).toBe(expectedLineCount);
|
|
365
|
+
});
|
|
316
366
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
367
|
+
it('passes fullPath as key for required tag row when fullPath is present', () => {
|
|
368
|
+
const handleChange = jest.fn();
|
|
369
|
+
render(
|
|
370
|
+
<IntlProvider locale="en" messages={{}}>
|
|
371
|
+
<CustomValuesEditor
|
|
372
|
+
{...baseProps}
|
|
373
|
+
sections={[
|
|
374
|
+
{
|
|
375
|
+
key: 'sec',
|
|
376
|
+
title: 'S',
|
|
377
|
+
requiredTags: [{ fullPath: 'my.full.path', name: 'name' }],
|
|
378
|
+
optionalTags: [],
|
|
379
|
+
},
|
|
380
|
+
]}
|
|
381
|
+
handleCustomValueChange={handleChange}
|
|
382
|
+
customValues={{ 'my.full.path': 'existing' }}
|
|
383
|
+
/>
|
|
384
|
+
</IntlProvider>,
|
|
385
|
+
);
|
|
386
|
+
const input = screen.getByTestId('tag-input');
|
|
387
|
+
expect(input.value).toBe('existing');
|
|
388
|
+
fireEvent.change(input, { target: { value: 'updated' } });
|
|
389
|
+
expect(handleChange).toHaveBeenCalledWith('my.full.path', 'updated');
|
|
390
|
+
});
|
|
327
391
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
});
|
|
392
|
+
it('renders no sections when sections is undefined (sections || [] fallback)', () => {
|
|
393
|
+
render(
|
|
394
|
+
<IntlProvider locale="en" messages={{}}>
|
|
395
|
+
<CustomValuesEditor {...baseProps} sections={undefined} />
|
|
396
|
+
</IntlProvider>,
|
|
397
|
+
);
|
|
398
|
+
expect(screen.queryAllByTestId('tag-input').length).toBe(0);
|
|
399
|
+
});
|
|
337
400
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
401
|
+
it('falls back to title.id for the section key when key is absent but title is a message descriptor', () => {
|
|
402
|
+
render(
|
|
403
|
+
<IntlProvider locale="en" messages={{ 'title.id.value': 'Descriptor Title' }}>
|
|
404
|
+
<CustomValuesEditor
|
|
405
|
+
{...baseProps}
|
|
406
|
+
sections={[
|
|
407
|
+
{
|
|
408
|
+
title: { id: 'title.id.value', defaultMessage: 'Descriptor Title' },
|
|
409
|
+
requiredTags: [{ fullPath: 'tag.x', name: 'x' }],
|
|
410
|
+
optionalTags: [],
|
|
411
|
+
},
|
|
412
|
+
]}
|
|
413
|
+
/>
|
|
414
|
+
</IntlProvider>,
|
|
415
|
+
);
|
|
416
|
+
expect(screen.getByText('Descriptor Title')).toBeInTheDocument();
|
|
417
|
+
});
|
|
347
418
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
419
|
+
it('falls back to the title string for the section key when key is absent and title has no id', () => {
|
|
420
|
+
render(
|
|
421
|
+
<IntlProvider locale="en" messages={{}}>
|
|
422
|
+
<CustomValuesEditor
|
|
423
|
+
{...baseProps}
|
|
424
|
+
sections={[
|
|
425
|
+
{
|
|
426
|
+
title: 'Keyless Section Title',
|
|
427
|
+
requiredTags: [{ fullPath: 'tag.y', name: 'y' }],
|
|
428
|
+
optionalTags: [],
|
|
429
|
+
},
|
|
430
|
+
]}
|
|
431
|
+
/>
|
|
432
|
+
</IntlProvider>,
|
|
433
|
+
);
|
|
434
|
+
expect(screen.getByText('Keyless Section Title')).toBeInTheDocument();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('falls back to the fallback constant key and renders no title label when key and title are both absent', () => {
|
|
438
|
+
render(
|
|
439
|
+
<IntlProvider locale="en" messages={{}}>
|
|
440
|
+
<CustomValuesEditor
|
|
441
|
+
{...baseProps}
|
|
442
|
+
sections={[
|
|
443
|
+
{
|
|
444
|
+
requiredTags: [{ fullPath: 'tag.z', name: 'z' }],
|
|
445
|
+
optionalTags: [],
|
|
446
|
+
},
|
|
447
|
+
]}
|
|
448
|
+
/>
|
|
449
|
+
</IntlProvider>,
|
|
450
|
+
);
|
|
451
|
+
const sectionTitleLabels = screen.queryAllByTestId('cap-label')
|
|
452
|
+
.filter((el) => el.className === 'tags-section-title');
|
|
453
|
+
expect(sectionTitleLabels.length).toBe(0);
|
|
454
|
+
expect(screen.getAllByTestId('tag-input').length).toBeGreaterThan(0);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
it('falls back to an empty array when requiredTags key is absent from the section', () => {
|
|
458
|
+
render(
|
|
459
|
+
<IntlProvider locale="en" messages={{}}>
|
|
460
|
+
<CustomValuesEditor
|
|
461
|
+
{...baseProps}
|
|
462
|
+
sections={[
|
|
463
|
+
{
|
|
464
|
+
key: 'no-required-tags-key',
|
|
465
|
+
title: 'No RequiredTags Key',
|
|
466
|
+
optionalTags: [{ fullPath: 'tag.opt-only', name: 'opt-only' }],
|
|
467
|
+
},
|
|
468
|
+
]}
|
|
469
|
+
/>
|
|
470
|
+
</IntlProvider>,
|
|
471
|
+
);
|
|
472
|
+
expect(screen.getByText('No RequiredTags Key')).toBeInTheDocument();
|
|
473
|
+
expect(screen.getAllByTestId('tag-input').length).toBe(1);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('falls back to an empty array when optionalTags key is absent from the section', () => {
|
|
477
|
+
render(
|
|
478
|
+
<IntlProvider locale="en" messages={{}}>
|
|
479
|
+
<CustomValuesEditor
|
|
480
|
+
{...baseProps}
|
|
481
|
+
sections={[
|
|
482
|
+
{
|
|
483
|
+
key: 'no-optional-tags-key',
|
|
484
|
+
title: 'No OptionalTags Key',
|
|
485
|
+
requiredTags: [{ fullPath: 'tag.req-only', name: 'req-only' }],
|
|
486
|
+
},
|
|
487
|
+
]}
|
|
488
|
+
/>
|
|
489
|
+
</IntlProvider>,
|
|
490
|
+
);
|
|
491
|
+
expect(screen.getByText('No OptionalTags Key')).toBeInTheDocument();
|
|
492
|
+
expect(screen.getAllByTestId('tag-input').length).toBe(1);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it('uses an index-based fallback key for optional tag rows when fullPath is absent', () => {
|
|
496
|
+
const handleChange = jest.fn();
|
|
497
|
+
render(
|
|
498
|
+
<IntlProvider locale="en" messages={{}}>
|
|
499
|
+
<CustomValuesEditor
|
|
500
|
+
{...baseProps}
|
|
501
|
+
sections={[
|
|
502
|
+
{
|
|
503
|
+
key: 'opt-no-fullpath',
|
|
504
|
+
title: 'Optional No FullPath',
|
|
505
|
+
requiredTags: [],
|
|
506
|
+
optionalTags: [{ name: 'noPathOpt' }],
|
|
507
|
+
},
|
|
508
|
+
]}
|
|
509
|
+
handleCustomValueChange={handleChange}
|
|
510
|
+
/>
|
|
511
|
+
</IntlProvider>,
|
|
512
|
+
);
|
|
513
|
+
const input = screen.getByTestId('tag-input');
|
|
514
|
+
fireEvent.change(input, { target: { value: 'val' } });
|
|
515
|
+
expect(handleChange).toHaveBeenCalledWith('optional-0', 'val');
|
|
361
516
|
});
|
|
362
517
|
});
|