@capillarytech/creatives-library 8.0.208 → 8.0.210
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/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/package.json +16 -2
- package/v2Components/HtmlEditor/HTMLEditor.js +508 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1809 -0
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +532 -0
- package/v2Components/HtmlEditor/_htmlEditor.scss +304 -0
- package/v2Components/HtmlEditor/_index.lazy.scss +26 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +376 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +331 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/__tests__/index.test.js +314 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +244 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +111 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/PreviewModeGroup.js +72 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/__tests__/PreviewModeGroup.test.js +1594 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +113 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/_previewModeGroup.scss +82 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +115 -0
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +57 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/ContentOverlay.js +90 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +60 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/LayoutSelector.js +58 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/ContentOverlay.test.js +403 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +424 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/LayoutSelector.test.js +248 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +253 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +104 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +179 -0
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +220 -0
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +229 -0
- package/v2Components/HtmlEditor/components/SplitContainer/SplitContainer.js +276 -0
- package/v2Components/HtmlEditor/components/SplitContainer/__tests__/SplitContainer.test.js +295 -0
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +257 -0
- package/v2Components/HtmlEditor/components/SplitContainer/index.js +7 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +31 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +70 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/__tests__/index.test.js +98 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +311 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +297 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/messages.js +57 -0
- package/v2Components/HtmlEditor/components/common/EditorContext.js +84 -0
- package/v2Components/HtmlEditor/components/common/__tests__/EditorContext.test.js +660 -0
- package/v2Components/HtmlEditor/constants.js +241 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useEditorContent.test.js +450 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +785 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useLayoutState.test.js +580 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.enhanced.test.js +768 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +590 -0
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +274 -0
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +407 -0
- package/v2Components/HtmlEditor/hooks/useLayoutState.js +247 -0
- package/v2Components/HtmlEditor/hooks/useValidation.js +325 -0
- package/v2Components/HtmlEditor/index.js +29 -0
- package/v2Components/HtmlEditor/index.lazy.js +114 -0
- package/v2Components/HtmlEditor/messages.js +389 -0
- package/v2Components/HtmlEditor/utils/__tests__/contentSanitizer.test.js +741 -0
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +1042 -0
- package/v2Components/HtmlEditor/utils/__tests__/liquidTemplateSupport.test.js +515 -0
- package/v2Components/HtmlEditor/utils/__tests__/properSyntaxHighlighting.test.js +473 -0
- package/v2Components/HtmlEditor/utils/__tests__/simplePerformance.test.js +1109 -0
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +240 -0
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +433 -0
- package/v2Components/HtmlEditor/utils/htmlValidator.js +508 -0
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +524 -0
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +163 -0
- package/v2Components/HtmlEditor/utils/simplePerformance.js +145 -0
- package/v2Components/HtmlEditor/utils/validationAdapter.js +130 -0
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +200 -0
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +545 -0
- package/v2Containers/EmailWrapper/index.js +8 -1
- package/v2Containers/Rcs/index.js +2 -0
- package/v2Containers/Templates/constants.js +8 -0
- package/v2Containers/Templates/index.js +56 -28
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +5 -14
- package/v2Containers/Whatsapp/index.js +1 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContentOverlay Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for InApp HTML content overlay component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { render, screen } from '@testing-library/react';
|
|
9
|
+
import '@testing-library/jest-dom';
|
|
10
|
+
import ContentOverlay from '../ContentOverlay';
|
|
11
|
+
import { LAYOUT_TYPES } from '../constants';
|
|
12
|
+
import { DEVICE_TYPES } from '../../../constants';
|
|
13
|
+
|
|
14
|
+
describe('ContentOverlay', () => {
|
|
15
|
+
describe('Rendering', () => {
|
|
16
|
+
it('renders without crashing', () => {
|
|
17
|
+
render(<ContentOverlay />);
|
|
18
|
+
const overlay = document.querySelector('.content-overlay');
|
|
19
|
+
expect(overlay).toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('renders with default props', () => {
|
|
23
|
+
render(<ContentOverlay />);
|
|
24
|
+
const overlay = document.querySelector('.content-overlay');
|
|
25
|
+
expect(overlay).toBeInTheDocument();
|
|
26
|
+
expect(overlay).toHaveClass('content-overlay--popup');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renders screen area container', () => {
|
|
30
|
+
render(<ContentOverlay />);
|
|
31
|
+
const screenArea = document.querySelector('.content-overlay__screen-area');
|
|
32
|
+
expect(screenArea).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('applies custom className', () => {
|
|
36
|
+
render(<ContentOverlay className="custom-class" />);
|
|
37
|
+
const overlay = document.querySelector('.content-overlay');
|
|
38
|
+
expect(overlay).toHaveClass('custom-class');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('Layout Types', () => {
|
|
43
|
+
it('renders with MODAL layout type', () => {
|
|
44
|
+
render(<ContentOverlay layoutType={LAYOUT_TYPES.MODAL} />);
|
|
45
|
+
const overlay = document.querySelector('.content-overlay');
|
|
46
|
+
expect(overlay).toHaveClass('content-overlay--popup');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('renders with HEADER layout type', () => {
|
|
50
|
+
render(<ContentOverlay layoutType={LAYOUT_TYPES.HEADER} />);
|
|
51
|
+
const overlay = document.querySelector('.content-overlay');
|
|
52
|
+
expect(overlay).toHaveClass('content-overlay--header');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('renders with FOOTER layout type', () => {
|
|
56
|
+
render(<ContentOverlay layoutType={LAYOUT_TYPES.FOOTER} />);
|
|
57
|
+
const overlay = document.querySelector('.content-overlay');
|
|
58
|
+
expect(overlay).toHaveClass('content-overlay--footer');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('renders with FULLSCREEN layout type', () => {
|
|
62
|
+
render(<ContentOverlay layoutType={LAYOUT_TYPES.FULLSCREEN} />);
|
|
63
|
+
const overlay = document.querySelector('.content-overlay');
|
|
64
|
+
expect(overlay).toHaveClass('content-overlay--fullscreen');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('Device Types', () => {
|
|
69
|
+
it('renders with ANDROID device', () => {
|
|
70
|
+
render(<ContentOverlay device={DEVICE_TYPES.ANDROID} />);
|
|
71
|
+
const screenArea = document.querySelector('.content-overlay__screen-area');
|
|
72
|
+
expect(screenArea).toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('renders with IOS device', () => {
|
|
76
|
+
render(<ContentOverlay device={DEVICE_TYPES.IOS} />);
|
|
77
|
+
const screenArea = document.querySelector('.content-overlay__screen-area');
|
|
78
|
+
expect(screenArea).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('defaults to ANDROID device when invalid device provided', () => {
|
|
82
|
+
render(<ContentOverlay device="INVALID" />);
|
|
83
|
+
const screenArea = document.querySelector('.content-overlay__screen-area');
|
|
84
|
+
expect(screenArea).toBeInTheDocument();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('Empty State', () => {
|
|
89
|
+
it('shows empty state when no content provided', () => {
|
|
90
|
+
render(<ContentOverlay />);
|
|
91
|
+
expect(screen.getByText('HTML content will appear here')).toBeInTheDocument();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('shows empty state when content is empty string', () => {
|
|
95
|
+
render(<ContentOverlay content="" />);
|
|
96
|
+
expect(screen.getByText('HTML content will appear here')).toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('shows empty state when content is whitespace only', () => {
|
|
100
|
+
render(<ContentOverlay content=" " />);
|
|
101
|
+
expect(screen.getByText('HTML content will appear here')).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('displays layout type in empty state', () => {
|
|
105
|
+
render(<ContentOverlay layoutType={LAYOUT_TYPES.MODAL} />);
|
|
106
|
+
expect(screen.getByText('POPUP')).toBeInTheDocument();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('shows icon in empty state', () => {
|
|
110
|
+
render(<ContentOverlay />);
|
|
111
|
+
expect(screen.getByText('📱')).toBeInTheDocument();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('Content Rendering', () => {
|
|
116
|
+
it('renders iframe when content is provided', () => {
|
|
117
|
+
render(<ContentOverlay content="<p>Test content</p>" />);
|
|
118
|
+
const iframe = document.querySelector('iframe');
|
|
119
|
+
expect(iframe).toBeInTheDocument();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('sets iframe srcDoc with HTML content', () => {
|
|
123
|
+
const htmlContent = '<p>Hello World</p>';
|
|
124
|
+
render(<ContentOverlay content={htmlContent} />);
|
|
125
|
+
const iframe = document.querySelector('iframe');
|
|
126
|
+
expect(iframe).toHaveAttribute('srcDoc', htmlContent);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('sets iframe title', () => {
|
|
130
|
+
render(<ContentOverlay content="<p>Test</p>" />);
|
|
131
|
+
const iframe = document.querySelector('iframe');
|
|
132
|
+
expect(iframe).toHaveAttribute('title', 'InApp HTML Preview');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('sets iframe sandbox attribute', () => {
|
|
136
|
+
render(<ContentOverlay content="<p>Test</p>" />);
|
|
137
|
+
const iframe = document.querySelector('iframe');
|
|
138
|
+
expect(iframe).toHaveAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('hides empty state when content is provided', () => {
|
|
142
|
+
render(<ContentOverlay content="<p>Test</p>" />);
|
|
143
|
+
expect(screen.queryByText('HTML content will appear here')).not.toBeInTheDocument();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('Styling', () => {
|
|
148
|
+
it('applies screen area positioning styles', () => {
|
|
149
|
+
render(<ContentOverlay />);
|
|
150
|
+
const screenArea = document.querySelector('.content-overlay__screen-area');
|
|
151
|
+
const styles = window.getComputedStyle(screenArea);
|
|
152
|
+
expect(styles.position).toBe('absolute');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('applies overlay positioning styles', () => {
|
|
156
|
+
render(<ContentOverlay />);
|
|
157
|
+
const overlay = document.querySelector('.content-overlay');
|
|
158
|
+
// Check that the overlay element exists and has the correct CSS class
|
|
159
|
+
expect(overlay).toBeInTheDocument();
|
|
160
|
+
expect(overlay).toHaveClass('content-overlay');
|
|
161
|
+
expect(overlay).toHaveClass('content-overlay--popup'); // default layout type is MODAL which maps to 'popup' class
|
|
162
|
+
|
|
163
|
+
// Check that inline styles from getOverlayStyles() are applied
|
|
164
|
+
const inlineStyles = overlay.style;
|
|
165
|
+
expect(inlineStyles.top).toBe('50%');
|
|
166
|
+
expect(inlineStyles.left).toBe('50%');
|
|
167
|
+
expect(inlineStyles.transform).toBe('translate(-50%, -50%)');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('does not apply inline iframe styles (SCSS-managed)', () => {
|
|
171
|
+
render(<ContentOverlay content="<p>Test</p>" />);
|
|
172
|
+
const iframe = document.querySelector('iframe');
|
|
173
|
+
|
|
174
|
+
// Verify iframe styling is managed by SCSS, not inline styles
|
|
175
|
+
// The iframe should have no inline style attribute since all styling
|
|
176
|
+
// (width: 100%, height: 100%, border: none, display: block, backgroundColor)
|
|
177
|
+
// is handled via the .content-overlay iframe CSS rule in _inAppPreviewPane.scss
|
|
178
|
+
expect(iframe.style.cssText).toBe('');
|
|
179
|
+
expect(iframe.hasAttribute('style')).toBe(false);
|
|
180
|
+
|
|
181
|
+
// Ensure no inline style properties are set
|
|
182
|
+
expect(iframe.style.width).toBe('');
|
|
183
|
+
expect(iframe.style.height).toBe('');
|
|
184
|
+
expect(iframe.style.border).toBe('');
|
|
185
|
+
expect(iframe.style.display).toBe('');
|
|
186
|
+
expect(iframe.style.backgroundColor).toBe('');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('Props Forwarding', () => {
|
|
191
|
+
it('forwards additional props to overlay container', () => {
|
|
192
|
+
render(<ContentOverlay data-testid="custom-overlay" />);
|
|
193
|
+
const overlay = screen.getByTestId('custom-overlay');
|
|
194
|
+
expect(overlay).toBeInTheDocument();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('forwards aria attributes', () => {
|
|
198
|
+
render(<ContentOverlay aria-label="Preview overlay" />);
|
|
199
|
+
const overlay = document.querySelector('.content-overlay');
|
|
200
|
+
expect(overlay).toHaveAttribute('aria-label', 'Preview overlay');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('forwards data attributes', () => {
|
|
204
|
+
render(<ContentOverlay data-preview="true" />);
|
|
205
|
+
const overlay = document.querySelector('.content-overlay');
|
|
206
|
+
expect(overlay).toHaveAttribute('data-preview', 'true');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('Content Variations', () => {
|
|
211
|
+
it('renders simple HTML content', () => {
|
|
212
|
+
render(<ContentOverlay content="<p>Simple text</p>" />);
|
|
213
|
+
const iframe = document.querySelector('iframe');
|
|
214
|
+
expect(iframe).toHaveAttribute('srcDoc', '<p>Simple text</p>');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('renders complex HTML content', () => {
|
|
218
|
+
const complexHtml = `
|
|
219
|
+
<div>
|
|
220
|
+
<h1>Title</h1>
|
|
221
|
+
<p>Paragraph</p>
|
|
222
|
+
<button>Click me</button>
|
|
223
|
+
</div>
|
|
224
|
+
`;
|
|
225
|
+
render(<ContentOverlay content={complexHtml} />);
|
|
226
|
+
const iframe = document.querySelector('iframe');
|
|
227
|
+
expect(iframe).toHaveAttribute('srcDoc', complexHtml);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('renders HTML with inline styles', () => {
|
|
231
|
+
const styledHtml = '<div style="color: red;">Styled content</div>';
|
|
232
|
+
render(<ContentOverlay content={styledHtml} />);
|
|
233
|
+
const iframe = document.querySelector('iframe');
|
|
234
|
+
expect(iframe).toHaveAttribute('srcDoc', styledHtml);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('renders HTML with CSS', () => {
|
|
238
|
+
const htmlWithCss = '<style>p { color: blue; }</style><p>Blue text</p>';
|
|
239
|
+
render(<ContentOverlay content={htmlWithCss} />);
|
|
240
|
+
const iframe = document.querySelector('iframe');
|
|
241
|
+
expect(iframe).toHaveAttribute('srcDoc', htmlWithCss);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('Layout Type Combinations', () => {
|
|
246
|
+
it('renders modal layout with Android device', () => {
|
|
247
|
+
render(
|
|
248
|
+
<ContentOverlay
|
|
249
|
+
layoutType={LAYOUT_TYPES.MODAL}
|
|
250
|
+
device={DEVICE_TYPES.ANDROID}
|
|
251
|
+
content="<p>Modal Android</p>"
|
|
252
|
+
/>
|
|
253
|
+
);
|
|
254
|
+
const overlay = document.querySelector('.content-overlay--popup');
|
|
255
|
+
expect(overlay).toBeInTheDocument();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('renders header layout with iOS device', () => {
|
|
259
|
+
render(
|
|
260
|
+
<ContentOverlay
|
|
261
|
+
layoutType={LAYOUT_TYPES.HEADER}
|
|
262
|
+
device={DEVICE_TYPES.IOS}
|
|
263
|
+
content="<p>Header iOS</p>"
|
|
264
|
+
/>
|
|
265
|
+
);
|
|
266
|
+
const overlay = document.querySelector('.content-overlay--header');
|
|
267
|
+
expect(overlay).toBeInTheDocument();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('renders footer layout with content', () => {
|
|
271
|
+
render(
|
|
272
|
+
<ContentOverlay
|
|
273
|
+
layoutType={LAYOUT_TYPES.FOOTER}
|
|
274
|
+
content="<p>Footer content</p>"
|
|
275
|
+
/>
|
|
276
|
+
);
|
|
277
|
+
const overlay = document.querySelector('.content-overlay--footer');
|
|
278
|
+
const iframe = document.querySelector('iframe');
|
|
279
|
+
expect(overlay).toBeInTheDocument();
|
|
280
|
+
expect(iframe).toBeInTheDocument();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('renders fullscreen layout with content', () => {
|
|
284
|
+
render(
|
|
285
|
+
<ContentOverlay
|
|
286
|
+
layoutType={LAYOUT_TYPES.FULLSCREEN}
|
|
287
|
+
content="<p>Fullscreen content</p>"
|
|
288
|
+
/>
|
|
289
|
+
);
|
|
290
|
+
const overlay = document.querySelector('.content-overlay--fullscreen');
|
|
291
|
+
const iframe = document.querySelector('iframe');
|
|
292
|
+
expect(overlay).toBeInTheDocument();
|
|
293
|
+
expect(iframe).toBeInTheDocument();
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
describe('Edge Cases', () => {
|
|
298
|
+
it('handles null content', () => {
|
|
299
|
+
render(<ContentOverlay content={null} />);
|
|
300
|
+
expect(screen.getByText('HTML content will appear here')).toBeInTheDocument();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('handles undefined content', () => {
|
|
304
|
+
render(<ContentOverlay content={undefined} />);
|
|
305
|
+
expect(screen.getByText('HTML content will appear here')).toBeInTheDocument();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('handles very long content', () => {
|
|
309
|
+
const longContent = '<p>' + 'a'.repeat(10000) + '</p>';
|
|
310
|
+
render(<ContentOverlay content={longContent} />);
|
|
311
|
+
const iframe = document.querySelector('iframe');
|
|
312
|
+
expect(iframe).toBeInTheDocument();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('handles content with special characters', () => {
|
|
316
|
+
const specialContent = '<p>Special: & < > " \'</p>';
|
|
317
|
+
render(<ContentOverlay content={specialContent} />);
|
|
318
|
+
const iframe = document.querySelector('iframe');
|
|
319
|
+
expect(iframe).toHaveAttribute('srcDoc', specialContent);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('handles content with unicode characters', () => {
|
|
323
|
+
const unicodeContent = '<p>Unicode: 你好 مرحبا 🎉</p>';
|
|
324
|
+
render(<ContentOverlay content={unicodeContent} />);
|
|
325
|
+
const iframe = document.querySelector('iframe');
|
|
326
|
+
expect(iframe).toHaveAttribute('srcDoc', unicodeContent);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
describe('Accessibility', () => {
|
|
331
|
+
it('provides iframe title for screen readers', () => {
|
|
332
|
+
render(<ContentOverlay content="<p>Test</p>" />);
|
|
333
|
+
const iframe = document.querySelector('iframe');
|
|
334
|
+
expect(iframe).toHaveAttribute('title');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('empty state is readable', () => {
|
|
338
|
+
render(<ContentOverlay />);
|
|
339
|
+
const text = screen.getByText('HTML content will appear here');
|
|
340
|
+
expect(text).toBeVisible();
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe('Component Structure', () => {
|
|
345
|
+
it('maintains correct DOM hierarchy', () => {
|
|
346
|
+
render(<ContentOverlay content="<p>Test</p>" />);
|
|
347
|
+
const screenArea = document.querySelector('.content-overlay__screen-area');
|
|
348
|
+
const overlay = document.querySelector('.content-overlay');
|
|
349
|
+
const iframe = document.querySelector('iframe');
|
|
350
|
+
|
|
351
|
+
expect(screenArea).toBeInTheDocument();
|
|
352
|
+
expect(overlay).toBeInTheDocument();
|
|
353
|
+
expect(iframe).toBeInTheDocument();
|
|
354
|
+
expect(overlay.parentElement).toBe(screenArea);
|
|
355
|
+
expect(iframe.parentElement).toBe(overlay);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('applies correct CSS classes', () => {
|
|
359
|
+
render(<ContentOverlay layoutType={LAYOUT_TYPES.MODAL} className="custom" />);
|
|
360
|
+
const overlay = document.querySelector('.content-overlay');
|
|
361
|
+
|
|
362
|
+
expect(overlay).toHaveClass('content-overlay');
|
|
363
|
+
expect(overlay).toHaveClass('content-overlay--popup');
|
|
364
|
+
expect(overlay).toHaveClass('custom');
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('PropTypes Validation', () => {
|
|
369
|
+
// These tests verify the component accepts the expected prop types
|
|
370
|
+
it('accepts valid layoutType values', () => {
|
|
371
|
+
const { rerender } = render(<ContentOverlay layoutType={LAYOUT_TYPES.MODAL} />);
|
|
372
|
+
expect(document.querySelector('.content-overlay')).toBeInTheDocument();
|
|
373
|
+
|
|
374
|
+
rerender(<ContentOverlay layoutType={LAYOUT_TYPES.HEADER} />);
|
|
375
|
+
expect(document.querySelector('.content-overlay')).toBeInTheDocument();
|
|
376
|
+
|
|
377
|
+
rerender(<ContentOverlay layoutType={LAYOUT_TYPES.FOOTER} />);
|
|
378
|
+
expect(document.querySelector('.content-overlay')).toBeInTheDocument();
|
|
379
|
+
|
|
380
|
+
rerender(<ContentOverlay layoutType={LAYOUT_TYPES.FULLSCREEN} />);
|
|
381
|
+
expect(document.querySelector('.content-overlay')).toBeInTheDocument();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('accepts valid device values', () => {
|
|
385
|
+
const { rerender } = render(<ContentOverlay device={DEVICE_TYPES.ANDROID} />);
|
|
386
|
+
expect(document.querySelector('.content-overlay')).toBeInTheDocument();
|
|
387
|
+
|
|
388
|
+
rerender(<ContentOverlay device={DEVICE_TYPES.IOS} />);
|
|
389
|
+
expect(document.querySelector('.content-overlay')).toBeInTheDocument();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('accepts string content', () => {
|
|
393
|
+
render(<ContentOverlay content="String content" />);
|
|
394
|
+
expect(document.querySelector('iframe')).toBeInTheDocument();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('accepts string className', () => {
|
|
398
|
+
render(<ContentOverlay className="test-class" />);
|
|
399
|
+
expect(document.querySelector('.test-class')).toBeInTheDocument();
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
|