@capillarytech/creatives-library 8.0.345-alpha.13 → 8.0.345-alpha.15
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/package.json +1 -1
- package/services/api.js +0 -20
- package/services/tests/api.test.js +13 -59
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +167 -109
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapCustomSkeleton/index.js +1 -1
- package/v2Components/CapCustomSkeleton/tests/__snapshots__/index.test.js.snap +12 -12
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +207 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +160 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +18 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +341 -76
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -2
- package/v2Components/CommonTestAndPreview/index.js +676 -186
- package/v2Components/CommonTestAndPreview/messages.js +49 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +15 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +308 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
- 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 +34 -13
- 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 +132 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
- package/v2Components/FormBuilder/index.js +8 -10
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +955 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +118 -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 +197 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +277 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +33 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -28
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- 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/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +11 -4
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
- package/v2Containers/CreativesContainer/index.js +300 -108
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/messages.js +0 -4
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +78 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +357 -98
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -18
- 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/Rcs/constants.js +119 -8
- package/v2Containers/Rcs/index.js +2379 -807
- package/v2Containers/Rcs/index.js.rej +1336 -0
- package/v2Containers/Rcs/index.scss +276 -6
- package/v2Containers/Rcs/index.scss.rej +74 -0
- package/v2Containers/Rcs/messages.js +38 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98018 -70073
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +128 -0
- package/v2Containers/Rcs/tests/index.test.js +152 -121
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
- package/v2Containers/Rcs/tests/utils.test.js +646 -30
- package/v2Containers/Rcs/utils.js +478 -11
- package/v2Containers/Sms/Create/index.js +100 -40
- 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 +636 -130
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4328 -2375
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +6 -0
- package/v2Containers/Templates/ChannelTypeIllustration.js +6 -23
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +181 -126
- package/v2Containers/Templates/actions.js +11 -36
- package/v2Containers/Templates/constants.js +2 -23
- package/v2Containers/Templates/index.js +142 -333
- package/v2Containers/Templates/messages.js +0 -68
- package/v2Containers/Templates/reducer.js +0 -68
- package/v2Containers/Templates/sagas.js +55 -98
- package/v2Containers/Templates/selectors.js +0 -12
- package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +0 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1042 -1256
- package/v2Containers/Templates/tests/index.test.js +0 -6
- package/v2Containers/Templates/tests/reducer.test.js +0 -178
- package/v2Containers/Templates/tests/sagas.test.js +200 -436
- package/v2Containers/Templates/tests/selector.test.js +0 -32
- 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 +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
- package/v2Containers/Assets/images/archive_Empty_Illustration.svg +0 -9
|
@@ -1,83 +1,95 @@
|
|
|
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,
|
|
74
86
|
};
|
|
75
87
|
|
|
76
88
|
// IntlProvider wrapper for incoming tests
|
|
77
89
|
const scope = 'app.v2Components.TestAndPreviewSlidebox';
|
|
78
90
|
const mockMessages = {
|
|
79
91
|
[`${scope}.extractingTags`]: 'Extracting tags...',
|
|
80
|
-
[`${scope}.valuesMissing`]: '
|
|
92
|
+
[`${scope}.valuesMissing`]: 'Some values are missing',
|
|
81
93
|
[`${scope}.showJSON`]: 'Show JSON',
|
|
82
94
|
[`${scope}.personalizationTags`]: 'Personalization Tags',
|
|
83
95
|
[`${scope}.customValues`]: 'Custom Values',
|
|
@@ -97,256 +109,268 @@ TestWrapper.propTypes = {
|
|
|
97
109
|
};
|
|
98
110
|
|
|
99
111
|
describe('CustomValuesEditor', () => {
|
|
100
|
-
beforeEach(() =>
|
|
101
|
-
|
|
102
|
-
describe('loading state (isExtractingTags)', () => {
|
|
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
|
-
});
|
|
112
|
-
|
|
113
|
-
it('does not render the editor toggle when extracting tags', () => {
|
|
114
|
-
render(
|
|
115
|
-
<TestWrapper>
|
|
116
|
-
<CustomValuesEditor {...defaultProps} isExtractingTags />
|
|
117
|
-
</TestWrapper>
|
|
118
|
-
);
|
|
119
|
-
expect(screen.queryByTestId('cap-switch')).toBeNull();
|
|
120
|
-
expect(screen.queryAllByTestId('cap-button')).toHaveLength(0);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('renders the editor (not spinner) when isExtractingTags is false', () => {
|
|
124
|
-
render(
|
|
125
|
-
<TestWrapper>
|
|
126
|
-
<CustomValuesEditor {...defaultProps} isExtractingTags={false} />
|
|
127
|
-
</TestWrapper>
|
|
128
|
-
);
|
|
129
|
-
expect(screen.queryByTestId('cap-spin')).toBeNull();
|
|
130
|
-
expect(screen.getByTestId('cap-switch')).toBeTruthy();
|
|
131
|
-
});
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
jest.clearAllMocks();
|
|
132
114
|
});
|
|
133
115
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
expect(screen.getByText('Values missing for some of the personalization tags')).toBeTruthy();
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('does not show values-missing label when isUpdatePreviewDisabled is false', () => {
|
|
145
|
-
render(
|
|
146
|
-
<TestWrapper>
|
|
147
|
-
<CustomValuesEditor {...defaultProps} isUpdatePreviewDisabled={false} />
|
|
148
|
-
</TestWrapper>
|
|
149
|
-
);
|
|
150
|
-
expect(
|
|
151
|
-
screen.queryByText('Values missing for some of the personalization tags')
|
|
152
|
-
).toBeNull();
|
|
153
|
-
});
|
|
116
|
+
it('shows loading state when isExtractingTags', () => {
|
|
117
|
+
render(
|
|
118
|
+
<IntlProvider locale="en" messages={{}}>
|
|
119
|
+
<CustomValuesEditor {...baseProps} isExtractingTags />
|
|
120
|
+
</IntlProvider>,
|
|
121
|
+
);
|
|
122
|
+
expect(screen.getByTestId('cap-spin')).toBeInTheDocument();
|
|
154
123
|
});
|
|
155
124
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const textarea = document.querySelector('textarea.json-textarea');
|
|
165
|
-
expect(textarea).toBeTruthy();
|
|
166
|
-
expect(textarea.value).toBe(JSON.stringify(customValues, null, 2));
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('renders line numbers matching the number of JSON lines', () => {
|
|
170
|
-
const customValues = { a: 1, b: 2 };
|
|
171
|
-
render(
|
|
172
|
-
<TestWrapper>
|
|
173
|
-
<CustomValuesEditor {...defaultProps} showJSON customValues={customValues} />
|
|
174
|
-
</TestWrapper>
|
|
175
|
-
);
|
|
176
|
-
const lineCount = JSON.stringify(customValues, null, 2).split('\n').length;
|
|
177
|
-
const lineNumbers = document.querySelectorAll('.line-number');
|
|
178
|
-
expect(lineNumbers).toHaveLength(lineCount);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('calls handleJSONTextChange when the textarea value changes', () => {
|
|
182
|
-
render(
|
|
183
|
-
<TestWrapper>
|
|
184
|
-
<CustomValuesEditor {...defaultProps} showJSON />
|
|
185
|
-
</TestWrapper>
|
|
186
|
-
);
|
|
187
|
-
const textarea = document.querySelector('textarea.json-textarea');
|
|
188
|
-
fireEvent.change(textarea, { target: { value: '{"key": "val"}' } });
|
|
189
|
-
expect(defaultProps.handleJSONTextChange).toHaveBeenCalledWith('{"key": "val"}');
|
|
190
|
-
});
|
|
125
|
+
it('shows values missing label when isUpdatePreviewDisabled', () => {
|
|
126
|
+
render(
|
|
127
|
+
<IntlProvider locale="en" messages={{}}>
|
|
128
|
+
<CustomValuesEditor {...baseProps} isUpdatePreviewDisabled />
|
|
129
|
+
</IntlProvider>,
|
|
130
|
+
);
|
|
131
|
+
expect(document.querySelector('.values-missing-message')).toBeTruthy();
|
|
132
|
+
});
|
|
191
133
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
134
|
+
it('toggles JSON mode and calls setShowJSON', () => {
|
|
135
|
+
const setShowJSON = jest.fn();
|
|
136
|
+
render(
|
|
137
|
+
<IntlProvider locale="en" messages={{}}>
|
|
138
|
+
<CustomValuesEditor {...baseProps} setShowJSON={setShowJSON} />
|
|
139
|
+
</IntlProvider>,
|
|
140
|
+
);
|
|
141
|
+
fireEvent.click(screen.getByTestId('json-switch'));
|
|
142
|
+
expect(setShowJSON).toHaveBeenCalled();
|
|
200
143
|
});
|
|
201
144
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
});
|
|
145
|
+
it('renders JSON textarea and fires handleJSONTextChange', () => {
|
|
146
|
+
render(
|
|
147
|
+
<IntlProvider locale="en" messages={{}}>
|
|
148
|
+
<CustomValuesEditor {...baseProps} showJSON />
|
|
149
|
+
</IntlProvider>,
|
|
150
|
+
);
|
|
151
|
+
const ta = document.querySelector('.json-textarea');
|
|
152
|
+
expect(ta).toBeTruthy();
|
|
153
|
+
fireEvent.change(ta, { target: { value: '{}' } });
|
|
154
|
+
expect(baseProps.handleJSONTextChange).toHaveBeenCalledWith('{}');
|
|
155
|
+
});
|
|
212
156
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
});
|
|
157
|
+
it('renders required and optional tag inputs when not JSON', () => {
|
|
158
|
+
render(
|
|
159
|
+
<IntlProvider locale="en" messages={{}}>
|
|
160
|
+
<CustomValuesEditor {...baseProps} />
|
|
161
|
+
</IntlProvider>,
|
|
162
|
+
);
|
|
163
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
164
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
165
|
+
fireEvent.change(inputs[0], { target: { value: 'new' } });
|
|
166
|
+
expect(baseProps.handleCustomValueChange).toHaveBeenCalledWith('tag.a', 'new');
|
|
167
|
+
});
|
|
222
168
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
169
|
+
it('calls discard and update handlers', () => {
|
|
170
|
+
render(
|
|
171
|
+
<IntlProvider locale="en" messages={{}}>
|
|
172
|
+
<CustomValuesEditor {...baseProps} />
|
|
173
|
+
</IntlProvider>,
|
|
174
|
+
);
|
|
175
|
+
const buttons = screen.getAllByTestId('cap-button');
|
|
176
|
+
fireEvent.click(buttons[0]);
|
|
177
|
+
fireEvent.click(buttons[buttons.length - 1]);
|
|
178
|
+
expect(baseProps.handleDiscardCustomValues).toHaveBeenCalled();
|
|
179
|
+
expect(baseProps.handleUpdatePreview).toHaveBeenCalled();
|
|
180
|
+
});
|
|
231
181
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
182
|
+
it('skips sections with no tags', () => {
|
|
183
|
+
render(
|
|
184
|
+
<IntlProvider locale="en" messages={{}}>
|
|
185
|
+
<CustomValuesEditor
|
|
186
|
+
{...baseProps}
|
|
187
|
+
sections={[
|
|
188
|
+
{ key: 'empty', requiredTags: [], optionalTags: [] },
|
|
189
|
+
baseProps.sections[0],
|
|
190
|
+
]}
|
|
191
|
+
/>
|
|
192
|
+
</IntlProvider>,
|
|
193
|
+
);
|
|
194
|
+
expect(screen.getAllByTestId('tag-input').length).toBeGreaterThan(0);
|
|
195
|
+
});
|
|
246
196
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
197
|
+
it('renders section title as FormattedMessage when title is an intl message object (not a string)', () => {
|
|
198
|
+
render(
|
|
199
|
+
<IntlProvider locale="en" messages={{ 'section.title.id': 'Intl Section Title' }}>
|
|
200
|
+
<CustomValuesEditor
|
|
201
|
+
{...baseProps}
|
|
202
|
+
sections={[
|
|
203
|
+
{
|
|
204
|
+
key: 'intl-sec',
|
|
205
|
+
title: { id: 'section.title.id', defaultMessage: 'Intl Section Title' },
|
|
206
|
+
requiredTags: [{ fullPath: 'tag.a', name: 'a' }],
|
|
207
|
+
optionalTags: [],
|
|
208
|
+
},
|
|
209
|
+
]}
|
|
210
|
+
/>
|
|
211
|
+
</IntlProvider>,
|
|
212
|
+
);
|
|
213
|
+
expect(screen.getByText('Intl Section Title')).toBeInTheDocument();
|
|
214
|
+
});
|
|
257
215
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
216
|
+
it('renders section title as plain text when title is a string', () => {
|
|
217
|
+
render(
|
|
218
|
+
<IntlProvider locale="en" messages={{}}>
|
|
219
|
+
<CustomValuesEditor
|
|
220
|
+
{...baseProps}
|
|
221
|
+
sections={[
|
|
222
|
+
{
|
|
223
|
+
key: 'str-sec',
|
|
224
|
+
title: 'Plain String Title',
|
|
225
|
+
requiredTags: [{ fullPath: 'tag.a', name: 'a' }],
|
|
226
|
+
optionalTags: [],
|
|
227
|
+
},
|
|
228
|
+
]}
|
|
229
|
+
/>
|
|
230
|
+
</IntlProvider>,
|
|
231
|
+
);
|
|
232
|
+
expect(screen.getByText('Plain String Title')).toBeInTheDocument();
|
|
271
233
|
});
|
|
272
234
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
<
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
235
|
+
it('renders nothing for section title when title is null (does not crash)', () => {
|
|
236
|
+
render(
|
|
237
|
+
<IntlProvider locale="en" messages={{}}>
|
|
238
|
+
<CustomValuesEditor
|
|
239
|
+
{...baseProps}
|
|
240
|
+
sections={[
|
|
241
|
+
{
|
|
242
|
+
key: 'no-title-sec',
|
|
243
|
+
title: null,
|
|
244
|
+
requiredTags: [{ fullPath: 'tag.a', name: 'a' }],
|
|
245
|
+
optionalTags: [],
|
|
246
|
+
},
|
|
247
|
+
]}
|
|
248
|
+
/>
|
|
249
|
+
</IntlProvider>,
|
|
250
|
+
);
|
|
251
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
252
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
253
|
+
});
|
|
283
254
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
255
|
+
it('uses tag.name as column label when fullPath is absent', () => {
|
|
256
|
+
render(
|
|
257
|
+
<IntlProvider locale="en" messages={{}}>
|
|
258
|
+
<CustomValuesEditor
|
|
259
|
+
{...baseProps}
|
|
260
|
+
sections={[
|
|
261
|
+
{
|
|
262
|
+
key: 'name-only',
|
|
263
|
+
title: 'Section',
|
|
264
|
+
requiredTags: [{ name: 'myTag' }],
|
|
265
|
+
optionalTags: [],
|
|
266
|
+
},
|
|
267
|
+
]}
|
|
268
|
+
/>
|
|
269
|
+
</IntlProvider>,
|
|
270
|
+
);
|
|
271
|
+
expect(screen.getByText('myTag')).toBeInTheDocument();
|
|
293
272
|
});
|
|
294
273
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
<
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
274
|
+
it('uses empty string as column label when both fullPath and name are absent', () => {
|
|
275
|
+
render(
|
|
276
|
+
<IntlProvider locale="en" messages={{}}>
|
|
277
|
+
<CustomValuesEditor
|
|
278
|
+
{...baseProps}
|
|
279
|
+
sections={[
|
|
280
|
+
{
|
|
281
|
+
key: 'no-label',
|
|
282
|
+
title: 'Section',
|
|
283
|
+
requiredTags: [{}],
|
|
284
|
+
optionalTags: [],
|
|
285
|
+
},
|
|
286
|
+
]}
|
|
287
|
+
/>
|
|
288
|
+
</IntlProvider>,
|
|
289
|
+
);
|
|
290
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
291
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
292
|
+
});
|
|
306
293
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
294
|
+
it('renders optional-only section (no requiredTags) correctly', () => {
|
|
295
|
+
render(
|
|
296
|
+
<IntlProvider locale="en" messages={{}}>
|
|
297
|
+
<CustomValuesEditor
|
|
298
|
+
{...baseProps}
|
|
299
|
+
sections={[
|
|
300
|
+
{
|
|
301
|
+
key: 'optional-only',
|
|
302
|
+
title: 'Optional Section',
|
|
303
|
+
requiredTags: [],
|
|
304
|
+
optionalTags: [{ fullPath: 'tag.opt', name: 'opt' }],
|
|
305
|
+
},
|
|
306
|
+
]}
|
|
307
|
+
/>
|
|
308
|
+
</IntlProvider>,
|
|
309
|
+
);
|
|
310
|
+
expect(screen.getByText('Optional Section')).toBeInTheDocument();
|
|
311
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
312
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
313
|
+
});
|
|
317
314
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
315
|
+
it('renders required-only section (no optionalTags) correctly', () => {
|
|
316
|
+
render(
|
|
317
|
+
<IntlProvider locale="en" messages={{}}>
|
|
318
|
+
<CustomValuesEditor
|
|
319
|
+
{...baseProps}
|
|
320
|
+
sections={[
|
|
321
|
+
{
|
|
322
|
+
key: 'required-only',
|
|
323
|
+
title: 'Required Section',
|
|
324
|
+
requiredTags: [{ fullPath: 'tag.req', name: 'req' }],
|
|
325
|
+
optionalTags: [],
|
|
326
|
+
},
|
|
327
|
+
]}
|
|
328
|
+
/>
|
|
329
|
+
</IntlProvider>,
|
|
330
|
+
);
|
|
331
|
+
expect(screen.getByText('Required Section')).toBeInTheDocument();
|
|
332
|
+
const inputs = screen.getAllByTestId('tag-input');
|
|
333
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
334
|
+
});
|
|
327
335
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
336
|
+
it('renders line numbers in JSON mode matching JSON line count', () => {
|
|
337
|
+
const multiValueCustomValues = { a: 'val1', b: 'val2', c: 'val3' };
|
|
338
|
+
render(
|
|
339
|
+
<IntlProvider locale="en" messages={{}}>
|
|
340
|
+
<CustomValuesEditor
|
|
341
|
+
{...baseProps}
|
|
342
|
+
showJSON
|
|
343
|
+
customValues={multiValueCustomValues}
|
|
344
|
+
/>
|
|
345
|
+
</IntlProvider>,
|
|
346
|
+
);
|
|
347
|
+
const lineNumbers = document.querySelectorAll('.line-number');
|
|
348
|
+
const expectedLineCount = JSON.stringify(multiValueCustomValues, null, 2).split('\n').length;
|
|
349
|
+
expect(lineNumbers.length).toBe(expectedLineCount);
|
|
350
|
+
});
|
|
337
351
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
352
|
+
it('passes fullPath as key for required tag row when fullPath is present', () => {
|
|
353
|
+
const handleChange = jest.fn();
|
|
354
|
+
render(
|
|
355
|
+
<IntlProvider locale="en" messages={{}}>
|
|
356
|
+
<CustomValuesEditor
|
|
357
|
+
{...baseProps}
|
|
358
|
+
sections={[
|
|
359
|
+
{
|
|
360
|
+
key: 'sec',
|
|
361
|
+
title: 'S',
|
|
362
|
+
requiredTags: [{ fullPath: 'my.full.path', name: 'name' }],
|
|
363
|
+
optionalTags: [],
|
|
364
|
+
},
|
|
365
|
+
]}
|
|
366
|
+
handleCustomValueChange={handleChange}
|
|
367
|
+
customValues={{ 'my.full.path': 'existing' }}
|
|
368
|
+
/>
|
|
369
|
+
</IntlProvider>,
|
|
370
|
+
);
|
|
371
|
+
const input = screen.getByTestId('tag-input');
|
|
372
|
+
expect(input.value).toBe('existing');
|
|
373
|
+
fireEvent.change(input, { target: { value: 'updated' } });
|
|
374
|
+
expect(handleChange).toHaveBeenCalledWith('my.full.path', 'updated');
|
|
351
375
|
});
|
|
352
376
|
});
|