@capillarytech/creatives-library 8.0.359-alpha.0 → 8.0.360-alpha.0
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/index.html +1 -0
- package/package.json +1 -1
- package/utils/cdnTransformation.js +75 -3
- package/utils/tests/cdnTransformation.test.js +127 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +16 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +132 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +2 -37
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +169 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +55 -85
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +127 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +52 -6
- package/v2Components/CommonTestAndPreview/constants.js +2 -0
- package/v2Components/CommonTestAndPreview/index.js +67 -3
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +163 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +522 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +255 -0
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +2 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +194 -0
- package/v2Components/FormBuilder/index.js +162 -52
- package/v2Components/TestAndPreviewSlidebox/index.js +2 -2
- package/v2Containers/App/constants.js +3 -0
- package/v2Containers/App/tests/constants.test.js +61 -0
- package/v2Containers/CreativesContainer/index.js +60 -24
- package/v2Containers/Templates/index.js +72 -2
- package/v2Containers/Templates/sagas.js +6 -1
- package/v2Containers/Templates/tests/sagas.test.js +23 -6
- package/v2Containers/Templates/tests/webpush.test.js +375 -0
- package/v2Containers/Viber/index.js +24 -18
- package/v2Containers/Viber/index.scss +27 -0
- package/v2Containers/Viber/messages.js +4 -4
- package/v2Containers/WebPush/Create/index.js +91 -8
- package/v2Containers/WebPush/Create/index.scss +7 -0
- package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +348 -0
- package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +325 -0
|
@@ -514,4 +514,167 @@ describe('PreviewHeader', () => {
|
|
|
514
514
|
consoleSpy.mockRestore();
|
|
515
515
|
});
|
|
516
516
|
});
|
|
517
|
+
|
|
518
|
+
describe('WEBPUSH channel - Fullscreen expander', () => {
|
|
519
|
+
it('should render expander icon for WEBPUSH channel', () => {
|
|
520
|
+
const setIsFullscreenOpen = jest.fn();
|
|
521
|
+
const props = {
|
|
522
|
+
...defaultProps,
|
|
523
|
+
channel: CHANNELS.WEBPUSH,
|
|
524
|
+
setIsFullscreenOpen,
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
const { container } = render(
|
|
528
|
+
<TestWrapper>
|
|
529
|
+
<PreviewHeader {...props} />
|
|
530
|
+
</TestWrapper>
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
// expander icon should be present for WEBPUSH
|
|
534
|
+
const expanderIcon = container.querySelector('[class*="expander"], [aria-label*="expander"], .anticon');
|
|
535
|
+
expect(expanderIcon).toBeTruthy();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('should NOT render expander icon for non-WEBPUSH channels', () => {
|
|
539
|
+
const setIsFullscreenOpen = jest.fn();
|
|
540
|
+
const props = {
|
|
541
|
+
...defaultProps,
|
|
542
|
+
channel: CHANNELS.EMAIL,
|
|
543
|
+
setIsFullscreenOpen,
|
|
544
|
+
showDeviceToggle: false,
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
const { container } = render(
|
|
548
|
+
<TestWrapper>
|
|
549
|
+
<PreviewHeader {...props} />
|
|
550
|
+
</TestWrapper>
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
// No expander icon for EMAIL channel (only device toggle icons may appear)
|
|
554
|
+
const expanderIcon = container.querySelector('[class*="expander"]');
|
|
555
|
+
expect(expanderIcon).toBeNull();
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it('should call setIsFullscreenOpen(true) when expander icon is clicked', () => {
|
|
559
|
+
const setIsFullscreenOpen = jest.fn();
|
|
560
|
+
const props = {
|
|
561
|
+
...defaultProps,
|
|
562
|
+
channel: CHANNELS.WEBPUSH,
|
|
563
|
+
setIsFullscreenOpen,
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const { container } = render(
|
|
567
|
+
<TestWrapper>
|
|
568
|
+
<PreviewHeader {...props} />
|
|
569
|
+
</TestWrapper>
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
const expanderIcon = container.querySelector('[class*="expander"]') ||
|
|
573
|
+
container.querySelector('.anticon');
|
|
574
|
+
if (expanderIcon) {
|
|
575
|
+
fireEvent.click(expanderIcon);
|
|
576
|
+
expect(setIsFullscreenOpen).toHaveBeenCalledWith(true);
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it('should render expander icon without ACTIVE class when device is MOBILE', () => {
|
|
581
|
+
const setIsFullscreenOpen = jest.fn();
|
|
582
|
+
const props = {
|
|
583
|
+
...defaultProps,
|
|
584
|
+
channel: CHANNELS.WEBPUSH,
|
|
585
|
+
device: MOBILE,
|
|
586
|
+
setIsFullscreenOpen,
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
const { container } = render(
|
|
590
|
+
<TestWrapper>
|
|
591
|
+
<PreviewHeader {...props} />
|
|
592
|
+
</TestWrapper>
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
// Expander icon no longer adds ACTIVE class based on device
|
|
596
|
+
const activeEl = container.querySelector('.active');
|
|
597
|
+
expect(activeEl).toBeNull();
|
|
598
|
+
// But the expander icon itself should still be present
|
|
599
|
+
const expanderIcon = container.querySelector('[class*="expander"]') ||
|
|
600
|
+
container.querySelector('.anticon');
|
|
601
|
+
expect(expanderIcon).toBeTruthy();
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('should render expander icon without ACTIVE class when device is DESKTOP', () => {
|
|
605
|
+
const setIsFullscreenOpen = jest.fn();
|
|
606
|
+
const props = {
|
|
607
|
+
...defaultProps,
|
|
608
|
+
channel: CHANNELS.WEBPUSH,
|
|
609
|
+
device: DESKTOP,
|
|
610
|
+
setIsFullscreenOpen,
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
const { container } = render(
|
|
614
|
+
<TestWrapper>
|
|
615
|
+
<PreviewHeader {...props} />
|
|
616
|
+
</TestWrapper>
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
// Expander icon does not have ACTIVE class for any device
|
|
620
|
+
const activeEl = container.querySelector('.active');
|
|
621
|
+
expect(activeEl).toBeNull();
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
it('should render expander icon alongside device content for WEBPUSH', () => {
|
|
625
|
+
// Note: suppression of showDeviceToggle for WEBPUSH is done in UnifiedPreview (parent),
|
|
626
|
+
// not in PreviewHeader itself. PreviewHeader only adds the expander icon for WEBPUSH.
|
|
627
|
+
const setIsFullscreenOpen = jest.fn();
|
|
628
|
+
const props = {
|
|
629
|
+
...defaultProps,
|
|
630
|
+
channel: CHANNELS.WEBPUSH,
|
|
631
|
+
setIsFullscreenOpen,
|
|
632
|
+
showDeviceToggle: false,
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
const { container } = render(
|
|
636
|
+
<TestWrapper>
|
|
637
|
+
<PreviewHeader {...props} />
|
|
638
|
+
</TestWrapper>
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
// expander icon should be present for WEBPUSH
|
|
642
|
+
const expanderIcon = container.querySelector('[class*="expander"]') ||
|
|
643
|
+
container.querySelector('.anticon');
|
|
644
|
+
expect(expanderIcon).toBeTruthy();
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('should accept isFullscreenOpen and setIsFullscreenOpen as props', () => {
|
|
648
|
+
const setIsFullscreenOpen = jest.fn();
|
|
649
|
+
const props = {
|
|
650
|
+
...defaultProps,
|
|
651
|
+
channel: CHANNELS.WEBPUSH,
|
|
652
|
+
isFullscreenOpen: false,
|
|
653
|
+
setIsFullscreenOpen,
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
expect(() =>
|
|
657
|
+
render(
|
|
658
|
+
<TestWrapper>
|
|
659
|
+
<PreviewHeader {...props} />
|
|
660
|
+
</TestWrapper>
|
|
661
|
+
)
|
|
662
|
+
).not.toThrow();
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
it('should use default setIsFullscreenOpen when not provided', () => {
|
|
666
|
+
const props = {
|
|
667
|
+
...defaultProps,
|
|
668
|
+
channel: CHANNELS.WEBPUSH,
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
expect(() =>
|
|
672
|
+
render(
|
|
673
|
+
<TestWrapper>
|
|
674
|
+
<PreviewHeader {...props} />
|
|
675
|
+
</TestWrapper>
|
|
676
|
+
)
|
|
677
|
+
).not.toThrow();
|
|
678
|
+
});
|
|
679
|
+
});
|
|
517
680
|
});
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for WebPushPreviewContent Component
|
|
3
|
+
*
|
|
4
|
+
* Covers: OS/browser state, fullscreen modal, isUpdating/error early-returns,
|
|
5
|
+
* handleOSChange, handleBrowserChange, handleCloseFullscreen, browser coercion effect.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { render, screen, fireEvent, act } from '@testing-library/react';
|
|
10
|
+
import '@testing-library/jest-dom';
|
|
11
|
+
import { IntlProvider } from 'react-intl';
|
|
12
|
+
import WebPushPreviewContent from '../../UnifiedPreview/WebPushPreviewContent';
|
|
13
|
+
import messages from '../../messages';
|
|
14
|
+
|
|
15
|
+
const messagesForIntl = Object.keys(messages).reduce((acc, key) => {
|
|
16
|
+
const msg = messages[key];
|
|
17
|
+
acc[msg.id] = msg.defaultMessage;
|
|
18
|
+
return acc;
|
|
19
|
+
}, {});
|
|
20
|
+
|
|
21
|
+
const TestWrapper = ({ children }) => (
|
|
22
|
+
<IntlProvider locale="en" messages={messagesForIntl}>
|
|
23
|
+
{children}
|
|
24
|
+
</IntlProvider>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Mock heavy child components
|
|
28
|
+
jest.mock('../../../../v2Containers/WebPush/Create/preview/PreviewControls', () => ({
|
|
29
|
+
__esModule: true,
|
|
30
|
+
default: (props) => (
|
|
31
|
+
<div data-testid="preview-controls">
|
|
32
|
+
<button
|
|
33
|
+
data-testid="os-change-btn"
|
|
34
|
+
onClick={() => props.onOSChange('Windows')}
|
|
35
|
+
>
|
|
36
|
+
Change OS
|
|
37
|
+
</button>
|
|
38
|
+
<button
|
|
39
|
+
data-testid="browser-change-btn"
|
|
40
|
+
onClick={() => props.onBrowserChange('Firefox')}
|
|
41
|
+
>
|
|
42
|
+
Change Browser
|
|
43
|
+
</button>
|
|
44
|
+
<div data-testid="selected-os">{props.selectedOS}</div>
|
|
45
|
+
<div data-testid="selected-browser">{props.selectedBrowser}</div>
|
|
46
|
+
<div data-testid="browser-options">{JSON.stringify(props.browserOptions)}</div>
|
|
47
|
+
</div>
|
|
48
|
+
),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
jest.mock('../../../../v2Containers/WebPush/Create/preview/PreviewContent', () => ({
|
|
52
|
+
__esModule: true,
|
|
53
|
+
default: (props) => (
|
|
54
|
+
<div data-testid="preview-content">
|
|
55
|
+
<div data-testid="content-title">{props.notificationTitle}</div>
|
|
56
|
+
<div data-testid="content-body">{props.notificationBody}</div>
|
|
57
|
+
<div data-testid="content-url">{props.url}</div>
|
|
58
|
+
<div data-testid="content-os">{props.selectedOS}</div>
|
|
59
|
+
<div data-testid="content-browser">{props.selectedBrowser}</div>
|
|
60
|
+
<div data-testid="content-image">{props.imageSrc}</div>
|
|
61
|
+
<div data-testid="content-icon">{props.brandIconSrc}</div>
|
|
62
|
+
<div data-testid="content-buttons">{JSON.stringify(props.buttons)}</div>
|
|
63
|
+
</div>
|
|
64
|
+
),
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
jest.mock('../../../../v2Containers/WebPush/Create/preview/DevicePreviewContent', () => ({
|
|
68
|
+
__esModule: true,
|
|
69
|
+
default: (props) => (
|
|
70
|
+
<div data-testid="device-preview-content">
|
|
71
|
+
<div data-testid="device-title">{props.notificationTitle}</div>
|
|
72
|
+
<div data-testid="device-body">{props.notificationBody}</div>
|
|
73
|
+
<div data-testid="device-image">{props.imageSrc}</div>
|
|
74
|
+
<div data-testid="device-icon">{props.brandIconSrc}</div>
|
|
75
|
+
</div>
|
|
76
|
+
),
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
// Mock CapModal to render children when visible
|
|
80
|
+
jest.mock('@capillarytech/cap-ui-library/CapModal', () => ({
|
|
81
|
+
__esModule: true,
|
|
82
|
+
default: ({ visible, children, onCancel }) => (
|
|
83
|
+
<div data-testid="cap-modal" data-visible={visible ? 'true' : 'false'}>
|
|
84
|
+
{visible && <div data-testid="modal-content">{children}</div>}
|
|
85
|
+
<button data-testid="modal-cancel" onClick={onCancel}>Cancel</button>
|
|
86
|
+
</div>
|
|
87
|
+
),
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
jest.mock('@capillarytech/cap-ui-library/CapRow', () => ({
|
|
91
|
+
__esModule: true,
|
|
92
|
+
default: ({ children, className }) => <div className={className}>{children}</div>,
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
jest.mock('@capillarytech/cap-ui-library/CapLabel', () => ({
|
|
96
|
+
__esModule: true,
|
|
97
|
+
default: ({ children }) => <span>{children}</span>,
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
jest.mock('@capillarytech/cap-ui-library/CapIcon', () => ({
|
|
101
|
+
__esModule: true,
|
|
102
|
+
default: ({ type, onClick, className }) => (
|
|
103
|
+
<span
|
|
104
|
+
data-testid={`cap-icon-${type}`}
|
|
105
|
+
className={className}
|
|
106
|
+
onClick={onClick}
|
|
107
|
+
/>
|
|
108
|
+
),
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
jest.mock('@capillarytech/cap-ui-library/CapDivider', () => ({
|
|
112
|
+
__esModule: true,
|
|
113
|
+
default: () => <hr data-testid="cap-divider" />,
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
const defaultProps = {
|
|
117
|
+
notificationTitle: 'Test Title',
|
|
118
|
+
notificationBody: 'Test body text',
|
|
119
|
+
imageSrc: 'https://example.com/image.jpg',
|
|
120
|
+
brandIconSrc: 'https://example.com/icon.png',
|
|
121
|
+
buttons: [{ text: 'Click', url: 'https://example.com', type: 'EXTERNAL_URL' }],
|
|
122
|
+
url: 'https://example.com',
|
|
123
|
+
isUpdating: false,
|
|
124
|
+
error: null,
|
|
125
|
+
isFullscreenOpen: false,
|
|
126
|
+
setIsFullscreenOpen: jest.fn(),
|
|
127
|
+
selectedCustomer: null,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
describe('WebPushPreviewContent', () => {
|
|
131
|
+
beforeEach(() => {
|
|
132
|
+
jest.clearAllMocks();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('Early-return guards', () => {
|
|
136
|
+
it('should return null when isUpdating is true', () => {
|
|
137
|
+
const { container } = render(
|
|
138
|
+
<TestWrapper>
|
|
139
|
+
<WebPushPreviewContent {...defaultProps} isUpdating={true} />
|
|
140
|
+
</TestWrapper>
|
|
141
|
+
);
|
|
142
|
+
expect(container.firstChild).toBeNull();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should return null when error is truthy', () => {
|
|
146
|
+
const { container } = render(
|
|
147
|
+
<TestWrapper>
|
|
148
|
+
<WebPushPreviewContent {...defaultProps} error="Something went wrong" />
|
|
149
|
+
</TestWrapper>
|
|
150
|
+
);
|
|
151
|
+
expect(container.firstChild).toBeNull();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should render normally when isUpdating is false and error is null', () => {
|
|
155
|
+
render(
|
|
156
|
+
<TestWrapper>
|
|
157
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
158
|
+
</TestWrapper>
|
|
159
|
+
);
|
|
160
|
+
expect(screen.getByTestId('preview-controls')).toBeTruthy();
|
|
161
|
+
expect(screen.getByTestId('preview-content')).toBeTruthy();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('Initial OS and browser state', () => {
|
|
166
|
+
it('should render with default OS (macOS)', () => {
|
|
167
|
+
render(
|
|
168
|
+
<TestWrapper>
|
|
169
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
170
|
+
</TestWrapper>
|
|
171
|
+
);
|
|
172
|
+
expect(screen.getByTestId('selected-os')).toHaveTextContent('macOS');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should render with default browser (Chrome)', () => {
|
|
176
|
+
render(
|
|
177
|
+
<TestWrapper>
|
|
178
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
179
|
+
</TestWrapper>
|
|
180
|
+
);
|
|
181
|
+
expect(screen.getByTestId('selected-browser')).toHaveTextContent('Chrome');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should pass default OS to PreviewContent', () => {
|
|
185
|
+
render(
|
|
186
|
+
<TestWrapper>
|
|
187
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
188
|
+
</TestWrapper>
|
|
189
|
+
);
|
|
190
|
+
expect(screen.getByTestId('content-os')).toHaveTextContent('macOS');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should pass default browser to PreviewContent', () => {
|
|
194
|
+
render(
|
|
195
|
+
<TestWrapper>
|
|
196
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
197
|
+
</TestWrapper>
|
|
198
|
+
);
|
|
199
|
+
expect(screen.getByTestId('content-browser')).toHaveTextContent('Chrome');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('Props forwarding to PreviewContent', () => {
|
|
204
|
+
it('should pass notificationTitle to PreviewContent', () => {
|
|
205
|
+
render(
|
|
206
|
+
<TestWrapper>
|
|
207
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
208
|
+
</TestWrapper>
|
|
209
|
+
);
|
|
210
|
+
expect(screen.getByTestId('content-title')).toHaveTextContent('Test Title');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should pass notificationBody to PreviewContent', () => {
|
|
214
|
+
render(
|
|
215
|
+
<TestWrapper>
|
|
216
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
217
|
+
</TestWrapper>
|
|
218
|
+
);
|
|
219
|
+
expect(screen.getByTestId('content-body')).toHaveTextContent('Test body text');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should pass url to PreviewContent', () => {
|
|
223
|
+
render(
|
|
224
|
+
<TestWrapper>
|
|
225
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
226
|
+
</TestWrapper>
|
|
227
|
+
);
|
|
228
|
+
expect(screen.getByTestId('content-url')).toHaveTextContent('https://example.com');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should pass imageSrc to PreviewContent', () => {
|
|
232
|
+
render(
|
|
233
|
+
<TestWrapper>
|
|
234
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
235
|
+
</TestWrapper>
|
|
236
|
+
);
|
|
237
|
+
expect(screen.getByTestId('content-image')).toHaveTextContent('https://example.com/image.jpg');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should pass brandIconSrc to PreviewContent', () => {
|
|
241
|
+
render(
|
|
242
|
+
<TestWrapper>
|
|
243
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
244
|
+
</TestWrapper>
|
|
245
|
+
);
|
|
246
|
+
expect(screen.getByTestId('content-icon')).toHaveTextContent('https://example.com/icon.png');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should pass buttons to PreviewContent', () => {
|
|
250
|
+
render(
|
|
251
|
+
<TestWrapper>
|
|
252
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
253
|
+
</TestWrapper>
|
|
254
|
+
);
|
|
255
|
+
const buttons = JSON.parse(screen.getByTestId('content-buttons').textContent);
|
|
256
|
+
expect(buttons).toHaveLength(1);
|
|
257
|
+
expect(buttons[0]).toEqual({ text: 'Click', url: 'https://example.com', type: 'EXTERNAL_URL' });
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe('OS and browser change handlers', () => {
|
|
262
|
+
it('should update selected OS when handleOSChange is called', () => {
|
|
263
|
+
render(
|
|
264
|
+
<TestWrapper>
|
|
265
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
266
|
+
</TestWrapper>
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
fireEvent.click(screen.getByTestId('os-change-btn'));
|
|
270
|
+
expect(screen.getByTestId('selected-os')).toHaveTextContent('Windows');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should update selected browser when handleBrowserChange is called', () => {
|
|
274
|
+
render(
|
|
275
|
+
<TestWrapper>
|
|
276
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
277
|
+
</TestWrapper>
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
fireEvent.click(screen.getByTestId('browser-change-btn'));
|
|
281
|
+
expect(screen.getByTestId('selected-browser')).toHaveTextContent('Firefox');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should pass updated OS to PreviewContent after OS change', () => {
|
|
285
|
+
render(
|
|
286
|
+
<TestWrapper>
|
|
287
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
288
|
+
</TestWrapper>
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
fireEvent.click(screen.getByTestId('os-change-btn'));
|
|
292
|
+
expect(screen.getByTestId('content-os')).toHaveTextContent('Windows');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('Browser coercion on OS change', () => {
|
|
297
|
+
it('should keep Chrome when switching from macOS to Windows (Chrome is valid on both)', () => {
|
|
298
|
+
// Chrome is supported on all OS platforms, so switching macOS → Windows should NOT coerce.
|
|
299
|
+
render(
|
|
300
|
+
<TestWrapper>
|
|
301
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
302
|
+
</TestWrapper>
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
expect(screen.getByTestId('selected-browser')).toHaveTextContent('Chrome');
|
|
306
|
+
fireEvent.click(screen.getByTestId('os-change-btn')); // sets OS to Windows
|
|
307
|
+
// Chrome is still valid on Windows, so browser stays Chrome (no coercion)
|
|
308
|
+
expect(screen.getByTestId('selected-browser')).toHaveTextContent('Chrome');
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should update OS state when OS is changed', () => {
|
|
312
|
+
render(
|
|
313
|
+
<TestWrapper>
|
|
314
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
315
|
+
</TestWrapper>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
fireEvent.click(screen.getByTestId('os-change-btn')); // sets OS to Windows
|
|
319
|
+
expect(screen.getByTestId('selected-os')).toHaveTextContent('Windows');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should allow explicit browser change independent of OS', () => {
|
|
323
|
+
render(
|
|
324
|
+
<TestWrapper>
|
|
325
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
326
|
+
</TestWrapper>
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
fireEvent.click(screen.getByTestId('browser-change-btn')); // sets browser to Firefox
|
|
330
|
+
expect(screen.getByTestId('selected-browser')).toHaveTextContent('Firefox');
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
describe('Fullscreen modal', () => {
|
|
335
|
+
it('should NOT show modal when isFullscreenOpen is false', () => {
|
|
336
|
+
render(
|
|
337
|
+
<TestWrapper>
|
|
338
|
+
<WebPushPreviewContent {...defaultProps} isFullscreenOpen={false} />
|
|
339
|
+
</TestWrapper>
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const modal = screen.getByTestId('cap-modal');
|
|
343
|
+
expect(modal.getAttribute('data-visible')).toBe('false');
|
|
344
|
+
expect(screen.queryByTestId('modal-content')).toBeNull();
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('should show modal when isFullscreenOpen is true', () => {
|
|
348
|
+
render(
|
|
349
|
+
<TestWrapper>
|
|
350
|
+
<WebPushPreviewContent {...defaultProps} isFullscreenOpen={true} />
|
|
351
|
+
</TestWrapper>
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
const modal = screen.getByTestId('cap-modal');
|
|
355
|
+
expect(modal.getAttribute('data-visible')).toBe('true');
|
|
356
|
+
expect(screen.getByTestId('modal-content')).toBeTruthy();
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('should render DevicePreviewContent inside modal', () => {
|
|
360
|
+
render(
|
|
361
|
+
<TestWrapper>
|
|
362
|
+
<WebPushPreviewContent {...defaultProps} isFullscreenOpen={true} />
|
|
363
|
+
</TestWrapper>
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
expect(screen.getByTestId('device-preview-content')).toBeTruthy();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('should pass notificationTitle to DevicePreviewContent', () => {
|
|
370
|
+
render(
|
|
371
|
+
<TestWrapper>
|
|
372
|
+
<WebPushPreviewContent {...defaultProps} isFullscreenOpen={true} />
|
|
373
|
+
</TestWrapper>
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
expect(screen.getByTestId('device-title')).toHaveTextContent('Test Title');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('should pass notificationBody to DevicePreviewContent', () => {
|
|
380
|
+
render(
|
|
381
|
+
<TestWrapper>
|
|
382
|
+
<WebPushPreviewContent {...defaultProps} isFullscreenOpen={true} />
|
|
383
|
+
</TestWrapper>
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
expect(screen.getByTestId('device-body')).toHaveTextContent('Test body text');
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it('should call setIsFullscreenOpen(false) when close icon is clicked', () => {
|
|
390
|
+
const setIsFullscreenOpen = jest.fn();
|
|
391
|
+
render(
|
|
392
|
+
<TestWrapper>
|
|
393
|
+
<WebPushPreviewContent
|
|
394
|
+
{...defaultProps}
|
|
395
|
+
isFullscreenOpen={true}
|
|
396
|
+
setIsFullscreenOpen={setIsFullscreenOpen}
|
|
397
|
+
/>
|
|
398
|
+
</TestWrapper>
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
fireEvent.click(screen.getByTestId('cap-icon-collapse2'));
|
|
402
|
+
expect(setIsFullscreenOpen).toHaveBeenCalledWith(false);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it('should call setIsFullscreenOpen(false) when modal onCancel fires', () => {
|
|
406
|
+
const setIsFullscreenOpen = jest.fn();
|
|
407
|
+
render(
|
|
408
|
+
<TestWrapper>
|
|
409
|
+
<WebPushPreviewContent
|
|
410
|
+
{...defaultProps}
|
|
411
|
+
isFullscreenOpen={true}
|
|
412
|
+
setIsFullscreenOpen={setIsFullscreenOpen}
|
|
413
|
+
/>
|
|
414
|
+
</TestWrapper>
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
fireEvent.click(screen.getByTestId('modal-cancel'));
|
|
418
|
+
expect(setIsFullscreenOpen).toHaveBeenCalledWith(false);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('should display selectedCustomer name in modal header when customer is provided', () => {
|
|
422
|
+
render(
|
|
423
|
+
<TestWrapper>
|
|
424
|
+
<WebPushPreviewContent
|
|
425
|
+
{...defaultProps}
|
|
426
|
+
isFullscreenOpen={true}
|
|
427
|
+
selectedCustomer={{ name: 'Alice' }}
|
|
428
|
+
/>
|
|
429
|
+
</TestWrapper>
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
expect(screen.getByText('Alice')).toBeTruthy();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('should display default preview text in modal header when no customer', () => {
|
|
436
|
+
render(
|
|
437
|
+
<TestWrapper>
|
|
438
|
+
<WebPushPreviewContent
|
|
439
|
+
{...defaultProps}
|
|
440
|
+
isFullscreenOpen={true}
|
|
441
|
+
selectedCustomer={null}
|
|
442
|
+
/>
|
|
443
|
+
</TestWrapper>
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
// FormattedMessage renders defaultMessage for defaultPreview
|
|
447
|
+
expect(screen.queryByText('Alice')).toBeNull();
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
describe('Default props', () => {
|
|
452
|
+
it('should render with minimal props (title and body only)', () => {
|
|
453
|
+
render(
|
|
454
|
+
<TestWrapper>
|
|
455
|
+
<WebPushPreviewContent
|
|
456
|
+
notificationTitle="Min title"
|
|
457
|
+
notificationBody="Min body"
|
|
458
|
+
/>
|
|
459
|
+
</TestWrapper>
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
expect(screen.getByTestId('content-title')).toHaveTextContent('Min title');
|
|
463
|
+
expect(screen.getByTestId('content-body')).toHaveTextContent('Min body');
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it('should render with no props at all (all defaults)', () => {
|
|
467
|
+
render(
|
|
468
|
+
<TestWrapper>
|
|
469
|
+
<WebPushPreviewContent />
|
|
470
|
+
</TestWrapper>
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
expect(screen.getByTestId('preview-controls')).toBeTruthy();
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('should render empty buttons array by default', () => {
|
|
477
|
+
render(
|
|
478
|
+
<TestWrapper>
|
|
479
|
+
<WebPushPreviewContent notificationTitle="T" notificationBody="B" />
|
|
480
|
+
</TestWrapper>
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
const buttons = JSON.parse(screen.getByTestId('content-buttons').textContent);
|
|
484
|
+
expect(buttons).toEqual([]);
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
describe('PreviewControls props', () => {
|
|
489
|
+
it('should pass OS_OPTIONS to PreviewControls', () => {
|
|
490
|
+
render(
|
|
491
|
+
<TestWrapper>
|
|
492
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
493
|
+
</TestWrapper>
|
|
494
|
+
);
|
|
495
|
+
// PreviewControls is rendered
|
|
496
|
+
expect(screen.getByTestId('preview-controls')).toBeTruthy();
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should pass browserOptions derived from selectedOS to PreviewControls', () => {
|
|
500
|
+
render(
|
|
501
|
+
<TestWrapper>
|
|
502
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
503
|
+
</TestWrapper>
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
// macOS supports all browsers including Safari
|
|
507
|
+
const browserOptions = JSON.parse(screen.getByTestId('browser-options').textContent);
|
|
508
|
+
expect(Array.isArray(browserOptions)).toBe(true);
|
|
509
|
+
expect(browserOptions.length).toBeGreaterThan(0);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it('should pass layoutMode="newRow" to PreviewControls', () => {
|
|
513
|
+
// PreviewControls mock just renders - verifying no crash when layoutMode is set
|
|
514
|
+
render(
|
|
515
|
+
<TestWrapper>
|
|
516
|
+
<WebPushPreviewContent {...defaultProps} />
|
|
517
|
+
</TestWrapper>
|
|
518
|
+
);
|
|
519
|
+
expect(screen.getByTestId('preview-controls')).toBeTruthy();
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
});
|