@capillarytech/creatives-library 9.0.29 → 9.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/constants/unified.js +29 -0
  2. package/global-styles.js +1 -1
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +35 -20
  5. package/utils/commonUtils.js +22 -1
  6. package/utils/rcsPayloadUtils.js +102 -0
  7. package/utils/templateVarUtils.js +198 -0
  8. package/utils/tests/rcsPayloadUtils.test.js +295 -0
  9. package/utils/tests/templateVarUtils.test.js +204 -0
  10. package/v2Components/CapActionButton/constants.js +21 -1
  11. package/v2Components/CapActionButton/index.js +261 -144
  12. package/v2Components/CapActionButton/index.scss +245 -14
  13. package/v2Components/CapActionButton/messages.js +32 -3
  14. package/v2Components/CapActionButton/tests/index.test.js +74 -19
  15. package/v2Components/CapImageUpload/index.js +2 -2
  16. package/v2Components/CapTagList/index.js +9 -0
  17. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
  21. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
  22. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +58 -11
  24. package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
  25. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +186 -22
  26. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +381 -80
  27. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
  28. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
  29. package/v2Components/CommonTestAndPreview/constants.js +35 -2
  30. package/v2Components/CommonTestAndPreview/index.js +774 -231
  31. package/v2Components/CommonTestAndPreview/messages.js +45 -3
  32. package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  33. package/v2Components/CommonTestAndPreview/sagas.js +25 -6
  34. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +1 -0
  35. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +412 -257
  36. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +337 -63
  37. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
  38. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
  39. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
  40. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +108 -15
  41. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
  42. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  43. package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
  44. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  45. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
  46. package/v2Components/CommonTestAndPreview/tests/utils.test.js +151 -0
  47. package/v2Components/CommonTestAndPreview/utils.js +84 -0
  48. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
  49. package/v2Components/SmsFallback/constants.js +94 -0
  50. package/v2Components/SmsFallback/index.js +958 -0
  51. package/v2Components/SmsFallback/index.scss +266 -0
  52. package/v2Components/SmsFallback/messages.js +78 -0
  53. package/v2Components/SmsFallback/smsFallbackUtils.js +120 -0
  54. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  55. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  56. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  57. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +208 -0
  58. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
  59. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +471 -0
  60. package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  61. package/v2Components/TemplatePreview/_templatePreview.scss +45 -25
  62. package/v2Components/TemplatePreview/constants.js +2 -0
  63. package/v2Components/TemplatePreview/index.js +147 -32
  64. package/v2Components/TemplatePreview/tests/index.test.js +142 -0
  65. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  66. package/v2Components/TestAndPreviewSlidebox/index.js +13 -1
  67. package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  68. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  69. package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  70. package/v2Components/VarSegmentMessageEditor/index.js +125 -0
  71. package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  72. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
  73. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
  74. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  75. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +27 -0
  76. package/v2Containers/CreativesContainer/SlideBoxContent.js +37 -4
  77. package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
  78. package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
  79. package/v2Containers/CreativesContainer/constants.js +11 -0
  80. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +77 -0
  81. package/v2Containers/CreativesContainer/index.js +322 -106
  82. package/v2Containers/CreativesContainer/index.scss +102 -1
  83. package/v2Containers/CreativesContainer/tests/CreativesSlideBoxWrapper.test.js +58 -0
  84. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  85. package/v2Containers/CreativesContainer/tests/SlideBoxContent.smsDltPreview.test.js +73 -0
  86. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +37 -0
  87. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +103 -34
  88. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +193 -15
  89. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +88 -0
  90. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +549 -57
  91. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
  92. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  93. package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  94. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  95. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  96. package/v2Containers/Rcs/carouselUtils.js +224 -0
  97. package/v2Containers/Rcs/components/CarouselCard.js +317 -0
  98. package/v2Containers/Rcs/components/CarouselCardButtons.js +113 -0
  99. package/v2Containers/Rcs/components/CarouselCardMedia.js +136 -0
  100. package/v2Containers/Rcs/components/CarouselCharacterCount.js +31 -0
  101. package/v2Containers/Rcs/components/CarouselDimensionSelection.js +80 -0
  102. package/v2Containers/Rcs/constants.js +132 -16
  103. package/v2Containers/Rcs/index.js +1822 -946
  104. package/v2Containers/Rcs/index.scss +443 -8
  105. package/v2Containers/Rcs/messages.js +45 -22
  106. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +494 -0
  107. package/v2Containers/Rcs/tests/CarouselCard.test.js +464 -0
  108. package/v2Containers/Rcs/tests/CarouselCardButtons.test.js +211 -0
  109. package/v2Containers/Rcs/tests/CarouselCardMedia.test.js +160 -0
  110. package/v2Containers/Rcs/tests/CarouselCharacterCount.test.js +50 -0
  111. package/v2Containers/Rcs/tests/CarouselDimensionSelection.test.js +119 -0
  112. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +74440 -39387
  113. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +10 -74
  114. package/v2Containers/Rcs/tests/carouselUtils.test.js +916 -0
  115. package/v2Containers/Rcs/tests/index.test.js +275 -40
  116. package/v2Containers/Rcs/tests/mockData.js +38 -0
  117. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +912 -0
  118. package/v2Containers/Rcs/tests/utils.test.js +682 -30
  119. package/v2Containers/Rcs/utils.js +514 -12
  120. package/v2Containers/Sms/Create/index.js +115 -48
  121. package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  122. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  123. package/v2Containers/SmsTrai/Create/index.js +9 -4
  124. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  125. package/v2Containers/SmsTrai/Edit/index.js +678 -169
  126. package/v2Containers/SmsTrai/Edit/index.scss +126 -0
  127. package/v2Containers/SmsTrai/Edit/messages.js +14 -4
  128. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
  129. package/v2Containers/SmsWrapper/index.js +37 -8
  130. package/v2Containers/TagList/index.js +5 -0
  131. package/v2Containers/Templates/TemplatesActionBar.js +101 -0
  132. package/v2Containers/Templates/_templates.scss +196 -12
  133. package/v2Containers/Templates/actions.js +11 -0
  134. package/v2Containers/Templates/constants.js +2 -0
  135. package/v2Containers/Templates/index.js +131 -59
  136. package/v2Containers/Templates/sagas.js +57 -13
  137. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +129 -0
  138. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
  139. package/v2Containers/Templates/tests/sagas.test.js +199 -16
  140. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  141. package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  142. package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  143. package/v2Containers/TemplatesV2/index.js +88 -25
  144. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  145. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  146. package/v2Containers/Whatsapp/index.js +3 -20
  147. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ import React from 'react';
5
+ import { render, screen } from '@testing-library/react';
6
+ import '@testing-library/jest-dom';
7
+ import CarouselCardMedia from '../components/CarouselCardMedia';
8
+ import { RCS_MEDIA_TYPES } from '../constants';
9
+
10
+ jest.mock('@capillarytech/cap-ui-library/CapHeading', () => {
11
+ const React = require('react');
12
+ return function CapHeading(props) {
13
+ return React.createElement('h4', { className: props?.className }, props?.children);
14
+ };
15
+ });
16
+
17
+ jest.mock('../../../v2Components/CapVideoUpload', () => {
18
+ const React = require('react');
19
+ return function MockCapVideoUpload(props) {
20
+ global.__lastVideoUploadProps = props;
21
+ return React.createElement('div', { 'data-testid': 'cap-video-upload' }, 'video-upload');
22
+ };
23
+ });
24
+
25
+ jest.mock('../../../v2Components/CapImageUpload', () => {
26
+ const React = require('react');
27
+ return function MockCapImageUpload(props) {
28
+ global.__lastImageUploadCalls = global.__lastImageUploadCalls || [];
29
+ global.__lastImageUploadCalls.push(props);
30
+ return React.createElement('div', { 'data-testid': 'cap-image-upload' }, 'image-upload');
31
+ };
32
+ });
33
+
34
+ const baseProps = {
35
+ cardIndex: 0,
36
+ card: { mediaType: RCS_MEDIA_TYPES.IMAGE, imageSrc: 'img.png' },
37
+ dimKey: 'SHORT_SMALL',
38
+ isFullMode: true,
39
+ isEditFlow: false,
40
+ rcsData: { some: 'data' },
41
+ uploadRcsImage: jest.fn(),
42
+ uploadRcsVideo: jest.fn(),
43
+ formatMessage: jest.fn((msg) => msg?.defaultMessage || msg?.id || String(msg)),
44
+ onFieldChange: jest.fn(),
45
+ };
46
+
47
+ describe('CarouselCardMedia', () => {
48
+ beforeEach(() => {
49
+ jest.clearAllMocks();
50
+ global.__lastVideoUploadProps = undefined;
51
+ global.__lastImageUploadCalls = [];
52
+ });
53
+
54
+ describe('IMAGE media type (default)', () => {
55
+ it('renders a single CapImageUpload and the media image heading', () => {
56
+ render(<CarouselCardMedia {...baseProps} />);
57
+ expect(screen.queryByTestId('cap-video-upload')).not.toBeInTheDocument();
58
+ expect(screen.getAllByTestId('cap-image-upload')).toHaveLength(1);
59
+ });
60
+
61
+ it('calls onFieldChange("imageSrc", val) via updateImageSrc', () => {
62
+ render(<CarouselCardMedia {...baseProps} />);
63
+ const props = global.__lastImageUploadCalls[0];
64
+ props.updateImageSrc('new-src.png');
65
+ expect(baseProps.onFieldChange).toHaveBeenCalledWith('imageSrc', 'new-src.png');
66
+ });
67
+
68
+ it('calls onFieldChange("imageSrc", "") via updateOnReUpload', () => {
69
+ render(<CarouselCardMedia {...baseProps} />);
70
+ const props = global.__lastImageUploadCalls[0];
71
+ props.updateOnReUpload();
72
+ expect(baseProps.onFieldChange).toHaveBeenCalledWith('imageSrc', '');
73
+ });
74
+
75
+ it('sets showReUploadButton = !isEditFlow && isFullMode (true) and disabled = isEditFlow || !isFullMode (false)', () => {
76
+ render(<CarouselCardMedia {...baseProps} isEditFlow={false} isFullMode />);
77
+ const props = global.__lastImageUploadCalls[0];
78
+ expect(props.showReUploadButton).toBe(true);
79
+ expect(props.disabled).toBe(false);
80
+ });
81
+
82
+ it('sets showReUploadButton to false and disabled to true when isEditFlow is true', () => {
83
+ render(<CarouselCardMedia {...baseProps} isEditFlow isFullMode />);
84
+ const props = global.__lastImageUploadCalls[0];
85
+ expect(props.showReUploadButton).toBe(false);
86
+ expect(props.disabled).toBe(true);
87
+ });
88
+
89
+ it('sets showReUploadButton to false and disabled to true when isFullMode is false', () => {
90
+ render(<CarouselCardMedia {...baseProps} isEditFlow={false} isFullMode={false} />);
91
+ const props = global.__lastImageUploadCalls[0];
92
+ expect(props.showReUploadButton).toBe(false);
93
+ expect(props.disabled).toBe(true);
94
+ });
95
+
96
+ it('passes imageSrc, index and dimension props derived from card/cardIndex/dimKey', () => {
97
+ render(<CarouselCardMedia {...baseProps} cardIndex={2} dimKey="MEDIUM_MEDIUM" />);
98
+ const props = global.__lastImageUploadCalls[0];
99
+ expect(props.imageSrc).toBe('img.png');
100
+ expect(props.channel).toBe('RCS');
101
+ expect(props.imgSize).toBeDefined();
102
+ });
103
+ });
104
+
105
+ describe('VIDEO media type', () => {
106
+ const videoProps = {
107
+ ...baseProps,
108
+ card: {
109
+ mediaType: RCS_MEDIA_TYPES.VIDEO,
110
+ videoAsset: { url: 'video.mp4' },
111
+ thumbnailSrc: 'thumb.png',
112
+ },
113
+ };
114
+
115
+ it('renders CapVideoUpload and a thumbnail CapImageUpload', () => {
116
+ render(<CarouselCardMedia {...videoProps} />);
117
+ expect(screen.getByTestId('cap-video-upload')).toBeInTheDocument();
118
+ expect(screen.getAllByTestId('cap-image-upload')).toHaveLength(1);
119
+ });
120
+
121
+ it('calls onFieldChange("videoAsset", val) via onVideoUploadUpdateAssestList', () => {
122
+ render(<CarouselCardMedia {...videoProps} />);
123
+ const props = global.__lastVideoUploadProps;
124
+ props.onVideoUploadUpdateAssestList(null, { url: 'updated.mp4' });
125
+ expect(videoProps.onFieldChange).toHaveBeenCalledWith('videoAsset', { url: 'updated.mp4' });
126
+ });
127
+
128
+ it('calls onFieldChange("thumbnailSrc", val) via updateImageSrc on thumbnail upload', () => {
129
+ render(<CarouselCardMedia {...videoProps} />);
130
+ const props = global.__lastImageUploadCalls[0];
131
+ props.updateImageSrc('new-thumb.png');
132
+ expect(videoProps.onFieldChange).toHaveBeenCalledWith('thumbnailSrc', 'new-thumb.png');
133
+ });
134
+
135
+ it('calls onFieldChange("thumbnailSrc", "") via updateOnReUpload on thumbnail upload', () => {
136
+ render(<CarouselCardMedia {...videoProps} />);
137
+ const props = global.__lastImageUploadCalls[0];
138
+ props.updateOnReUpload();
139
+ expect(videoProps.onFieldChange).toHaveBeenCalledWith('thumbnailSrc', '');
140
+ });
141
+
142
+ it('passes showReUploadButton/disabled to video and thumbnail uploads based on isEditFlow/isFullMode', () => {
143
+ render(<CarouselCardMedia {...videoProps} isEditFlow={false} isFullMode />);
144
+ expect(global.__lastVideoUploadProps.showReUploadButton).toBe(true);
145
+ const thumbProps = global.__lastImageUploadCalls[0];
146
+ expect(thumbProps.showReUploadButton).toBe(true);
147
+ expect(thumbProps.disabled).toBe(false);
148
+ });
149
+
150
+ it('defaults videoAsset to {} when card.videoAsset is absent', () => {
151
+ render(
152
+ <CarouselCardMedia
153
+ {...videoProps}
154
+ card={{ mediaType: RCS_MEDIA_TYPES.VIDEO }}
155
+ />,
156
+ );
157
+ expect(global.__lastVideoUploadProps.uploadedAssetList).toEqual({});
158
+ });
159
+ });
160
+ });
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ import React from 'react';
5
+ import { render, screen } from '@testing-library/react';
6
+ import '@testing-library/jest-dom';
7
+ import CarouselCharacterCount from '../components/CarouselCharacterCount';
8
+
9
+ jest.mock('@capillarytech/cap-ui-library/CapLabel', () => {
10
+ const React = require('react');
11
+ return function CapLabel(props) {
12
+ return React.createElement('div', { className: props?.className, 'data-testid': 'cap-label' }, props?.children);
13
+ };
14
+ });
15
+
16
+ describe('CarouselCharacterCount', () => {
17
+ it('renders formatMessage output with currentLength/maxLength and default className', () => {
18
+ const formatMessage = jest.fn((msg, vals) => `${msg.id}:${JSON.stringify(vals)}`);
19
+ render(
20
+ <CarouselCharacterCount
21
+ formatMessage={formatMessage}
22
+ currentLength={12}
23
+ maxLength={100}
24
+ />,
25
+ );
26
+ expect(formatMessage).toHaveBeenCalledWith(
27
+ expect.objectContaining({ id: expect.any(String) }),
28
+ { currentLength: 12, maxLength: 100 },
29
+ );
30
+ const label = screen.getByTestId('cap-label');
31
+ expect(label).toHaveClass('rcs-character-count');
32
+ expect(label.textContent).toContain('12');
33
+ expect(label.textContent).toContain('100');
34
+ });
35
+
36
+ it('applies an overridden className when provided', () => {
37
+ const formatMessage = jest.fn(() => 'Characters count: 5/50');
38
+ render(
39
+ <CarouselCharacterCount
40
+ formatMessage={formatMessage}
41
+ currentLength={5}
42
+ maxLength={50}
43
+ className="custom-count-class"
44
+ />,
45
+ );
46
+ const label = screen.getByTestId('cap-label');
47
+ expect(label).toHaveClass('custom-count-class');
48
+ expect(label).not.toHaveClass('rcs-character-count');
49
+ });
50
+ });
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ import React from 'react';
5
+ import { render, screen, fireEvent } from '@testing-library/react';
6
+ import '@testing-library/jest-dom';
7
+ import CarouselDimensionSelection from '../components/CarouselDimensionSelection';
8
+
9
+ jest.mock('@capillarytech/cap-ui-library/CapRow', () => {
10
+ const React = require('react');
11
+ return function CapRow(props) {
12
+ return React.createElement('div', { className: props?.className, 'data-testid': 'cap-row' }, props?.children);
13
+ };
14
+ });
15
+ jest.mock('@capillarytech/cap-ui-library/CapColumn', () => {
16
+ const React = require('react');
17
+ return function CapColumn(props) {
18
+ return React.createElement('div', { 'data-testid': 'cap-column' }, props?.children);
19
+ };
20
+ });
21
+ jest.mock('@capillarytech/cap-ui-library/CapHeading', () => {
22
+ const React = require('react');
23
+ return function CapHeading(props) {
24
+ return React.createElement(props?.type === 'h5' ? 'h5' : 'h4', { className: props?.className }, props?.children);
25
+ };
26
+ });
27
+ jest.mock('@capillarytech/cap-ui-library/CapLabel', () => {
28
+ const React = require('react');
29
+ return function CapLabel(props) {
30
+ return React.createElement('div', { className: props?.className, 'data-testid': 'cap-label' }, props?.children);
31
+ };
32
+ });
33
+ jest.mock('@capillarytech/cap-ui-library/CapSelect', () => {
34
+ const React = require('react');
35
+ return function CapSelect(props) {
36
+ return React.createElement('select', {
37
+ 'data-testid': props?.id,
38
+ value: props?.value,
39
+ disabled: props?.disabled,
40
+ onChange: (e) => props?.onChange?.(e.target.value),
41
+ }, (props?.options || []).map((opt) => (
42
+ React.createElement('option', { key: opt.value, value: opt.value }, opt.label)
43
+ )));
44
+ };
45
+ });
46
+
47
+ const baseProps = {
48
+ isEditFlow: false,
49
+ isFullMode: true,
50
+ selectedCarouselHeight: 'SHORT',
51
+ selectedCarouselWidth: 'SMALL',
52
+ selectedCarousel: '',
53
+ onHeightChange: jest.fn(),
54
+ onWidthChange: jest.fn(),
55
+ };
56
+
57
+ describe('CarouselDimensionSelection', () => {
58
+ beforeEach(() => {
59
+ jest.clearAllMocks();
60
+ });
61
+
62
+ it('renders CapSelect controls for height and width when isEditFlow is false', () => {
63
+ render(<CarouselDimensionSelection {...baseProps} />);
64
+ expect(screen.getByTestId('rcs-carousel-height-select')).toBeInTheDocument();
65
+ expect(screen.getByTestId('rcs-carousel-width-select')).toBeInTheDocument();
66
+ });
67
+
68
+ it('fires onHeightChange and onWidthChange when selects change', () => {
69
+ render(<CarouselDimensionSelection {...baseProps} />);
70
+ fireEvent.change(screen.getByTestId('rcs-carousel-height-select'), { target: { value: 'MEDIUM' } });
71
+ expect(baseProps.onHeightChange).toHaveBeenCalledWith('MEDIUM');
72
+ fireEvent.change(screen.getByTestId('rcs-carousel-width-select'), { target: { value: 'MEDIUM' } });
73
+ expect(baseProps.onWidthChange).toHaveBeenCalledWith('MEDIUM');
74
+ });
75
+
76
+ it('disables the CapSelect controls when isFullMode is false', () => {
77
+ render(<CarouselDimensionSelection {...baseProps} isFullMode={false} />);
78
+ expect(screen.getByTestId('rcs-carousel-height-select')).toBeDisabled();
79
+ expect(screen.getByTestId('rcs-carousel-width-select')).toBeDisabled();
80
+ });
81
+
82
+ it('does not disable the CapSelect controls when isFullMode is true', () => {
83
+ render(<CarouselDimensionSelection {...baseProps} isFullMode />);
84
+ expect(screen.getByTestId('rcs-carousel-height-select')).not.toBeDisabled();
85
+ expect(screen.getByTestId('rcs-carousel-width-select')).not.toBeDisabled();
86
+ });
87
+
88
+ it('renders read-only labels with matched option label when isEditFlow is true', () => {
89
+ render(<CarouselDimensionSelection {...baseProps} isEditFlow />);
90
+ expect(screen.queryByTestId('rcs-carousel-height-select')).not.toBeInTheDocument();
91
+ expect(screen.queryByTestId('rcs-carousel-width-select')).not.toBeInTheDocument();
92
+ expect(screen.getByText('Short')).toBeInTheDocument();
93
+ expect(screen.getByText('Small')).toBeInTheDocument();
94
+ });
95
+
96
+ it('renders "-" fallback in read-only mode when no matching height/width option is found', () => {
97
+ render(
98
+ <CarouselDimensionSelection
99
+ {...baseProps}
100
+ isEditFlow
101
+ selectedCarouselHeight="UNKNOWN"
102
+ selectedCarouselWidth="UNKNOWN"
103
+ />,
104
+ );
105
+ const dashes = screen.getAllByText('-');
106
+ expect(dashes.length).toBe(2);
107
+ });
108
+
109
+ it('shows the "Selected: ..." label when selectedCarousel is truthy', () => {
110
+ render(<CarouselDimensionSelection {...baseProps} selectedCarousel="SHORT_SMALL" />);
111
+ expect(screen.getByText(/Selected:/)).toBeInTheDocument();
112
+ expect(screen.getByText(/SHORT_SMALL/)).toBeInTheDocument();
113
+ });
114
+
115
+ it('hides the "Selected: ..." label when selectedCarousel is falsy', () => {
116
+ render(<CarouselDimensionSelection {...baseProps} selectedCarousel="" />);
117
+ expect(screen.queryByText(/Selected:/)).not.toBeInTheDocument();
118
+ });
119
+ });