@mkhuda/dom-screenshot 0.0.1 → 1.0.1

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 (51) hide show
  1. package/.gitattributes +1 -0
  2. package/EXAMPLES_QUICKSTART.md +240 -0
  3. package/README.md +542 -25
  4. package/TESTING.md +269 -0
  5. package/TESTING_STATUS.md +215 -0
  6. package/TEST_SETUP_SUMMARY.md +335 -0
  7. package/dist/dom-screenshot.d.ts +44 -272
  8. package/dist/dom-screenshot.d.ts.map +1 -0
  9. package/dist/dom-screenshot.esm.js +753 -0
  10. package/dist/dom-screenshot.esm.js.map +1 -0
  11. package/dist/dom-screenshot.min.js +2 -1
  12. package/dist/dom-screenshot.min.js.map +1 -0
  13. package/examples/README.md +211 -0
  14. package/examples/react-app/README.md +161 -0
  15. package/examples/react-app/index.html +12 -0
  16. package/examples/react-app/node_modules/.vite/deps/_metadata.json +46 -0
  17. package/examples/react-app/node_modules/.vite/deps/chunk-FK77NBP6.js +1895 -0
  18. package/examples/react-app/node_modules/.vite/deps/chunk-FK77NBP6.js.map +7 -0
  19. package/examples/react-app/node_modules/.vite/deps/chunk-VSODSHUF.js +21647 -0
  20. package/examples/react-app/node_modules/.vite/deps/chunk-VSODSHUF.js.map +7 -0
  21. package/examples/react-app/node_modules/.vite/deps/package.json +3 -0
  22. package/examples/react-app/node_modules/.vite/deps/react-dom.js +5 -0
  23. package/examples/react-app/node_modules/.vite/deps/react-dom.js.map +7 -0
  24. package/examples/react-app/node_modules/.vite/deps/react-dom_client.js +38 -0
  25. package/examples/react-app/node_modules/.vite/deps/react-dom_client.js.map +7 -0
  26. package/examples/react-app/node_modules/.vite/deps/react.js +4 -0
  27. package/examples/react-app/node_modules/.vite/deps/react.js.map +7 -0
  28. package/examples/react-app/node_modules/.vite/deps/react_jsx-dev-runtime.js +898 -0
  29. package/examples/react-app/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
  30. package/examples/react-app/node_modules/.vite/deps/react_jsx-runtime.js +910 -0
  31. package/examples/react-app/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
  32. package/examples/react-app/package.json +21 -0
  33. package/examples/react-app/tsconfig.json +25 -0
  34. package/examples/react-app/tsconfig.node.json +10 -0
  35. package/examples/react-app/vite.config.ts +10 -0
  36. package/package.json +75 -44
  37. package/rollup.config.mjs +35 -0
  38. package/tests/README.md +394 -0
  39. package/tests/fixtures/html.ts +192 -0
  40. package/tests/fixtures/images.ts +86 -0
  41. package/tests/fixtures/styles.ts +288 -0
  42. package/tests/helpers/dom-helpers.ts +242 -0
  43. package/tests/mocks/canvas-mock.ts +94 -0
  44. package/tests/mocks/image-mock.ts +147 -0
  45. package/tests/mocks/xhr-mock.ts +202 -0
  46. package/tests/setup.ts +103 -0
  47. package/tests/unit/basic.test.ts +263 -0
  48. package/tests/unit/simple.test.ts +172 -0
  49. package/tsconfig.json +44 -20
  50. package/vitest.config.mts +35 -0
  51. package/rollup.config.js +0 -20
@@ -0,0 +1,394 @@
1
+ # DOM Screenshot Testing Guide
2
+
3
+ Complete testing setup for the dom-screenshot library using Vitest.
4
+
5
+ ## 📋 Directory Structure
6
+
7
+ ```
8
+ tests/
9
+ ├── setup.ts # Global test setup and configuration
10
+ ├── README.md # This file
11
+ ├── unit/ # Unit tests
12
+ │ └── basic.test.ts # Basic functionality tests
13
+ ├── integration/ # Integration tests (coming soon)
14
+ ├── helpers/ # Test helper utilities
15
+ │ └── dom-helpers.ts # DOM manipulation helpers
16
+ ├── mocks/ # Mock implementations
17
+ │ ├── canvas-mock.ts # Canvas API mocks
18
+ │ ├── image-mock.ts # Image loading mocks
19
+ │ └── xhr-mock.ts # XMLHttpRequest mocks
20
+ └── fixtures/ # Test data and fixtures
21
+ ├── html.ts # HTML test fixtures
22
+ ├── images.ts # Image data URLs
23
+ └── styles.ts # CSS and style fixtures
24
+ ```
25
+
26
+ ## 🚀 Quick Start
27
+
28
+ ### Install Dependencies
29
+
30
+ ```bash
31
+ npm install
32
+ ```
33
+
34
+ ### Run Tests
35
+
36
+ ```bash
37
+ # Run all tests
38
+ npm test
39
+
40
+ # Run tests once (CI mode)
41
+ npm run test:run
42
+
43
+ # Run tests in watch mode
44
+ npm run test:watch
45
+
46
+ # Run tests with UI
47
+ npm run test:ui
48
+
49
+ # Generate coverage report
50
+ npm run test:coverage
51
+ ```
52
+
53
+ ## 📝 Writing Tests
54
+
55
+ ### Basic Test Template
56
+
57
+ ```typescript
58
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
59
+ import { domtoimage } from '../../src/dom-screenshot';
60
+ import { createSimpleDiv } from '../helpers/dom-helpers';
61
+
62
+ describe('My Test Suite', () => {
63
+ let container: HTMLElement;
64
+
65
+ beforeEach(() => {
66
+ container = document.createElement('div');
67
+ document.body.appendChild(container);
68
+ });
69
+
70
+ afterEach(() => {
71
+ if (container?.parentNode) {
72
+ container.parentNode.removeChild(container);
73
+ }
74
+ });
75
+
76
+ it('should do something', async () => {
77
+ const div = createSimpleDiv('Test');
78
+ const result = await domtoimage.toSvg(div);
79
+
80
+ expect(result).toBeValidSvgDataUrl();
81
+ });
82
+ });
83
+ ```
84
+
85
+ ## 🛠️ Test Helpers
86
+
87
+ ### DOM Helpers (`helpers/dom-helpers.ts`)
88
+
89
+ Create test DOM elements easily:
90
+
91
+ ```typescript
92
+ import {
93
+ createSimpleDiv,
94
+ createStyledDiv,
95
+ createColoredDiv,
96
+ createImageElement,
97
+ createCanvasElement,
98
+ createComplexDOM,
99
+ createDOMWithStyles,
100
+ createSVGElement,
101
+ wait
102
+ } from '../helpers/dom-helpers';
103
+
104
+ // Create a simple div
105
+ const div = createSimpleDiv('Hello');
106
+
107
+ // Create styled div
108
+ const styled = createStyledDiv('Content', { color: 'red' });
109
+
110
+ // Create colored div
111
+ const colored = createColoredDiv('Text', 'white', 'blue');
112
+
113
+ // Create complex DOM tree
114
+ const complex = createComplexDOM();
115
+ ```
116
+
117
+ ## 🎭 Mock Utilities
118
+
119
+ ### Canvas Mocks (`mocks/canvas-mock.ts`)
120
+
121
+ Mock Canvas API operations:
122
+
123
+ ```typescript
124
+ import {
125
+ mockCanvasToDataUrl,
126
+ mockCanvasToBlob,
127
+ mockCanvasContext,
128
+ createValidPngDataUrl,
129
+ createValidSvgDataUrl
130
+ } from '../mocks/canvas-mock';
131
+
132
+ // Mock canvas.toDataURL()
133
+ mockCanvasToDataUrl(createValidPngDataUrl());
134
+
135
+ // Mock canvas.toBlob()
136
+ mockCanvasToBlob(new Blob(['data']));
137
+
138
+ // Mock canvas context
139
+ const { fillRect, drawImage } = mockCanvasContext();
140
+ ```
141
+
142
+ ### Image Mocks (`mocks/image-mock.ts`)
143
+
144
+ Mock image loading:
145
+
146
+ ```typescript
147
+ import {
148
+ mockImageSuccess,
149
+ mockImageError,
150
+ createImageDataUrl,
151
+ mockFileReaderDataUrl
152
+ } from '../mocks/image-mock';
153
+
154
+ // Mock successful image load
155
+ mockImageSuccess(10); // 10ms delay
156
+
157
+ // Mock image load error
158
+ mockImageError(10);
159
+
160
+ // Create image data URL
161
+ const dataUrl = createImageDataUrl('png'); // or 'jpeg', 'gif'
162
+ ```
163
+
164
+ ### XHR Mocks (`mocks/xhr-mock.ts`)
165
+
166
+ Mock XMLHttpRequest:
167
+
168
+ ```typescript
169
+ import {
170
+ mockXhrSuccess,
171
+ mockXhrError,
172
+ mockXhrTimeout,
173
+ stubUrlPattern,
174
+ createBase64ImageData
175
+ } from '../mocks/xhr-mock';
176
+
177
+ // Mock successful XHR
178
+ mockXhrSuccess('response-data', 10);
179
+
180
+ // Mock XHR error
181
+ mockXhrError(404, 10);
182
+
183
+ // Mock XHR timeout
184
+ mockXhrTimeout(100);
185
+
186
+ // Stub specific URLs
187
+ stubUrlPattern(
188
+ /example\.com\/image/,
189
+ 'image-data',
190
+ 200
191
+ );
192
+ ```
193
+
194
+ ## 📦 Test Fixtures
195
+
196
+ ### HTML Fixtures (`fixtures/html.ts`)
197
+
198
+ Pre-defined HTML strings for testing:
199
+
200
+ ```typescript
201
+ import {
202
+ SIMPLE_HTML,
203
+ STYLED_HTML,
204
+ COMPLEX_HTML,
205
+ NESTED_HTML,
206
+ TEXT_HTML,
207
+ FORM_HTML,
208
+ COLOR_HTML,
209
+ BORDER_SHADOW_HTML,
210
+ MULTI_IMAGE_HTML,
211
+ TABLE_HTML,
212
+ SVG_HTML,
213
+ generateLargeHTML
214
+ } from '../fixtures/html';
215
+
216
+ // Use in tests
217
+ container.innerHTML = SIMPLE_HTML;
218
+
219
+ // Generate dynamic HTML
220
+ const large = generateLargeHTML(100); // 100 items
221
+ ```
222
+
223
+ ### Image Fixtures (`fixtures/images.ts`)
224
+
225
+ Pre-encoded image data URLs:
226
+
227
+ ```typescript
228
+ import {
229
+ PNG_1X1_TRANSPARENT,
230
+ JPEG_1X1_RED,
231
+ GIF_1X1_BLUE,
232
+ SVG_CIRCLE,
233
+ TEST_IMAGES,
234
+ createTestImageElement,
235
+ createTestImageElements
236
+ } from '../fixtures/images';
237
+
238
+ // Use image data
239
+ const img = new Image();
240
+ img.src = PNG_1X1_TRANSPARENT;
241
+
242
+ // Create test image elements
243
+ const images = createTestImageElements(3);
244
+ ```
245
+
246
+ ### Style Fixtures (`fixtures/styles.ts`)
247
+
248
+ Pre-defined CSS styles for testing:
249
+
250
+ ```typescript
251
+ import {
252
+ CSS_FIXTURES,
253
+ createStyleElement,
254
+ createPseudoElementCSS,
255
+ createDivWithPseudoElements
256
+ } from '../fixtures/styles';
257
+
258
+ // Use CSS fixtures
259
+ container.innerHTML = CSS_FIXTURES.gradientDiv;
260
+
261
+ // Create pseudo-elements
262
+ const div = createDivWithPseudoElements();
263
+ ```
264
+
265
+ ## 🧪 Custom Matchers
266
+
267
+ Custom expect matchers are available:
268
+
269
+ ```typescript
270
+ // Check for valid data URL
271
+ expect(result).toBeValidDataUrl();
272
+
273
+ // Check for valid SVG data URL
274
+ expect(result).toBeValidSvgDataUrl();
275
+
276
+ // Check for valid PNG data URL
277
+ expect(result).toBeValidPngDataUrl();
278
+ ```
279
+
280
+ ## 📊 Test Coverage
281
+
282
+ Generate coverage reports:
283
+
284
+ ```bash
285
+ npm run test:coverage
286
+ ```
287
+
288
+ Coverage reports are generated in:
289
+ - `coverage/index.html` - HTML report
290
+ - `coverage/lcov.info` - LCOV format (for CI/CD)
291
+ - Console output - Summary
292
+
293
+ ## 🔍 Debugging Tests
294
+
295
+ ### Enable Debug Logging
296
+
297
+ ```typescript
298
+ import { describe, it, expect, beforeEach } from 'vitest';
299
+
300
+ describe('Debug Example', () => {
301
+ it('should log debug info', () => {
302
+ console.log('Debugging info here');
303
+ expect(true).toBe(true);
304
+ });
305
+ });
306
+ ```
307
+
308
+ ### Run Single Test File
309
+
310
+ ```bash
311
+ npx vitest tests/unit/basic.test.ts
312
+ ```
313
+
314
+ ### Run Single Test Suite
315
+
316
+ ```bash
317
+ npx vitest -t "My Test Suite"
318
+ ```
319
+
320
+ ### Use Vitest UI
321
+
322
+ ```bash
323
+ npm run test:ui
324
+ ```
325
+
326
+ Opens an interactive UI at http://localhost:51204/__vitest__/
327
+
328
+ ## 🔄 Continuous Integration
329
+
330
+ ### GitHub Actions Example
331
+
332
+ ```yaml
333
+ name: Tests
334
+
335
+ on: [push, pull_request]
336
+
337
+ jobs:
338
+ test:
339
+ runs-on: ubuntu-latest
340
+ steps:
341
+ - uses: actions/checkout@v3
342
+ - uses: actions/setup-node@v3
343
+ with:
344
+ node-version: '18'
345
+ - run: npm install
346
+ - run: npm run test:run
347
+ - run: npm run test:coverage
348
+ ```
349
+
350
+ ## 📚 Testing Best Practices
351
+
352
+ 1. **Isolation**: Each test should be independent
353
+ 2. **Cleanup**: Always clean up DOM in `afterEach`
354
+ 3. **Mocking**: Mock external dependencies (Canvas, Image, XHR)
355
+ 4. **Fixtures**: Use fixtures for consistent test data
356
+ 5. **Naming**: Use descriptive test names
357
+ 6. **Assertions**: Use specific assertions, not generic `toBeTruthy()`
358
+ 7. **Async**: Always `await` promises and handle async operations
359
+ 8. **Performance**: Keep tests fast (< 100ms each if possible)
360
+
361
+ ## 🐛 Common Issues
362
+
363
+ ### Canvas Not Available
364
+ Canvas is mocked in jsdom. Use `mockCanvasToDataUrl()` for PNG/JPEG tests.
365
+
366
+ ### Image Loading Fails
367
+ Use `mockImageSuccess()` or `mockImageError()` to control image behavior.
368
+
369
+ ### XHR Requests Fail
370
+ Use `mockXhrSuccess()`, `mockXhrError()`, or `stubUrlPattern()` to mock network requests.
371
+
372
+ ### Tests Timeout
373
+ Increase timeout or mock async operations that have delays.
374
+
375
+ ## 📖 Resources
376
+
377
+ - [Vitest Documentation](https://vitest.dev/)
378
+ - [Chai Assertion Library](https://www.chaijs.com/)
379
+ - [jsdom Documentation](https://github.com/jsdom/jsdom)
380
+ - [Sinon.js Mocking](https://sinonjs.org/)
381
+
382
+ ## 🤝 Contributing
383
+
384
+ When adding new features:
385
+
386
+ 1. Write tests first (TDD)
387
+ 2. Ensure all tests pass: `npm run test:run`
388
+ 3. Check coverage: `npm run test:coverage`
389
+ 4. Update this documentation
390
+ 5. Submit PR with tests
391
+
392
+ ---
393
+
394
+ Happy testing! 🎉
@@ -0,0 +1,192 @@
1
+ /**
2
+ * HTML test fixtures
3
+ */
4
+
5
+ /**
6
+ * Simple HTML fixture
7
+ */
8
+ export const SIMPLE_HTML = `
9
+ <div style="width: 100px; height: 100px; background-color: blue;">
10
+ <p>Hello World</p>
11
+ </div>
12
+ `;
13
+
14
+ /**
15
+ * HTML with styled elements
16
+ */
17
+ export const STYLED_HTML = `
18
+ <div style="
19
+ width: 200px;
20
+ height: 200px;
21
+ background: linear-gradient(to right, #ff0000, #00ff00);
22
+ border-radius: 10px;
23
+ padding: 20px;
24
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
25
+ ">
26
+ <h1 style="color: white; font-size: 24px; margin: 0;">Styled Content</h1>
27
+ <p style="color: #f0f0f0; font-size: 14px;">This is a paragraph with custom styling.</p>
28
+ </div>
29
+ `;
30
+
31
+ /**
32
+ * HTML with various elements
33
+ */
34
+ export const COMPLEX_HTML = `
35
+ <div style="width: 300px; background-color: #f5f5f5; padding: 20px;">
36
+ <h1>Title</h1>
37
+ <p>Paragraph text</p>
38
+ <ul>
39
+ <li>Item 1</li>
40
+ <li>Item 2</li>
41
+ <li>Item 3</li>
42
+ </ul>
43
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="test" style="width: 50px; height: 50px;" />
44
+ </div>
45
+ `;
46
+
47
+ /**
48
+ * HTML with nested divs
49
+ */
50
+ export const NESTED_HTML = `
51
+ <div style="background-color: #ddd; padding: 10px;">
52
+ <div style="background-color: #ccc; padding: 10px;">
53
+ <div style="background-color: #bbb; padding: 10px;">
54
+ <p>Nested content</p>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ `;
59
+
60
+ /**
61
+ * HTML with text and spans
62
+ */
63
+ export const TEXT_HTML = `
64
+ <div style="font-family: Arial, sans-serif; font-size: 16px; line-height: 1.5;">
65
+ <p>This is <strong>bold</strong> text.</p>
66
+ <p>This is <em>italic</em> text.</p>
67
+ <p>This is <span style="color: red;">colored</span> text.</p>
68
+ </div>
69
+ `;
70
+
71
+ /**
72
+ * HTML with forms
73
+ */
74
+ export const FORM_HTML = `
75
+ <div>
76
+ <form>
77
+ <input type="text" value="Test input" style="padding: 5px; border: 1px solid #ccc;" />
78
+ <textarea style="padding: 5px; border: 1px solid #ccc;">Test textarea value</textarea>
79
+ <button type="submit">Submit</button>
80
+ </form>
81
+ </div>
82
+ `;
83
+
84
+ /**
85
+ * HTML with colors
86
+ */
87
+ export const COLOR_HTML = `
88
+ <div style="display: flex; gap: 10px;">
89
+ <div style="width: 50px; height: 50px; background-color: red;"></div>
90
+ <div style="width: 50px; height: 50px; background-color: green;"></div>
91
+ <div style="width: 50px; height: 50px; background-color: blue;"></div>
92
+ <div style="width: 50px; height: 50px; background-color: yellow;"></div>
93
+ </div>
94
+ `;
95
+
96
+ /**
97
+ * HTML with borders and shadows
98
+ */
99
+ export const BORDER_SHADOW_HTML = `
100
+ <div style="
101
+ width: 150px;
102
+ height: 150px;
103
+ background-color: white;
104
+ border: 2px solid #333;
105
+ border-radius: 8px;
106
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
107
+ padding: 15px;
108
+ ">
109
+ <p style="margin: 0; text-align: center;">Bordered & Shadowed</p>
110
+ </div>
111
+ `;
112
+
113
+ /**
114
+ * HTML with transformations
115
+ */
116
+ export const TRANSFORM_HTML = `
117
+ <div style="
118
+ width: 100px;
119
+ height: 100px;
120
+ background-color: blue;
121
+ transform: rotate(45deg);
122
+ "></div>
123
+ `;
124
+
125
+ /**
126
+ * HTML with multiple images
127
+ */
128
+ export const MULTI_IMAGE_HTML = `
129
+ <div style="display: flex; gap: 10px;">
130
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="img1" style="width: 50px; height: 50px;" />
131
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="img2" style="width: 50px; height: 50px;" />
132
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="img3" style="width: 50px; height: 50px;" />
133
+ </div>
134
+ `;
135
+
136
+ /**
137
+ * HTML with table
138
+ */
139
+ export const TABLE_HTML = `
140
+ <table style="border-collapse: collapse; width: 200px;">
141
+ <tr style="background-color: #ddd;">
142
+ <th style="border: 1px solid #333; padding: 8px;">Column 1</th>
143
+ <th style="border: 1px solid #333; padding: 8px;">Column 2</th>
144
+ </tr>
145
+ <tr>
146
+ <td style="border: 1px solid #333; padding: 8px;">Data 1</td>
147
+ <td style="border: 1px solid #333; padding: 8px;">Data 2</td>
148
+ </tr>
149
+ <tr>
150
+ <td style="border: 1px solid #333; padding: 8px;">Data 3</td>
151
+ <td style="border: 1px solid #333; padding: 8px;">Data 4</td>
152
+ </tr>
153
+ </table>
154
+ `;
155
+
156
+ /**
157
+ * HTML with SVG
158
+ */
159
+ export const SVG_HTML = `
160
+ <div>
161
+ <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
162
+ <circle cx="50" cy="50" r="40" fill="blue" />
163
+ <rect x="10" y="10" width="30" height="30" fill="red" />
164
+ </svg>
165
+ </div>
166
+ `;
167
+
168
+ /**
169
+ * Empty div fixture
170
+ */
171
+ export const EMPTY_HTML = `<div></div>`;
172
+
173
+ /**
174
+ * Large HTML for performance testing
175
+ */
176
+ export function generateLargeHTML(itemCount: number = 100): string {
177
+ let html = '<div style="background-color: #f5f5f5; padding: 10px;">';
178
+ for (let i = 0; i < itemCount; i++) {
179
+ html += `
180
+ <div style="
181
+ background-color: ${i % 2 === 0 ? '#fff' : '#ddd'};
182
+ padding: 5px;
183
+ margin: 5px;
184
+ border: 1px solid #ccc;
185
+ ">
186
+ <p>Item ${i + 1}</p>
187
+ </div>
188
+ `;
189
+ }
190
+ html += '</div>';
191
+ return html;
192
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Image test fixtures
3
+ */
4
+
5
+ /**
6
+ * Base64-encoded 1x1 transparent PNG
7
+ */
8
+ export const PNG_1X1_TRANSPARENT =
9
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
10
+
11
+ /**
12
+ * Base64-encoded 1x1 red JPEG
13
+ */
14
+ export const JPEG_1X1_RED =
15
+ 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8VAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCwAA8A/9k=';
16
+
17
+ /**
18
+ * Base64-encoded 1x1 blue GIF
19
+ */
20
+ export const GIF_1X1_BLUE =
21
+ 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
22
+
23
+ /**
24
+ * SVG data URL
25
+ */
26
+ export const SVG_CIRCLE =
27
+ 'data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22100%22%20height%3D%22100%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2240%22%20fill%3D%22blue%22%2F%3E%3C%2Fsvg%3E';
28
+
29
+ /**
30
+ * Invalid/broken image data URL
31
+ */
32
+ export const INVALID_IMAGE_URL = 'data:image/png;base64,invalid-base64-data!!!';
33
+
34
+ /**
35
+ * Remote image URL (would require network)
36
+ */
37
+ export const REMOTE_IMAGE_URL = 'https://example.com/image.png';
38
+
39
+ /**
40
+ * CORS-restricted image URL
41
+ */
42
+ export const CORS_IMAGE_URL = 'https://other-domain.com/image.png';
43
+
44
+ /**
45
+ * Collection of all test images
46
+ */
47
+ export const TEST_IMAGES = {
48
+ png: PNG_1X1_TRANSPARENT,
49
+ jpeg: JPEG_1X1_RED,
50
+ gif: GIF_1X1_BLUE,
51
+ svg: SVG_CIRCLE,
52
+ invalid: INVALID_IMAGE_URL,
53
+ remote: REMOTE_IMAGE_URL,
54
+ cors: CORS_IMAGE_URL,
55
+ };
56
+
57
+ /**
58
+ * Create a test image HTML element
59
+ */
60
+ export function createTestImageElement(
61
+ src: string = PNG_1X1_TRANSPARENT,
62
+ alt: string = 'test'
63
+ ): HTMLImageElement {
64
+ const img = document.createElement('img');
65
+ img.src = src;
66
+ img.alt = alt;
67
+ img.style.width = '50px';
68
+ img.style.height = '50px';
69
+ return img;
70
+ }
71
+
72
+ /**
73
+ * Create multiple test images
74
+ */
75
+ export function createTestImageElements(count: number = 3): HTMLImageElement[] {
76
+ const images: HTMLImageElement[] = [];
77
+ const formats = ['png', 'jpeg', 'gif'] as const;
78
+
79
+ for (let i = 0; i < count; i++) {
80
+ const format = formats[i % formats.length];
81
+ const src = TEST_IMAGES[format];
82
+ images.push(createTestImageElement(src, `test-${i}`));
83
+ }
84
+
85
+ return images;
86
+ }