@capillarytech/creatives-library 9.0.55-alpha.2 → 9.0.55

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 (32) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/constants/unified.js +1 -0
  3. package/package.json +1 -1
  4. package/services/api.js +0 -12
  5. package/utils/common.js +4 -0
  6. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +0 -13
  7. package/v2Components/CommonTestAndPreview/constants.js +0 -2
  8. package/v2Components/CommonTestAndPreview/index.js +4 -1
  9. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +0 -106
  10. package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -9
  11. package/v2Containers/CommunicationFlow/CommunicationFlow.js +56 -109
  12. package/v2Containers/CommunicationFlow/CommunicationFlow.scss +1 -1
  13. package/v2Containers/CommunicationFlow/CommunicationFlowCard.js +6 -22
  14. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +49 -421
  15. package/v2Containers/CommunicationFlow/Tests/CommunicationFlowCard.test.js +2 -18
  16. package/v2Containers/CommunicationFlow/constants.js +4 -63
  17. package/v2Containers/CommunicationFlow/index.js +20 -15
  18. package/v2Containers/CommunicationFlow/messages.js +0 -4
  19. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +0 -6
  20. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +0 -25
  21. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +4 -11
  22. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +5 -19
  23. package/v2Containers/CreativesContainer/index.js +7 -1
  24. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +5 -5
  25. package/v2Containers/Rcs/constants.js +1 -0
  26. package/v2Containers/Rcs/index.js +10 -1
  27. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +120 -12
  28. package/v2Containers/Rcs/tests/index.test.js +121 -0
  29. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +3 -3
  30. package/v2Containers/Templates/index.js +26 -0
  31. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -34
  32. package/v2Containers/CommunicationFlow/Tests/constants.test.js +0 -85
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
 
3
3
  jest.mock('../../../services/api', () => ({
4
- createCommDefinition: jest.fn(),
5
- editCommDefinition: jest.fn(),
4
+ createCentralCommsMetaId: jest.fn(),
5
+ getCentralCommsMetaIds: 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 { createCommDefinition, editCommDefinition } from '../../../services/api';
41
+ import { createCentralCommsMetaId, getCentralCommsMetaIds } from '../../../services/api';
42
42
  import { getEnabledSteps } from '../utils/getEnabledSteps';
43
43
  import {
44
44
  CHANNELS,
@@ -359,313 +359,82 @@ describe('isSaveDisabled', () => {
359
359
  });
360
360
 
361
361
  describe('handleSave — CCS flow', () => {
362
- const ccsConfig = { ...baseConfig, context: { name: 'Order Placed Notification' }, features: {} };
363
-
364
362
  beforeEach(() => {
365
- createCommDefinition.mockResolvedValue({
366
- response: { data: { id: 'cd_123', referenceId: 'ORDER_PLACED_123', status: 'DRAFT', version: { version: 1 } } },
367
- });
363
+ createCentralCommsMetaId.mockResolvedValue({ response: { data: { id: 'meta-123' } } });
364
+ getCentralCommsMetaIds.mockResolvedValue({ response: { data: {} } });
368
365
  });
369
366
 
370
367
  afterEach(() => {
371
368
  jest.clearAllMocks();
372
369
  });
373
370
 
374
- it('calls createCommDefinition with a SINGLE-strategy payload when useCCS is not false', async () => {
371
+ it('calls createCentralCommsMetaId for each content item when useCCS is not false', async () => {
375
372
  const onSave = jest.fn();
376
373
  renderWithFlow({
377
374
  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.
382
375
  initialData: {
383
- contentItems: [{ channel: 'sms', templateData: { messageBody: 'Hello' } }],
376
+ contentItems: [{ channel: 'sms', templateData: { smsBody: 'Hello' } }],
384
377
  },
385
378
  onSave,
386
379
  });
387
380
 
388
381
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
389
382
 
390
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
391
- expect(createCommDefinition).toHaveBeenCalledWith(
383
+ await waitFor(() => expect(createCentralCommsMetaId).toHaveBeenCalledTimes(1));
384
+ expect(createCentralCommsMetaId).toHaveBeenCalledWith(
392
385
  expect.objectContaining({
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
- }),
386
+ centralCommsPayload: expect.objectContaining({ channel: 'SMS', module: 'CAMPAIGNS' }),
401
387
  }),
402
388
  );
403
389
  expect(onSave).toHaveBeenCalledTimes(1);
404
390
  });
405
391
 
406
- it('transforms SMS content from the legacy editor shape (messageBody) to CCS\'s message field', async () => {
407
- const onSave = jest.fn();
408
- renderWithFlow({
409
- features: {},
410
- config: ccsConfig,
411
- initialData: {
412
- contentItems: [{
413
- channel: 'SMS',
414
- templateData: { messageBody: 'Hello {{name}}', channel: 'SMS' },
415
- }],
416
- },
417
- onSave,
418
- });
419
-
420
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
421
-
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
- );
436
- });
437
-
438
- it('does not carry the legacy messageBody key into smsMessageContent (regression guard against reverting to pass-through)', async () => {
439
- const onSave = jest.fn();
440
- renderWithFlow({
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();
392
+ it('calls getCentralCommsMetaIds when metaIds are returned from createCentralCommsMetaId', async () => {
540
393
  renderWithFlow({
541
394
  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,
395
+ initialData: { contentItems: [{ channel: 'EMAIL', templateData: {} }] },
555
396
  });
556
397
 
557
398
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
558
399
 
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
- );
400
+ await waitFor(() => expect(getCentralCommsMetaIds).toHaveBeenCalledWith('meta-123'));
573
401
  });
574
402
 
575
- it('merges ccsCommDefinition into the data passed to onSave when create succeeds', async () => {
576
- const onSave = jest.fn();
403
+ it('skips getCentralCommsMetaIds when response contains no id', async () => {
404
+ createCentralCommsMetaId.mockResolvedValue({ response: { data: {} } });
577
405
  renderWithFlow({
578
406
  features: {},
579
- config: ccsConfig,
580
407
  initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
581
- onSave,
582
408
  });
583
409
 
584
410
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
585
411
 
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
- );
412
+ await waitFor(() => expect(createCentralCommsMetaId).toHaveBeenCalled());
413
+ expect(getCentralCommsMetaIds).not.toHaveBeenCalled();
592
414
  });
593
415
 
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
- });
416
+ it('uses ouId and module from config.context when provided', async () => {
599
417
  renderWithFlow({
600
418
  features: {},
601
- config: ccsConfig,
419
+ config: { ...baseConfig, context: { ouId: 42, module: 'LOYALTY' }, features: {} },
602
420
  initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
603
- onSave,
604
421
  });
605
422
 
606
423
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
607
424
 
608
- await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
609
- expect(onSave).toHaveBeenCalledWith(
425
+ await waitFor(() => expect(createCentralCommsMetaId).toHaveBeenCalled());
426
+ expect(createCentralCommsMetaId).toHaveBeenCalledWith(
610
427
  expect.objectContaining({
611
- ccsCommDefinition: { id: 'cd_123', referenceId: 'ORDER_PLACED_123', version: 0, status: 'DRAFT' },
428
+ centralCommsPayload: expect.objectContaining({ ouId: 42, module: 'LOYALTY' }),
612
429
  }),
613
430
  );
614
431
  });
615
432
 
616
- it('generates a referenceId from name when config.context.referenceId is absent', async () => {
617
- // moduleMocks.js spies on Date.now globally, but this config's resetMocks:true
618
- // clears that return value before every test — set it explicitly here.
619
- jest.spyOn(Date, 'now').mockReturnValue(1612267539410);
620
- renderWithFlow({
621
- features: {},
622
- config: ccsConfig,
623
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
624
- });
625
-
626
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
627
-
628
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
629
- const payload = createCommDefinition.mock.calls[0][0];
630
- expect(payload.referenceId).toBe('ORDER_PLACED_NOTIFICATION_1612267539410');
631
- });
632
-
633
- it('uses config.context.referenceId and description when provided', async () => {
634
- renderWithFlow({
635
- features: {},
636
- config: { ...ccsConfig, context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', description: 'desc' } },
637
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
638
- });
639
-
640
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
641
-
642
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
643
- expect(createCommDefinition).toHaveBeenCalledWith(
644
- expect.objectContaining({ referenceId: 'ORDER_PLACED', description: 'desc' }),
645
- );
646
- });
647
-
648
433
  it('skips CCS entirely when useCCS is false', async () => {
649
434
  const onSave = jest.fn();
650
435
  renderWithFlow({
651
436
  features: {},
652
- config: { ...ccsConfig, useCCS: false },
653
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
654
- onSave,
655
- });
656
-
657
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
658
-
659
- await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
660
- expect(createCommDefinition).not.toHaveBeenCalled();
661
- expect(onSave).toHaveBeenCalledWith(expect.not.objectContaining({ ccsCommDefinition: expect.anything() }));
662
- });
663
-
664
- it('skips createCommDefinition when config.context.name is absent (mandatory)', async () => {
665
- const onSave = jest.fn();
666
- renderWithFlow({
667
- features: {},
668
- config: { ...baseConfig, features: {} },
437
+ config: { ...baseConfig, useCCS: false, features: {} },
669
438
  initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
670
439
  onSave,
671
440
  });
@@ -673,34 +442,14 @@ describe('handleSave — CCS flow', () => {
673
442
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
674
443
 
675
444
  await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
676
- expect(createCommDefinition).not.toHaveBeenCalled();
677
- });
678
-
679
- it('skips createCommDefinition for multi-channel strategies (CHANNEL_PRIORITY/AB_TEST)', async () => {
680
- const onSave = jest.fn();
681
- renderWithFlow({
682
- features: {},
683
- config: ccsConfig,
684
- initialData: {
685
- communicationStrategy: CHANNEL_PRIORITY,
686
- channels: ['SMS', 'EMAIL'],
687
- contentItems: [{ channel: 'SMS', templateData: {} }, { channel: 'EMAIL', templateData: {} }],
688
- },
689
- onSave,
690
- });
691
-
692
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
693
-
694
- await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
695
- expect(createCommDefinition).not.toHaveBeenCalled();
445
+ expect(createCentralCommsMetaId).not.toHaveBeenCalled();
696
446
  });
697
447
 
698
- it('still calls onSave (without ccsCommDefinition) when createCommDefinition rejects', async () => {
699
- createCommDefinition.mockRejectedValue(new Error('Network error'));
448
+ it('still calls onSave when createCentralCommsMetaId rejects', async () => {
449
+ createCentralCommsMetaId.mockRejectedValue(new Error('Network error'));
700
450
  const onSave = jest.fn();
701
451
  renderWithFlow({
702
452
  features: {},
703
- config: ccsConfig,
704
453
  initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
705
454
  onSave,
706
455
  });
@@ -708,35 +457,12 @@ describe('handleSave — CCS flow', () => {
708
457
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
709
458
 
710
459
  await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
711
- expect(onSave).toHaveBeenCalledWith(expect.not.objectContaining({ ccsCommDefinition: expect.anything() }));
712
460
  });
713
461
 
714
- it('blocks save and shows an error when createCommDefinition resolves with a duplicate REFERENCE_ID_EXISTS conflict', async () => {
715
- createCommDefinition.mockResolvedValue({
716
- success: false,
717
- status: { isError: true, code: 409, message: 'REFERENCE_ID_EXISTS' },
718
- message: 'REFERENCE_ID_EXISTS',
719
- });
462
+ it('skips createCentralCommsMetaId when contentItems is empty', async () => {
720
463
  const onSave = jest.fn();
721
464
  renderWithFlow({
722
465
  features: {},
723
- config: ccsConfig,
724
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
725
- onSave,
726
- });
727
-
728
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
729
-
730
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
731
- expect(await screen.findByText(/already in use in your organization/i)).toBeInTheDocument();
732
- expect(onSave).not.toHaveBeenCalled();
733
- });
734
-
735
- it('skips createCommDefinition when contentItems is empty', async () => {
736
- const onSave = jest.fn();
737
- renderWithFlow({
738
- features: {},
739
- config: ccsConfig,
740
466
  initialData: { contentItems: [] },
741
467
  onSave,
742
468
  });
@@ -744,13 +470,12 @@ describe('handleSave — CCS flow', () => {
744
470
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
745
471
 
746
472
  await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
747
- expect(createCommDefinition).not.toHaveBeenCalled();
473
+ expect(createCentralCommsMetaId).not.toHaveBeenCalled();
748
474
  });
749
475
 
750
- it('places additionalSettings derived from dynamicControls under settings.additionalSettings (not delivery settings)', async () => {
476
+ it('includes additionalSettings derived from dynamicControls in the payload', async () => {
751
477
  renderWithFlow({
752
478
  features: {},
753
- config: ccsConfig,
754
479
  initialData: {
755
480
  contentItems: [{ channel: 'SMS', templateData: {} }],
756
481
  dynamicControls: {
@@ -764,116 +489,14 @@ describe('handleSave — CCS flow', () => {
764
489
 
765
490
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
766
491
 
767
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
768
- const payload = createCommDefinition.mock.calls[0][0];
769
- expect(payload.settings.additionalSettings).toEqual({
492
+ await waitFor(() => expect(createCentralCommsMetaId).toHaveBeenCalled());
493
+ const payload = createCentralCommsMetaId.mock.calls[0][0];
494
+ expect(payload.centralCommsPayload.smsDeliverySettings.additionalSettings).toEqual({
770
495
  useTinyUrl: true,
771
496
  encryptUrl: true,
772
497
  linkTrackingEnabled: true,
773
498
  userSubscriptionDisabled: true,
774
499
  });
775
- expect(payload.singleChannelStrategy.variant.smsDeliverySettings.additionalSettings).toBeUndefined();
776
- });
777
-
778
- it('includes channelSettings from deliverySetting.channelSetting in the payload', async () => {
779
- renderWithFlow({
780
- features: {},
781
- config: ccsConfig,
782
- initialData: {
783
- contentItems: [{ channel: 'SMS', templateData: {} }],
784
- deliverySetting: { channelSetting: { SMS: { domainId: 1001, gsmSenderId: 'BRAND1' } } },
785
- },
786
- });
787
-
788
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
789
-
790
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalled());
791
- const payload = createCommDefinition.mock.calls[0][0];
792
- expect(payload.singleChannelStrategy.variant.smsDeliverySettings.channelSettings).toEqual({
793
- channel: 'SMS',
794
- domainId: 1001,
795
- gsmSenderId: 'BRAND1',
796
- });
797
- });
798
-
799
- it('does not call editCommDefinition when config.context.existingCommDefinitionId is absent', async () => {
800
- const onSave = jest.fn();
801
- renderWithFlow({
802
- features: {},
803
- config: ccsConfig,
804
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
805
- onSave,
806
- });
807
-
808
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
809
-
810
- await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
811
- expect(editCommDefinition).not.toHaveBeenCalled();
812
- });
813
-
814
- it('calls editCommDefinition (not createCommDefinition) and merges the existing id into ccsCommDefinition when config.context.existingCommDefinitionId is set', async () => {
815
- editCommDefinition.mockResolvedValue({
816
- response: { data: { version: { version: 2 }, status: 'DRAFT' } },
817
- });
818
- const onSave = jest.fn();
819
- renderWithFlow({
820
- features: {},
821
- config: {
822
- ...ccsConfig,
823
- context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
824
- },
825
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
826
- onSave,
827
- });
828
-
829
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
830
-
831
- await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
832
- expect(editCommDefinition).toHaveBeenCalledWith(
833
- 'cd_existing_1',
834
- expect.objectContaining({
835
- strategyType: 'SINGLE',
836
- settings: expect.anything(),
837
- singleChannelStrategy: expect.anything(),
838
- }),
839
- );
840
- expect(createCommDefinition).not.toHaveBeenCalled();
841
-
842
- await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
843
- expect(onSave).toHaveBeenCalledWith(
844
- expect.objectContaining({
845
- ccsCommDefinition: {
846
- id: 'cd_existing_1',
847
- referenceId: 'ORDER_PLACED',
848
- version: 2,
849
- status: 'DRAFT',
850
- },
851
- }),
852
- );
853
- });
854
-
855
- it('blocks save and shows an error when editCommDefinition resolves with a duplicate REFERENCE_ID_EXISTS conflict', async () => {
856
- editCommDefinition.mockResolvedValue({
857
- success: false,
858
- status: { isError: true, code: 409, message: 'REFERENCE_ID_EXISTS' },
859
- message: 'REFERENCE_ID_EXISTS',
860
- });
861
- const onSave = jest.fn();
862
- renderWithFlow({
863
- features: {},
864
- config: {
865
- ...ccsConfig,
866
- context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
867
- },
868
- initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
869
- onSave,
870
- });
871
-
872
- await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
873
-
874
- await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
875
- expect(await screen.findByText(/already in use in your organization/i)).toBeInTheDocument();
876
- expect(onSave).not.toHaveBeenCalled();
877
500
  });
878
501
  });
879
502
 
@@ -929,34 +552,39 @@ describe('optional chaining safety', () => {
929
552
  jest.clearAllMocks();
930
553
  });
931
554
 
932
- it('does not crash and skips CCS when config.context is entirely absent', async () => {
933
- const onSave = jest.fn();
555
+ it('defaults ouId to -1 when config.context is absent', async () => {
556
+ createCentralCommsMetaId.mockResolvedValue({ response: { data: { id: 'x' } } });
934
557
  renderWithFlow({
935
558
  features: {},
936
- config: { ...baseConfig, features: {} },
937
559
  initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
938
- onSave,
939
560
  });
940
561
 
941
562
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
942
563
 
943
- await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
944
- expect(createCommDefinition).not.toHaveBeenCalled();
564
+ await waitFor(() => expect(createCentralCommsMetaId).toHaveBeenCalled());
565
+ expect(createCentralCommsMetaId).toHaveBeenCalledWith(
566
+ expect.objectContaining({
567
+ centralCommsPayload: expect.objectContaining({ ouId: -1 }),
568
+ }),
569
+ );
945
570
  });
946
571
 
947
- it('does not crash when config.context is present but empty', async () => {
948
- const onSave = jest.fn();
572
+ it('defaults module to consumer.toUpperCase() when config.context.module absent', async () => {
573
+ createCentralCommsMetaId.mockResolvedValue({ response: { data: { id: 'x' } } });
949
574
  renderWithFlow({
950
575
  features: {},
951
- config: { ...baseConfig, context: {}, features: {} },
576
+ config: { ...baseConfig, consumer: 'loyalty', features: {} },
952
577
  initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
953
- onSave,
954
578
  });
955
579
 
956
580
  await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
957
581
 
958
- await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
959
- expect(createCommDefinition).not.toHaveBeenCalled();
582
+ await waitFor(() => expect(createCentralCommsMetaId).toHaveBeenCalled());
583
+ expect(createCentralCommsMetaId).toHaveBeenCalledWith(
584
+ expect.objectContaining({
585
+ centralCommsPayload: expect.objectContaining({ module: 'LOYALTY' }),
586
+ }),
587
+ );
960
588
  });
961
589
 
962
590
  it('initializes channel from config.channel when initialData.channel is absent', () => {
@@ -108,22 +108,6 @@ describe('CommunicationFlowCard', () => {
108
108
  fireEvent.click(screen.getByText('Add creatives'));
109
109
  expect(screen.getByTestId('comm-flow-mock')).toHaveAttribute('data-mode', 'create');
110
110
  });
111
-
112
- it('disables the Add creatives button when disabled prop is true', () => {
113
- renderCard({ disabled: true, disabledTooltip: 'Enter an Alert name to add content' });
114
- expect(screen.getByText('Add creatives').closest('button')).toBeDisabled();
115
- });
116
-
117
- it('does not open SlideBox when Add creatives is clicked while disabled', () => {
118
- renderCard({ disabled: true, disabledTooltip: 'Enter an Alert name to add content' });
119
- fireEvent.click(screen.getByText('Add creatives'));
120
- expect(screen.queryByTestId('slide-box')).not.toBeInTheDocument();
121
- });
122
-
123
- it('Add creatives button is enabled by default (disabled prop absent)', () => {
124
- renderCard();
125
- expect(screen.getByText('Add creatives').closest('button')).not.toBeDisabled();
126
- });
127
111
  });
128
112
 
129
113
  describe('configured state (initialData provided)', () => {
@@ -247,11 +231,11 @@ describe('CommunicationFlowCard', () => {
247
231
  expect(screen.getByText(/Sender ID/)).toBeInTheDocument();
248
232
  });
249
233
 
250
- it('shows senderId for EMAIL with Sender ID label', () => {
234
+ it('shows senderEmail for EMAIL with Sender ID label', () => {
251
235
  renderCard({
252
236
  initialData: makeSavedData({
253
237
  contentItems: [{ channel: 'EMAIL', templateData: {} }],
254
- deliverySetting: { channelSetting: { EMAIL: { senderId: 'test@example.com' } } },
238
+ deliverySetting: { channelSetting: { EMAIL: { senderEmail: 'test@example.com' } } },
255
239
  }),
256
240
  });
257
241
  expect(screen.getByText(/test@example.com/)).toBeInTheDocument();