@capillarytech/creatives-library 9.0.56-betaa.0 → 9.0.56
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 +9 -4
- package/package.json +1 -1
- package/services/api.js +25 -4
- package/utils/common.js +0 -12
- package/utils/templateVarUtils.js +16 -0
- package/utils/tests/templateVarUtils.test.js +44 -0
- package/v2Components/CapActionButton/index.js +73 -60
- package/v2Components/CapActionButton/index.scss +44 -28
- package/v2Components/CapActionButton/messages.js +7 -3
- package/v2Components/CapActionButton/tests/index.test.js +17 -1
- package/v2Components/CapWhatsappCTA/messages.js +4 -0
- package/v2Components/CapWhatsappCarouselButton/index.js +42 -33
- package/v2Components/CapWhatsappCarouselButton/index.scss +44 -2
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +13 -0
- package/v2Components/CommonTestAndPreview/actions.js +13 -0
- package/v2Components/CommonTestAndPreview/constants.js +8 -0
- package/v2Components/CommonTestAndPreview/index.js +55 -3
- package/v2Components/CommonTestAndPreview/reducer.js +20 -0
- package/v2Components/CommonTestAndPreview/sagas.js +28 -0
- package/v2Components/CommonTestAndPreview/selectors.js +6 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +106 -0
- package/v2Components/CommonTestAndPreview/tests/actions.test.js +15 -0
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +9 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +101 -0
- package/v2Components/CommonTestAndPreview/tests/reducer.test.js +41 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +84 -0
- package/v2Components/CommonTestAndPreview/tests/selectors.test.js +12 -0
- package/v2Components/FormBuilder/Functional/FormBuilderShell.js +46 -320
- package/v2Components/FormBuilder/Functional/channels/registry.js +0 -2
- package/v2Components/FormBuilder/Functional/constants.js +8 -43
- package/v2Components/FormBuilder/Functional/core/schema/initializeFormState.js +28 -175
- package/v2Components/FormBuilder/Functional/core/store/formReducer.js +6 -75
- package/v2Components/FormBuilder/Functional/core/store/toLegacyFormData.js +20 -10
- package/v2Components/FormBuilder/Functional/layout/FieldSlot.js +1 -9
- package/v2Components/FormBuilder/Functional/layout/SchemaForm.js +3 -20
- package/v2Components/FormBuilder/Functional/layout/Section.js +1 -6
- package/v2Components/FormBuilder/Functional/tests/fieldSlot.test.js +2 -9
- package/v2Components/FormBuilder/Functional/tests/schemaForm.test.js +0 -17
- package/v2Components/FormBuilder/index.js +12 -34
- package/v2Components/FormBuilder/tests/entryGate.test.js +7 -94
- package/v2Components/TestAndPreviewSlidebox/index.js +9 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +140 -75
- package/v2Containers/CommunicationFlow/CommunicationFlow.scss +18 -2
- package/v2Containers/CommunicationFlow/CommunicationFlowCard.js +67 -28
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +503 -51
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlowCard.test.js +98 -4
- package/v2Containers/CommunicationFlow/Tests/constants.test.js +85 -0
- package/v2Containers/CommunicationFlow/constants.js +65 -4
- package/v2Containers/CommunicationFlow/index.js +16 -23
- package/v2Containers/CommunicationFlow/messages.js +11 -3
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +27 -11
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +4 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +176 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +22 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +14 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +11 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +51 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +11 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +19 -5
- package/v2Containers/CreativesContainer/SlideBoxContent.js +15 -0
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +6 -2
- package/v2Containers/CreativesContainer/index.js +29 -3
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +29 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +18 -5
- package/v2Containers/CreativesContainer/tests/index.test.js +12 -0
- package/v2Containers/MobilePush/Create/index.js +18 -1
- package/v2Containers/MobilePush/Create/test/contentValidity.test.js +96 -0
- package/v2Containers/MobilePush/Edit/index.js +18 -1
- package/v2Containers/MobilePush/Edit/test/contentValidity.test.js +116 -0
- package/v2Containers/MobilePush/commonMethods.js +49 -1
- package/v2Containers/MobilePushNew/index.js +29 -4
- package/v2Containers/MobilePushNew/tests/index.test.js +119 -0
- package/v2Containers/MobilePushNew/tests/utils.test.js +82 -0
- package/v2Containers/MobilePushNew/utils.js +34 -1
- package/v2Containers/MobilepushWrapper/index.js +3 -1
- package/v2Containers/Rcs/index.js +34 -0
- package/v2Containers/Rcs/index.scss +15 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +115 -19
- package/v2Containers/Rcs/tests/index.test.js +67 -0
- package/v2Containers/Sms/Create/index.js +3 -1
- package/v2Containers/Sms/Edit/index.js +25 -0
- package/v2Containers/Sms/Edit/tests/index.test.js +85 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +27 -3
- package/v2Containers/Viber/index.js +24 -1
- package/v2Containers/Viber/tests/index.test.js +103 -0
- package/v2Containers/WebPush/Create/index.js +19 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +17 -12
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +5 -0
- package/v2Containers/WebPush/Create/tests/contentValidity.test.js +294 -0
- package/v2Containers/Whatsapp/index.js +25 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +306 -34
- package/v2Containers/Whatsapp/tests/index.test.js +115 -0
- package/v2Containers/Zalo/index.js +28 -1
- package/v2Containers/Zalo/tests/index.test.js +99 -0
- package/v2Containers/mockdata.js +25 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/buildSubmitPayload.js +0 -10
- package/v2Components/FormBuilder/Functional/channels/mobilepush/config.js +0 -82
- package/v2Components/FormBuilder/Functional/channels/mobilepush/getEditorErrorDescriptor.js +0 -74
- package/v2Components/FormBuilder/Functional/channels/mobilepush/index.js +0 -28
- package/v2Components/FormBuilder/Functional/channels/mobilepush/modals.js +0 -19
- package/v2Components/FormBuilder/Functional/channels/mobilepush/runSubmitPipeline.js +0 -45
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/getEditorErrorDescriptor.test.js +0 -162
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/modals.test.js +0 -37
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/runSubmitPipeline.test.js +0 -70
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/validate.test.js +0 -274
- package/v2Components/FormBuilder/Functional/channels/mobilepush/validate.js +0 -251
- package/v2Components/FormBuilder/Functional/layout/TabsContainer.js +0 -89
- package/v2Components/FormBuilder/Functional/renderers/mpushRenderers.js +0 -440
- package/v2Components/FormBuilder/Functional/tests/mpush.crossFlowParity.test.js +0 -430
- package/v2Components/FormBuilder/Functional/tests/mpush.ctaFlows.parity.test.js +0 -282
- package/v2Components/FormBuilder/Functional/tests/mpush.editContainer.parity.test.js +0 -141
- package/v2Components/FormBuilder/Functional/tests/mpush.engine.test.js +0 -306
- package/v2Components/FormBuilder/Functional/tests/mpush.shellEvents.test.js +0 -151
- package/v2Components/FormBuilder/Functional/tests/mpushRenderers.test.js +0 -342
- package/v2Components/FormBuilder/Functional/tests/tabsContainer.test.js +0 -110
- package/v2Components/FormBuilder/tests/mpush.characterization.test.js +0 -459
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
jest.mock('../../../services/api', () => ({
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
createCommDefinition: jest.fn(),
|
|
5
|
+
editCommDefinition: jest.fn(),
|
|
6
6
|
}));
|
|
7
7
|
|
|
8
8
|
jest.mock('../../CreativesContainer', () => function MockCreativesContainer({
|
|
@@ -38,7 +38,7 @@ import { IntlProvider } from 'react-intl';
|
|
|
38
38
|
import history from '../../../utils/history';
|
|
39
39
|
import { initialReducer } from '../../../initialReducer';
|
|
40
40
|
import CommunicationFlow from '../CommunicationFlow';
|
|
41
|
-
import {
|
|
41
|
+
import { createCommDefinition, editCommDefinition } from '../../../services/api';
|
|
42
42
|
import { getEnabledSteps } from '../utils/getEnabledSteps';
|
|
43
43
|
import {
|
|
44
44
|
CHANNELS,
|
|
@@ -192,13 +192,13 @@ describe('CommunicationFlow', () => {
|
|
|
192
192
|
it('hides channel selection and dynamic controls until a communication strategy is set', async () => {
|
|
193
193
|
renderWithFlow({ features: FEATURES.strategyContentDynamic });
|
|
194
194
|
|
|
195
|
-
expect(screen.queryByText(/
|
|
195
|
+
expect(screen.queryByText(/add creative/i)).not.toBeInTheDocument();
|
|
196
196
|
expect(screen.queryByText(/other controls/i)).not.toBeInTheDocument();
|
|
197
197
|
|
|
198
198
|
await selectCommunicationStrategy('Single template');
|
|
199
199
|
|
|
200
200
|
await waitFor(() => {
|
|
201
|
-
expect(screen.getAllByText(/
|
|
201
|
+
expect(screen.getAllByText(/add creative/i).length).toBeGreaterThan(0);
|
|
202
202
|
});
|
|
203
203
|
expect(screen.getByText(/other controls/i)).toBeInTheDocument();
|
|
204
204
|
});
|
|
@@ -359,82 +359,295 @@ describe('isSaveDisabled', () => {
|
|
|
359
359
|
});
|
|
360
360
|
|
|
361
361
|
describe('handleSave — CCS flow', () => {
|
|
362
|
+
const ccsConfig = { ...baseConfig, context: { name: 'Order Placed Notification' }, features: {} };
|
|
363
|
+
|
|
362
364
|
beforeEach(() => {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
+
createCommDefinition.mockResolvedValue({
|
|
366
|
+
response: { data: { id: 'cd_123', referenceId: 'ORDER_PLACED_123', status: 'DRAFT', version: { version: 1 } } },
|
|
367
|
+
});
|
|
365
368
|
});
|
|
366
369
|
|
|
367
370
|
afterEach(() => {
|
|
368
371
|
jest.clearAllMocks();
|
|
369
372
|
});
|
|
370
373
|
|
|
371
|
-
it('calls
|
|
374
|
+
it('calls createCommDefinition with a SINGLE-strategy payload when useCCS is not false', async () => {
|
|
372
375
|
const onSave = jest.fn();
|
|
373
376
|
renderWithFlow({
|
|
374
377
|
features: {},
|
|
378
|
+
config: ccsConfig,
|
|
379
|
+
// messageBody is the legacy editor's field name for the typed SMS text
|
|
380
|
+
// (see CreativesContainer/index.js's getCreativesData SMS case) — the
|
|
381
|
+
// SMS transform maps it to CCS's `message` field.
|
|
375
382
|
initialData: {
|
|
376
|
-
contentItems: [{ channel: 'sms', templateData: {
|
|
383
|
+
contentItems: [{ channel: 'sms', templateData: { messageBody: 'Hello' } }],
|
|
377
384
|
},
|
|
378
385
|
onSave,
|
|
379
386
|
});
|
|
380
387
|
|
|
381
388
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
382
389
|
|
|
383
|
-
await waitFor(() => expect(
|
|
384
|
-
expect(
|
|
390
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
391
|
+
expect(createCommDefinition).toHaveBeenCalledWith(
|
|
385
392
|
expect.objectContaining({
|
|
386
|
-
|
|
393
|
+
name: 'Order Placed Notification',
|
|
394
|
+
strategyType: 'SINGLE',
|
|
395
|
+
singleChannelStrategy: expect.objectContaining({
|
|
396
|
+
variant: expect.objectContaining({
|
|
397
|
+
channel: 'SMS',
|
|
398
|
+
smsMessageContent: { channel: 'SMS', message: 'Hello' },
|
|
399
|
+
}),
|
|
400
|
+
}),
|
|
387
401
|
}),
|
|
388
402
|
);
|
|
389
403
|
expect(onSave).toHaveBeenCalledTimes(1);
|
|
390
404
|
});
|
|
391
405
|
|
|
392
|
-
it('
|
|
406
|
+
it('transforms SMS content from the legacy editor shape (messageBody) to CCS\'s message field', async () => {
|
|
407
|
+
const onSave = jest.fn();
|
|
393
408
|
renderWithFlow({
|
|
394
409
|
features: {},
|
|
395
|
-
|
|
410
|
+
config: ccsConfig,
|
|
411
|
+
initialData: {
|
|
412
|
+
contentItems: [{
|
|
413
|
+
channel: 'SMS',
|
|
414
|
+
templateData: { messageBody: 'Hello {{name}}', channel: 'SMS' },
|
|
415
|
+
}],
|
|
416
|
+
},
|
|
417
|
+
onSave,
|
|
396
418
|
});
|
|
397
419
|
|
|
398
420
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
399
421
|
|
|
400
|
-
await waitFor(() => expect(
|
|
422
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
423
|
+
expect(createCommDefinition).toHaveBeenCalledWith(
|
|
424
|
+
expect.objectContaining({
|
|
425
|
+
singleChannelStrategy: expect.objectContaining({
|
|
426
|
+
variant: expect.objectContaining({
|
|
427
|
+
channel: 'SMS',
|
|
428
|
+
smsMessageContent: {
|
|
429
|
+
channel: 'SMS',
|
|
430
|
+
message: 'Hello {{name}}',
|
|
431
|
+
},
|
|
432
|
+
}),
|
|
433
|
+
}),
|
|
434
|
+
}),
|
|
435
|
+
);
|
|
401
436
|
});
|
|
402
437
|
|
|
403
|
-
it('
|
|
404
|
-
|
|
438
|
+
it('does not carry the legacy messageBody key into smsMessageContent (regression guard against reverting to pass-through)', async () => {
|
|
439
|
+
const onSave = jest.fn();
|
|
405
440
|
renderWithFlow({
|
|
406
441
|
features: {},
|
|
442
|
+
config: ccsConfig,
|
|
443
|
+
initialData: {
|
|
444
|
+
contentItems: [{
|
|
445
|
+
channel: 'SMS',
|
|
446
|
+
templateData: { messageBody: 'Hello {{name}}', channel: 'SMS' },
|
|
447
|
+
}],
|
|
448
|
+
},
|
|
449
|
+
onSave,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
453
|
+
|
|
454
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
455
|
+
const payload = createCommDefinition.mock.calls[0][0];
|
|
456
|
+
expect(payload.singleChannelStrategy.variant.smsMessageContent).not.toHaveProperty('messageBody');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('transforms EMAIL content from the legacy editor shape (emailSubject) to CCS\'s messageSubject', async () => {
|
|
460
|
+
const onSave = jest.fn();
|
|
461
|
+
renderWithFlow({
|
|
462
|
+
features: {},
|
|
463
|
+
config: ccsConfig,
|
|
464
|
+
initialData: {
|
|
465
|
+
contentItems: [{
|
|
466
|
+
channel: 'EMAIL',
|
|
467
|
+
templateData: { emailSubject: 'Order Confirmed', emailBody: '<html>Hi</html>' },
|
|
468
|
+
}],
|
|
469
|
+
},
|
|
470
|
+
onSave,
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
474
|
+
|
|
475
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
476
|
+
expect(createCommDefinition).toHaveBeenCalledWith(
|
|
477
|
+
expect.objectContaining({
|
|
478
|
+
singleChannelStrategy: expect.objectContaining({
|
|
479
|
+
variant: expect.objectContaining({
|
|
480
|
+
channel: 'EMAIL',
|
|
481
|
+
emailMessageContent: {
|
|
482
|
+
channel: 'EMAIL',
|
|
483
|
+
messageSubject: 'Order Confirmed',
|
|
484
|
+
messageBody: '<html>Hi</html>',
|
|
485
|
+
},
|
|
486
|
+
}),
|
|
487
|
+
}),
|
|
488
|
+
}),
|
|
489
|
+
);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('transforms WEBPUSH content from the legacy editor\'s messageContent.content wrapping to CCS\'s flat shape', async () => {
|
|
493
|
+
const onSave = jest.fn();
|
|
494
|
+
const cta = { type: 'SITE_URL', actionLink: 'https://example.com' };
|
|
495
|
+
const expandableDetails = { media: [{ url: 'https://example.com/banner.png', type: 'IMAGE' }], ctas: [] };
|
|
496
|
+
renderWithFlow({
|
|
497
|
+
features: {},
|
|
498
|
+
config: ccsConfig,
|
|
499
|
+
initialData: {
|
|
500
|
+
contentItems: [{
|
|
501
|
+
channel: 'WEBPUSH',
|
|
502
|
+
templateData: {
|
|
503
|
+
messageContent: {
|
|
504
|
+
content: {
|
|
505
|
+
channel: 'WEBPUSH',
|
|
506
|
+
accountId: 13792,
|
|
507
|
+
content: { title: 'Hi', message: 'Body', iconImageUrl: 'https://example.com/icon.png', cta, expandableDetails },
|
|
508
|
+
messageSubject: 'Subject',
|
|
509
|
+
offers: [],
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
}],
|
|
514
|
+
},
|
|
515
|
+
onSave,
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
519
|
+
|
|
520
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
521
|
+
expect(createCommDefinition).toHaveBeenCalledWith(
|
|
522
|
+
expect.objectContaining({
|
|
523
|
+
singleChannelStrategy: expect.objectContaining({
|
|
524
|
+
variant: expect.objectContaining({
|
|
525
|
+
channel: 'WEBPUSH',
|
|
526
|
+
webPushMessageContent: {
|
|
527
|
+
channel: 'WEBPUSH',
|
|
528
|
+
messageSubject: 'Subject',
|
|
529
|
+
accountId: 13792,
|
|
530
|
+
content: { title: 'Hi', message: 'Body', iconImageUrl: 'https://example.com/icon.png', cta, expandableDetails },
|
|
531
|
+
},
|
|
532
|
+
}),
|
|
533
|
+
}),
|
|
534
|
+
}),
|
|
535
|
+
);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('normalizes the internal MOBILEPUSH channel to CCS\'s PUSH enum (keys stay mpush*), even when templateData/channelSetting carry their own stray channel field', async () => {
|
|
539
|
+
const onSave = jest.fn();
|
|
540
|
+
renderWithFlow({
|
|
541
|
+
features: {},
|
|
542
|
+
config: ccsConfig,
|
|
543
|
+
initialData: {
|
|
544
|
+
// `channel: 'MOBILEPUSH'` inline on templateData reproduces the real
|
|
545
|
+
// production bug: contentItem.templateData carries the UI's own
|
|
546
|
+
// internal channel identifier, which must not win over the
|
|
547
|
+
// normalized 'PUSH' enum once spread into mpushMessageContent.
|
|
548
|
+
contentItems: [{ channel: 'MOBILEPUSH', templateData: { channel: 'MOBILEPUSH', messageSubject: 'Hi' } }],
|
|
549
|
+
// Likewise, deliverySetting.channelSetting.PUSH carrying its own
|
|
550
|
+
// stray `channel` key must not win over the normalized value once
|
|
551
|
+
// spread into mpushDeliverySettings.channelSettings.
|
|
552
|
+
deliverySetting: { channelSetting: { PUSH: { channel: 'MOBILEPUSH', domainId: 2002 } } },
|
|
553
|
+
},
|
|
554
|
+
onSave,
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
558
|
+
|
|
559
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
560
|
+
expect(createCommDefinition).toHaveBeenCalledWith(
|
|
561
|
+
expect.objectContaining({
|
|
562
|
+
singleChannelStrategy: expect.objectContaining({
|
|
563
|
+
variant: expect.objectContaining({
|
|
564
|
+
channel: 'PUSH',
|
|
565
|
+
mpushMessageContent: { channel: 'PUSH', messageSubject: 'Hi' },
|
|
566
|
+
mpushDeliverySettings: {
|
|
567
|
+
channelSettings: { channel: 'PUSH', domainId: 2002 },
|
|
568
|
+
},
|
|
569
|
+
}),
|
|
570
|
+
}),
|
|
571
|
+
}),
|
|
572
|
+
);
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it('merges ccsCommDefinition into the data passed to onSave when create succeeds', async () => {
|
|
576
|
+
const onSave = jest.fn();
|
|
577
|
+
renderWithFlow({
|
|
578
|
+
features: {},
|
|
579
|
+
config: ccsConfig,
|
|
407
580
|
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
581
|
+
onSave,
|
|
408
582
|
});
|
|
409
583
|
|
|
410
584
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
411
585
|
|
|
412
|
-
await waitFor(() => expect(
|
|
413
|
-
expect(
|
|
586
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
587
|
+
expect(onSave).toHaveBeenCalledWith(
|
|
588
|
+
expect.objectContaining({
|
|
589
|
+
ccsCommDefinition: { id: 'cd_123', referenceId: 'ORDER_PLACED_123', version: 1, status: 'DRAFT' },
|
|
590
|
+
}),
|
|
591
|
+
);
|
|
414
592
|
});
|
|
415
593
|
|
|
416
|
-
it('
|
|
594
|
+
it('preserves a real version of 0 from CCS (not coerced to 1 by a falsy-zero fallback)', async () => {
|
|
595
|
+
const onSave = jest.fn();
|
|
596
|
+
createCommDefinition.mockResolvedValueOnce({
|
|
597
|
+
response: { data: { id: 'cd_123', referenceId: 'ORDER_PLACED_123', status: 'DRAFT', version: { version: 0 } } },
|
|
598
|
+
});
|
|
417
599
|
renderWithFlow({
|
|
418
600
|
features: {},
|
|
419
|
-
config:
|
|
601
|
+
config: ccsConfig,
|
|
420
602
|
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
603
|
+
onSave,
|
|
421
604
|
});
|
|
422
605
|
|
|
423
606
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
424
607
|
|
|
425
|
-
await waitFor(() => expect(
|
|
426
|
-
expect(
|
|
608
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
609
|
+
expect(onSave).toHaveBeenCalledWith(
|
|
427
610
|
expect.objectContaining({
|
|
428
|
-
|
|
611
|
+
ccsCommDefinition: { id: 'cd_123', referenceId: 'ORDER_PLACED_123', version: 0, status: 'DRAFT' },
|
|
429
612
|
}),
|
|
430
613
|
);
|
|
431
614
|
});
|
|
432
615
|
|
|
616
|
+
it('sends an empty referenceId/description when config.context does not supply them', async () => {
|
|
617
|
+
renderWithFlow({
|
|
618
|
+
features: {},
|
|
619
|
+
config: ccsConfig,
|
|
620
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
624
|
+
|
|
625
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
|
|
626
|
+
const payload = createCommDefinition.mock.calls[0][0];
|
|
627
|
+
expect(payload.referenceId).toBe('');
|
|
628
|
+
expect(payload.description).toBe('');
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('uses config.context.referenceId and description when provided', async () => {
|
|
632
|
+
renderWithFlow({
|
|
633
|
+
features: {},
|
|
634
|
+
config: { ...ccsConfig, context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', description: 'desc' } },
|
|
635
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
639
|
+
|
|
640
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
|
|
641
|
+
expect(createCommDefinition).toHaveBeenCalledWith(
|
|
642
|
+
expect.objectContaining({ referenceId: 'ORDER_PLACED', description: 'desc' }),
|
|
643
|
+
);
|
|
644
|
+
});
|
|
645
|
+
|
|
433
646
|
it('skips CCS entirely when useCCS is false', async () => {
|
|
434
647
|
const onSave = jest.fn();
|
|
435
648
|
renderWithFlow({
|
|
436
649
|
features: {},
|
|
437
|
-
config: { ...
|
|
650
|
+
config: { ...ccsConfig, useCCS: false },
|
|
438
651
|
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
439
652
|
onSave,
|
|
440
653
|
});
|
|
@@ -442,14 +655,15 @@ describe('handleSave — CCS flow', () => {
|
|
|
442
655
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
443
656
|
|
|
444
657
|
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
445
|
-
expect(
|
|
658
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
659
|
+
expect(onSave).toHaveBeenCalledWith(expect.not.objectContaining({ ccsCommDefinition: expect.anything() }));
|
|
446
660
|
});
|
|
447
661
|
|
|
448
|
-
it('
|
|
449
|
-
createCentralCommsMetaId.mockRejectedValue(new Error('Network error'));
|
|
662
|
+
it('skips createCommDefinition when config.context.name is absent (mandatory)', async () => {
|
|
450
663
|
const onSave = jest.fn();
|
|
451
664
|
renderWithFlow({
|
|
452
665
|
features: {},
|
|
666
|
+
config: { ...baseConfig, features: {} },
|
|
453
667
|
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
454
668
|
onSave,
|
|
455
669
|
});
|
|
@@ -457,12 +671,102 @@ describe('handleSave — CCS flow', () => {
|
|
|
457
671
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
458
672
|
|
|
459
673
|
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
674
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it('skips createCommDefinition for multi-channel strategies (CHANNEL_PRIORITY/AB_TEST)', async () => {
|
|
678
|
+
const onSave = jest.fn();
|
|
679
|
+
renderWithFlow({
|
|
680
|
+
features: {},
|
|
681
|
+
config: ccsConfig,
|
|
682
|
+
initialData: {
|
|
683
|
+
communicationStrategy: CHANNEL_PRIORITY,
|
|
684
|
+
channels: ['SMS', 'EMAIL'],
|
|
685
|
+
contentItems: [{ channel: 'SMS', templateData: {} }, { channel: 'EMAIL', templateData: {} }],
|
|
686
|
+
},
|
|
687
|
+
onSave,
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
691
|
+
|
|
692
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
693
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('blocks save and shows a generic error when createCommDefinition rejects (regression: this used to silently call onSave without ccsCommDefinition and no user-facing feedback — Send for approval would then just be disabled with zero explanation why)', async () => {
|
|
697
|
+
createCommDefinition.mockRejectedValue(new Error('Network error'));
|
|
698
|
+
const onSave = jest.fn();
|
|
699
|
+
renderWithFlow({
|
|
700
|
+
features: {},
|
|
701
|
+
config: ccsConfig,
|
|
702
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
703
|
+
onSave,
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
707
|
+
|
|
708
|
+
await waitFor(() => expect(screen.getByText('Something went wrong while saving your content. Please try again.')).toBeInTheDocument());
|
|
709
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
460
710
|
});
|
|
461
711
|
|
|
462
|
-
it('
|
|
712
|
+
it('blocks save and shows a generic error when createCommDefinition resolves with a network-level failure (api.js resolves isError instead of rejecting on a 401/403/etc)', async () => {
|
|
713
|
+
createCommDefinition.mockResolvedValue({ isError: true, status: 401 });
|
|
463
714
|
const onSave = jest.fn();
|
|
464
715
|
renderWithFlow({
|
|
465
716
|
features: {},
|
|
717
|
+
config: ccsConfig,
|
|
718
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
719
|
+
onSave,
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
723
|
+
|
|
724
|
+
await waitFor(() => expect(screen.getByText('Something went wrong while saving your content. Please try again.')).toBeInTheDocument());
|
|
725
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
it('blocks save and shows a generic error when createCommDefinition resolves with no usable data (e.g. missing id)', async () => {
|
|
729
|
+
createCommDefinition.mockResolvedValue({ response: { data: {} } });
|
|
730
|
+
const onSave = jest.fn();
|
|
731
|
+
renderWithFlow({
|
|
732
|
+
features: {},
|
|
733
|
+
config: ccsConfig,
|
|
734
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
735
|
+
onSave,
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
739
|
+
|
|
740
|
+
await waitFor(() => expect(screen.getByText('Something went wrong while saving your content. Please try again.')).toBeInTheDocument());
|
|
741
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
it('blocks save and shows an error when createCommDefinition resolves with a duplicate REFERENCE_ID_EXISTS conflict', async () => {
|
|
745
|
+
createCommDefinition.mockResolvedValue({
|
|
746
|
+
success: false,
|
|
747
|
+
status: { isError: true, code: 409, message: 'REFERENCE_ID_EXISTS' },
|
|
748
|
+
message: 'REFERENCE_ID_EXISTS',
|
|
749
|
+
});
|
|
750
|
+
const onSave = jest.fn();
|
|
751
|
+
renderWithFlow({
|
|
752
|
+
features: {},
|
|
753
|
+
config: ccsConfig,
|
|
754
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
755
|
+
onSave,
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
759
|
+
|
|
760
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
761
|
+
expect(await screen.findByText(/already in use in your organization/i)).toBeInTheDocument();
|
|
762
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
it('skips createCommDefinition when contentItems is empty', async () => {
|
|
766
|
+
const onSave = jest.fn();
|
|
767
|
+
renderWithFlow({
|
|
768
|
+
features: {},
|
|
769
|
+
config: ccsConfig,
|
|
466
770
|
initialData: { contentItems: [] },
|
|
467
771
|
onSave,
|
|
468
772
|
});
|
|
@@ -470,12 +774,13 @@ describe('handleSave — CCS flow', () => {
|
|
|
470
774
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
471
775
|
|
|
472
776
|
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
473
|
-
expect(
|
|
777
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
474
778
|
});
|
|
475
779
|
|
|
476
|
-
it('
|
|
780
|
+
it('places additionalSettings derived from dynamicControls under settings.additionalSettings (not delivery settings)', async () => {
|
|
477
781
|
renderWithFlow({
|
|
478
782
|
features: {},
|
|
783
|
+
config: ccsConfig,
|
|
479
784
|
initialData: {
|
|
480
785
|
contentItems: [{ channel: 'SMS', templateData: {} }],
|
|
481
786
|
dynamicControls: {
|
|
@@ -489,14 +794,118 @@ describe('handleSave — CCS flow', () => {
|
|
|
489
794
|
|
|
490
795
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
491
796
|
|
|
492
|
-
await waitFor(() => expect(
|
|
493
|
-
const payload =
|
|
494
|
-
expect(payload.
|
|
797
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
|
|
798
|
+
const payload = createCommDefinition.mock.calls[0][0];
|
|
799
|
+
expect(payload.settings.additionalSettings).toEqual({
|
|
495
800
|
useTinyUrl: true,
|
|
496
801
|
encryptUrl: true,
|
|
497
802
|
linkTrackingEnabled: true,
|
|
498
803
|
userSubscriptionDisabled: true,
|
|
499
804
|
});
|
|
805
|
+
expect(payload.singleChannelStrategy.variant.smsDeliverySettings.additionalSettings).toBeUndefined();
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
it('includes channelSettings from deliverySetting.channelSetting in the payload', async () => {
|
|
809
|
+
renderWithFlow({
|
|
810
|
+
features: {},
|
|
811
|
+
config: ccsConfig,
|
|
812
|
+
initialData: {
|
|
813
|
+
contentItems: [{ channel: 'SMS', templateData: {} }],
|
|
814
|
+
deliverySetting: { channelSetting: { SMS: { domainId: 1001, gsmSenderId: 'BRAND1' } } },
|
|
815
|
+
},
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
819
|
+
|
|
820
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
|
|
821
|
+
const payload = createCommDefinition.mock.calls[0][0];
|
|
822
|
+
expect(payload.singleChannelStrategy.variant.smsDeliverySettings.channelSettings).toEqual({
|
|
823
|
+
channel: 'SMS',
|
|
824
|
+
domainId: 1001,
|
|
825
|
+
gsmSenderId: 'BRAND1',
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
it('does not call editCommDefinition when config.context.existingCommDefinitionId is absent', async () => {
|
|
830
|
+
const onSave = jest.fn();
|
|
831
|
+
renderWithFlow({
|
|
832
|
+
features: {},
|
|
833
|
+
config: ccsConfig,
|
|
834
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
835
|
+
onSave,
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
839
|
+
|
|
840
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
841
|
+
expect(editCommDefinition).not.toHaveBeenCalled();
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it('calls editCommDefinition (not createCommDefinition) and merges the existing id into ccsCommDefinition when config.context.existingCommDefinitionId is set', async () => {
|
|
845
|
+
editCommDefinition.mockResolvedValue({
|
|
846
|
+
response: { data: { version: { version: 2 }, status: 'DRAFT' } },
|
|
847
|
+
});
|
|
848
|
+
const onSave = jest.fn();
|
|
849
|
+
renderWithFlow({
|
|
850
|
+
features: {},
|
|
851
|
+
config: {
|
|
852
|
+
...ccsConfig,
|
|
853
|
+
context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', description: 'desc', existingCommDefinitionId: 'cd_existing_1' },
|
|
854
|
+
},
|
|
855
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
856
|
+
onSave,
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
860
|
+
|
|
861
|
+
await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
|
|
862
|
+
expect(editCommDefinition).toHaveBeenCalledWith(
|
|
863
|
+
'cd_existing_1',
|
|
864
|
+
expect.objectContaining({
|
|
865
|
+
referenceId: 'ORDER_PLACED',
|
|
866
|
+
description: 'desc',
|
|
867
|
+
strategyType: 'SINGLE',
|
|
868
|
+
settings: expect.anything(),
|
|
869
|
+
singleChannelStrategy: expect.anything(),
|
|
870
|
+
}),
|
|
871
|
+
);
|
|
872
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
873
|
+
|
|
874
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
875
|
+
expect(onSave).toHaveBeenCalledWith(
|
|
876
|
+
expect.objectContaining({
|
|
877
|
+
ccsCommDefinition: {
|
|
878
|
+
id: 'cd_existing_1',
|
|
879
|
+
referenceId: 'ORDER_PLACED',
|
|
880
|
+
version: 2,
|
|
881
|
+
status: 'DRAFT',
|
|
882
|
+
},
|
|
883
|
+
}),
|
|
884
|
+
);
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it('blocks save and shows an error when editCommDefinition resolves with a duplicate REFERENCE_ID_EXISTS conflict', async () => {
|
|
888
|
+
editCommDefinition.mockResolvedValue({
|
|
889
|
+
success: false,
|
|
890
|
+
status: { isError: true, code: 409, message: 'REFERENCE_ID_EXISTS' },
|
|
891
|
+
message: 'REFERENCE_ID_EXISTS',
|
|
892
|
+
});
|
|
893
|
+
const onSave = jest.fn();
|
|
894
|
+
renderWithFlow({
|
|
895
|
+
features: {},
|
|
896
|
+
config: {
|
|
897
|
+
...ccsConfig,
|
|
898
|
+
context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
|
|
899
|
+
},
|
|
900
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
901
|
+
onSave,
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
905
|
+
|
|
906
|
+
await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
|
|
907
|
+
expect(await screen.findByText(/already in use in your organization/i)).toBeInTheDocument();
|
|
908
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
500
909
|
});
|
|
501
910
|
});
|
|
502
911
|
|
|
@@ -552,39 +961,34 @@ describe('optional chaining safety', () => {
|
|
|
552
961
|
jest.clearAllMocks();
|
|
553
962
|
});
|
|
554
963
|
|
|
555
|
-
it('
|
|
556
|
-
|
|
964
|
+
it('does not crash and skips CCS when config.context is entirely absent', async () => {
|
|
965
|
+
const onSave = jest.fn();
|
|
557
966
|
renderWithFlow({
|
|
558
967
|
features: {},
|
|
968
|
+
config: { ...baseConfig, features: {} },
|
|
559
969
|
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
970
|
+
onSave,
|
|
560
971
|
});
|
|
561
972
|
|
|
562
973
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
563
974
|
|
|
564
|
-
await waitFor(() => expect(
|
|
565
|
-
expect(
|
|
566
|
-
expect.objectContaining({
|
|
567
|
-
centralCommsPayload: expect.objectContaining({ ouId: -1 }),
|
|
568
|
-
}),
|
|
569
|
-
);
|
|
975
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
976
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
570
977
|
});
|
|
571
978
|
|
|
572
|
-
it('
|
|
573
|
-
|
|
979
|
+
it('does not crash when config.context is present but empty', async () => {
|
|
980
|
+
const onSave = jest.fn();
|
|
574
981
|
renderWithFlow({
|
|
575
982
|
features: {},
|
|
576
|
-
config: { ...baseConfig,
|
|
983
|
+
config: { ...baseConfig, context: {}, features: {} },
|
|
577
984
|
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
985
|
+
onSave,
|
|
578
986
|
});
|
|
579
987
|
|
|
580
988
|
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
581
989
|
|
|
582
|
-
await waitFor(() => expect(
|
|
583
|
-
expect(
|
|
584
|
-
expect.objectContaining({
|
|
585
|
-
centralCommsPayload: expect.objectContaining({ module: 'LOYALTY' }),
|
|
586
|
-
}),
|
|
587
|
-
);
|
|
990
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
991
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
588
992
|
});
|
|
589
993
|
|
|
590
994
|
it('initializes channel from config.channel when initialData.channel is absent', () => {
|
|
@@ -628,3 +1032,51 @@ describe('optional chaining safety', () => {
|
|
|
628
1032
|
expect(screen.getByRole('button', { name: /^save$/i })).toBeDisabled();
|
|
629
1033
|
});
|
|
630
1034
|
});
|
|
1035
|
+
|
|
1036
|
+
describe('step dividers', () => {
|
|
1037
|
+
it('renders a divider after CommunicationStrategyStep and after ChannelSelectionStep when both render together', () => {
|
|
1038
|
+
const { container } = renderWithFlow({
|
|
1039
|
+
features: {
|
|
1040
|
+
communicationStrategyData: { required: true, options: STRATEGY_OPTIONS },
|
|
1041
|
+
contentTemplateData: { required: true, channels: CHANNELS },
|
|
1042
|
+
},
|
|
1043
|
+
initialData: {
|
|
1044
|
+
communicationStrategy: SINGLE_TEMPLATE,
|
|
1045
|
+
contentItems: [{ channel: 'SMS', templateData: {} }],
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
// Each rendered step (CommunicationStrategyStep, ChannelSelectionStep) emits its
|
|
1049
|
+
// own trailing divider.
|
|
1050
|
+
expect(container.querySelectorAll('.ant-divider')).toHaveLength(2);
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
it('omits the divider after ChannelSelectionStep when no content has been added yet', () => {
|
|
1054
|
+
const { container } = renderWithFlow({
|
|
1055
|
+
features: {
|
|
1056
|
+
communicationStrategyData: { required: true, options: STRATEGY_OPTIONS },
|
|
1057
|
+
contentTemplateData: { required: true, channels: CHANNELS },
|
|
1058
|
+
},
|
|
1059
|
+
initialData: {
|
|
1060
|
+
communicationStrategy: SINGLE_TEMPLATE,
|
|
1061
|
+
contentItems: [],
|
|
1062
|
+
},
|
|
1063
|
+
});
|
|
1064
|
+
// Neither divider renders — both CommunicationStrategyStep's and ChannelSelectionStep's
|
|
1065
|
+
// own trailing dividers are conditional on content existing, to avoid a dangling line
|
|
1066
|
+
// around an empty "Add creative" state.
|
|
1067
|
+
expect(container.querySelectorAll('.ant-divider')).toHaveLength(0);
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
it('renders the divider after CommunicationStrategyStep unconditionally when no CHANNEL_SELECTION step follows', () => {
|
|
1071
|
+
const { container } = renderWithFlow({
|
|
1072
|
+
features: {
|
|
1073
|
+
communicationStrategyData: { required: true, options: STRATEGY_OPTIONS },
|
|
1074
|
+
// contentTemplateData.required omitted — no CHANNEL_SELECTION step in this flow.
|
|
1075
|
+
},
|
|
1076
|
+
initialData: {
|
|
1077
|
+
communicationStrategy: SINGLE_TEMPLATE,
|
|
1078
|
+
},
|
|
1079
|
+
});
|
|
1080
|
+
expect(container.querySelectorAll('.ant-divider')).toHaveLength(1);
|
|
1081
|
+
});
|
|
1082
|
+
});
|