html2canvas-pro 2.1.0 → 2.1.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.
- package/dist/html2canvas-pro.esm.js +21 -7
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +21 -7
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +3 -3
- package/dist/lib/core/cache-storage.js +2 -2
- package/dist/lib/core/features.js +2 -2
- package/dist/lib/render/canvas/background-renderer.js +6 -0
- package/dist/lib/render/canvas/canvas-renderer.js +5 -1
- package/dist/lib/render/canvas/foreignobject-renderer.js +5 -1
- package/package.json +3 -11
- package/dist/lib/invariant.js +0 -9
- package/dist/types/invariant.d.ts +0 -1
- package/src/__tests__/index.ts +0 -99
- package/src/config.ts +0 -107
- package/src/core/__mocks__/cache-storage.ts +0 -1
- package/src/core/__mocks__/context.ts +0 -19
- package/src/core/__mocks__/features.ts +0 -8
- package/src/core/__mocks__/logger.ts +0 -17
- package/src/core/__tests__/cache-storage.test.ts +0 -205
- package/src/core/__tests__/cache-storage.ts +0 -278
- package/src/core/__tests__/logger.ts +0 -29
- package/src/core/__tests__/validator.ts +0 -359
- package/src/core/bitwise.ts +0 -1
- package/src/core/cache-storage.ts +0 -315
- package/src/core/context.ts +0 -31
- package/src/core/debugger.ts +0 -32
- package/src/core/features.ts +0 -222
- package/src/core/logger.ts +0 -64
- package/src/core/origin-checker.ts +0 -57
- package/src/core/performance-monitor.ts +0 -241
- package/src/core/render-element.ts +0 -272
- package/src/core/util.ts +0 -1
- package/src/core/validator.ts +0 -593
- package/src/css/index.ts +0 -427
- package/src/css/layout/__mocks__/bounds.ts +0 -6
- package/src/css/layout/bounds.ts +0 -79
- package/src/css/layout/text.ts +0 -161
- package/src/css/property-descriptor.ts +0 -49
- package/src/css/property-descriptors/__tests__/background-tests.ts +0 -65
- package/src/css/property-descriptors/__tests__/clip-path.test.ts +0 -280
- package/src/css/property-descriptors/__tests__/font-family.ts +0 -25
- package/src/css/property-descriptors/__tests__/image-rendering-integration.test.ts +0 -153
- package/src/css/property-descriptors/__tests__/image-rendering-performance.test.ts +0 -175
- package/src/css/property-descriptors/__tests__/image-rendering.test.ts +0 -72
- package/src/css/property-descriptors/__tests__/paint-order.ts +0 -87
- package/src/css/property-descriptors/__tests__/text-shadow.ts +0 -94
- package/src/css/property-descriptors/__tests__/transform-tests.ts +0 -18
- package/src/css/property-descriptors/background-clip.ts +0 -30
- package/src/css/property-descriptors/background-color.ts +0 -9
- package/src/css/property-descriptors/background-image.ts +0 -27
- package/src/css/property-descriptors/background-origin.ts +0 -31
- package/src/css/property-descriptors/background-position.ts +0 -38
- package/src/css/property-descriptors/background-repeat.ts +0 -44
- package/src/css/property-descriptors/background-size.ts +0 -27
- package/src/css/property-descriptors/border-color.ts +0 -13
- package/src/css/property-descriptors/border-radius.ts +0 -19
- package/src/css/property-descriptors/border-style.ts +0 -34
- package/src/css/property-descriptors/border-width.ts +0 -20
- package/src/css/property-descriptors/box-shadow.ts +0 -60
- package/src/css/property-descriptors/clip-path.ts +0 -271
- package/src/css/property-descriptors/color.ts +0 -9
- package/src/css/property-descriptors/content.ts +0 -26
- package/src/css/property-descriptors/counter-increment.ts +0 -43
- package/src/css/property-descriptors/counter-reset.ts +0 -36
- package/src/css/property-descriptors/direction.ts +0 -23
- package/src/css/property-descriptors/display.ts +0 -117
- package/src/css/property-descriptors/duration.ts +0 -14
- package/src/css/property-descriptors/float.ts +0 -29
- package/src/css/property-descriptors/font-family.ts +0 -38
- package/src/css/property-descriptors/font-size.ts +0 -9
- package/src/css/property-descriptors/font-style.ts +0 -25
- package/src/css/property-descriptors/font-variant.ts +0 -12
- package/src/css/property-descriptors/font-weight.ts +0 -26
- package/src/css/property-descriptors/image-rendering.ts +0 -33
- package/src/css/property-descriptors/letter-spacing.ts +0 -25
- package/src/css/property-descriptors/line-break.ts +0 -22
- package/src/css/property-descriptors/line-height.ts +0 -22
- package/src/css/property-descriptors/list-style-image.ts +0 -19
- package/src/css/property-descriptors/list-style-position.ts +0 -22
- package/src/css/property-descriptors/list-style-type.ts +0 -179
- package/src/css/property-descriptors/margin.ts +0 -13
- package/src/css/property-descriptors/mix-blend-mode.ts +0 -35
- package/src/css/property-descriptors/object-fit.ts +0 -39
- package/src/css/property-descriptors/opacity.ts +0 -15
- package/src/css/property-descriptors/overflow-wrap.ts +0 -22
- package/src/css/property-descriptors/overflow.ts +0 -34
- package/src/css/property-descriptors/padding.ts +0 -14
- package/src/css/property-descriptors/paint-order.ts +0 -42
- package/src/css/property-descriptors/position.ts +0 -30
- package/src/css/property-descriptors/quotes.ts +0 -57
- package/src/css/property-descriptors/rotate.ts +0 -34
- package/src/css/property-descriptors/text-align.ts +0 -26
- package/src/css/property-descriptors/text-decoration-color.ts +0 -9
- package/src/css/property-descriptors/text-decoration-line.ts +0 -38
- package/src/css/property-descriptors/text-decoration-style.ts +0 -32
- package/src/css/property-descriptors/text-decoration-thickness.ts +0 -30
- package/src/css/property-descriptors/text-overflow.ts +0 -23
- package/src/css/property-descriptors/text-shadow.ts +0 -52
- package/src/css/property-descriptors/text-transform.ts +0 -27
- package/src/css/property-descriptors/text-underline-offset.ts +0 -27
- package/src/css/property-descriptors/transform-origin.ts +0 -29
- package/src/css/property-descriptors/transform.ts +0 -74
- package/src/css/property-descriptors/visibility.ts +0 -25
- package/src/css/property-descriptors/webkit-line-clamp.ts +0 -30
- package/src/css/property-descriptors/webkit-text-stroke-color.ts +0 -8
- package/src/css/property-descriptors/webkit-text-stroke-width.ts +0 -15
- package/src/css/property-descriptors/word-break.ts +0 -25
- package/src/css/property-descriptors/writing-mode.ts +0 -37
- package/src/css/property-descriptors/z-index.ts +0 -27
- package/src/css/syntax/__tests__/tokernizer-tests.ts +0 -29
- package/src/css/syntax/parser.ts +0 -188
- package/src/css/syntax/tokenizer.ts +0 -822
- package/src/css/type-descriptor.ts +0 -7
- package/src/css/types/__tests__/color-tests.ts +0 -147
- package/src/css/types/__tests__/image-tests.ts +0 -239
- package/src/css/types/angle.ts +0 -86
- package/src/css/types/color-math.ts +0 -22
- package/src/css/types/color-spaces/a98.ts +0 -86
- package/src/css/types/color-spaces/p3.ts +0 -92
- package/src/css/types/color-spaces/pro-photo.ts +0 -87
- package/src/css/types/color-spaces/rec2020.ts +0 -90
- package/src/css/types/color-spaces/srgb.ts +0 -87
- package/src/css/types/color-utilities.ts +0 -452
- package/src/css/types/color.ts +0 -485
- package/src/css/types/functions/-prefix-linear-gradient.ts +0 -35
- package/src/css/types/functions/-prefix-radial-gradient.ts +0 -106
- package/src/css/types/functions/-webkit-gradient.ts +0 -69
- package/src/css/types/functions/__tests__/radial-gradient.ts +0 -69
- package/src/css/types/functions/counter.ts +0 -511
- package/src/css/types/functions/gradient.ts +0 -206
- package/src/css/types/functions/linear-gradient.ts +0 -28
- package/src/css/types/functions/radial-gradient.ts +0 -101
- package/src/css/types/image.ts +0 -120
- package/src/css/types/index.ts +0 -1
- package/src/css/types/length-percentage.ts +0 -137
- package/src/css/types/length.ts +0 -7
- package/src/css/types/time.ts +0 -20
- package/src/dom/__mocks__/document-cloner.ts +0 -22
- package/src/dom/__tests__/dom-normalizer.test.ts +0 -133
- package/src/dom/__tests__/element-container.test.ts +0 -129
- package/src/dom/document-cloner.ts +0 -929
- package/src/dom/dom-normalizer.ts +0 -133
- package/src/dom/element-container.ts +0 -75
- package/src/dom/elements/li-element-container.ts +0 -10
- package/src/dom/elements/ol-element-container.ts +0 -12
- package/src/dom/elements/select-element-container.ts +0 -10
- package/src/dom/elements/textarea-element-container.ts +0 -9
- package/src/dom/node-parser.ts +0 -177
- package/src/dom/node-type-guards.ts +0 -70
- package/src/dom/replaced-elements/canvas-element-container.ts +0 -15
- package/src/dom/replaced-elements/iframe-element-container.ts +0 -55
- package/src/dom/replaced-elements/image-element-container.ts +0 -16
- package/src/dom/replaced-elements/index.ts +0 -5
- package/src/dom/replaced-elements/input-element-container.ts +0 -105
- package/src/dom/replaced-elements/pseudo-elements.ts +0 -0
- package/src/dom/replaced-elements/svg-element-container.ts +0 -23
- package/src/dom/text-container.ts +0 -42
- package/src/global.d.ts +0 -19
- package/src/index.ts +0 -82
- package/src/invariant.ts +0 -5
- package/src/options.ts +0 -55
- package/src/render/__tests__/object-fit.test.ts +0 -85
- package/src/render/background.ts +0 -298
- package/src/render/bezier-curve.ts +0 -47
- package/src/render/border.ts +0 -165
- package/src/render/bound-curves.ts +0 -388
- package/src/render/box-sizing.ts +0 -31
- package/src/render/canvas/__tests__/background-renderer.test.ts +0 -72
- package/src/render/canvas/__tests__/border-renderer.test.ts +0 -24
- package/src/render/canvas/__tests__/effects-renderer.test.ts +0 -32
- package/src/render/canvas/__tests__/text-renderer.test.ts +0 -471
- package/src/render/canvas/background-renderer.ts +0 -271
- package/src/render/canvas/border-renderer.ts +0 -224
- package/src/render/canvas/canvas-path.ts +0 -31
- package/src/render/canvas/canvas-renderer.ts +0 -641
- package/src/render/canvas/effects-renderer.ts +0 -130
- package/src/render/canvas/foreignobject-renderer.ts +0 -53
- package/src/render/canvas/text-renderer.ts +0 -700
- package/src/render/effects.ts +0 -75
- package/src/render/font-metrics.ts +0 -72
- package/src/render/object-fit.ts +0 -100
- package/src/render/path.ts +0 -37
- package/src/render/renderer-interface.ts +0 -28
- package/src/render/stacking-context.ts +0 -386
- package/src/render/vector.ts +0 -19
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import { deepStrictEqual, fail } from 'assert';
|
|
2
|
-
import { FEATURES } from '../features';
|
|
3
|
-
import { CacheStorage } from '../cache-storage';
|
|
4
|
-
import { Context } from '../context';
|
|
5
|
-
import { Bounds } from '../../css/layout/bounds';
|
|
6
|
-
import { Html2CanvasConfig } from '../../config';
|
|
7
|
-
|
|
8
|
-
const proxy = 'http://example.com/proxy';
|
|
9
|
-
|
|
10
|
-
const createMockContext = (origin: string, opts = {}) => {
|
|
11
|
-
const mockWindow = {
|
|
12
|
-
location: {
|
|
13
|
-
href: origin
|
|
14
|
-
},
|
|
15
|
-
document: {
|
|
16
|
-
createElement(_name: string) {
|
|
17
|
-
let _href = '';
|
|
18
|
-
return {
|
|
19
|
-
set href(value: string) {
|
|
20
|
-
_href = value;
|
|
21
|
-
},
|
|
22
|
-
get href() {
|
|
23
|
-
return _href;
|
|
24
|
-
},
|
|
25
|
-
get protocol() {
|
|
26
|
-
return new URL(_href).protocol;
|
|
27
|
-
},
|
|
28
|
-
get hostname() {
|
|
29
|
-
return new URL(_href).hostname;
|
|
30
|
-
},
|
|
31
|
-
get port() {
|
|
32
|
-
return new URL(_href).port;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// For backward compatibility, also initialize static CacheStorage
|
|
40
|
-
CacheStorage.setContext(mockWindow as Window);
|
|
41
|
-
|
|
42
|
-
const config = new Html2CanvasConfig({ window: mockWindow as Window });
|
|
43
|
-
|
|
44
|
-
return new Context(
|
|
45
|
-
{
|
|
46
|
-
logging: false,
|
|
47
|
-
imageTimeout: 0,
|
|
48
|
-
useCORS: false,
|
|
49
|
-
allowTaint: false,
|
|
50
|
-
proxy,
|
|
51
|
-
...opts
|
|
52
|
-
},
|
|
53
|
-
new Bounds(0, 0, 0, 0),
|
|
54
|
-
config
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const images: ImageMock[] = [];
|
|
59
|
-
const xhr: XMLHttpRequestMock[] = [];
|
|
60
|
-
const sleep = async (timeout: number) => await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
61
|
-
|
|
62
|
-
class ImageMock {
|
|
63
|
-
src?: string;
|
|
64
|
-
crossOrigin?: string;
|
|
65
|
-
onload?: () => void;
|
|
66
|
-
constructor() {
|
|
67
|
-
images.push(this);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
class XMLHttpRequestMock {
|
|
72
|
-
sent: boolean;
|
|
73
|
-
status: number;
|
|
74
|
-
timeout: number;
|
|
75
|
-
method?: string;
|
|
76
|
-
url?: string;
|
|
77
|
-
response?: string;
|
|
78
|
-
onload?: () => void;
|
|
79
|
-
ontimeout?: () => void;
|
|
80
|
-
constructor() {
|
|
81
|
-
this.sent = false;
|
|
82
|
-
this.status = 500;
|
|
83
|
-
this.timeout = 5000;
|
|
84
|
-
xhr.push(this);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async load(status: number, response: string) {
|
|
88
|
-
this.response = response;
|
|
89
|
-
this.status = status;
|
|
90
|
-
if (this.onload) {
|
|
91
|
-
this.onload();
|
|
92
|
-
}
|
|
93
|
-
await sleep(0);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
open(method: string, url: string) {
|
|
97
|
-
this.method = method;
|
|
98
|
-
this.url = url;
|
|
99
|
-
}
|
|
100
|
-
send() {
|
|
101
|
-
this.sent = true;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
Object.defineProperty(global, 'Image', { value: ImageMock, writable: true });
|
|
106
|
-
Object.defineProperty(global, 'XMLHttpRequest', {
|
|
107
|
-
value: XMLHttpRequestMock,
|
|
108
|
-
writable: true
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
const setFeatures = (opts: { [key: string]: boolean } = {}) => {
|
|
112
|
-
const defaults: { [key: string]: boolean } = {
|
|
113
|
-
SUPPORT_SVG_DRAWING: true,
|
|
114
|
-
SUPPORT_CORS_IMAGES: true,
|
|
115
|
-
SUPPORT_CORS_XHR: true,
|
|
116
|
-
SUPPORT_RESPONSE_TYPE: false
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
Object.keys(defaults).forEach((key) => {
|
|
120
|
-
Object.defineProperty(FEATURES, key, {
|
|
121
|
-
value: typeof opts[key] === 'boolean' ? opts[key] : defaults[key],
|
|
122
|
-
writable: true
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
describe('cache-storage', () => {
|
|
128
|
-
beforeEach(() => setFeatures());
|
|
129
|
-
afterEach(() => {
|
|
130
|
-
xhr.splice(0, xhr.length);
|
|
131
|
-
images.splice(0, images.length);
|
|
132
|
-
});
|
|
133
|
-
it('addImage adds images to cache', async () => {
|
|
134
|
-
const { cache } = createMockContext('http://example.com', { proxy: null });
|
|
135
|
-
await cache.addImage('http://example.com/test.jpg');
|
|
136
|
-
await cache.addImage('http://example.com/test2.jpg');
|
|
137
|
-
|
|
138
|
-
deepStrictEqual(images.length, 2);
|
|
139
|
-
deepStrictEqual(images[0].src, 'http://example.com/test.jpg');
|
|
140
|
-
deepStrictEqual(images[1].src, 'http://example.com/test2.jpg');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('addImage should not add duplicate entries', async () => {
|
|
144
|
-
const { cache } = createMockContext('http://example.com');
|
|
145
|
-
await cache.addImage('http://example.com/test.jpg');
|
|
146
|
-
await cache.addImage('http://example.com/test.jpg');
|
|
147
|
-
|
|
148
|
-
deepStrictEqual(images.length, 1);
|
|
149
|
-
deepStrictEqual(images[0].src, 'http://example.com/test.jpg');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
describe('svg', () => {
|
|
153
|
-
it('should add svg images correctly', async () => {
|
|
154
|
-
const { cache } = createMockContext('http://example.com');
|
|
155
|
-
await cache.addImage('http://example.com/test.svg');
|
|
156
|
-
await cache.addImage('http://example.com/test2.svg');
|
|
157
|
-
|
|
158
|
-
deepStrictEqual(images.length, 2);
|
|
159
|
-
deepStrictEqual(images[0].src, 'http://example.com/test.svg');
|
|
160
|
-
deepStrictEqual(images[1].src, 'http://example.com/test2.svg');
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should omit svg images if not supported', async () => {
|
|
164
|
-
setFeatures({ SUPPORT_SVG_DRAWING: false });
|
|
165
|
-
const { cache } = createMockContext('http://example.com');
|
|
166
|
-
await cache.addImage('http://example.com/test.svg');
|
|
167
|
-
await cache.addImage('http://example.com/test2.svg');
|
|
168
|
-
|
|
169
|
-
deepStrictEqual(images.length, 0);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
describe('cross-origin', () => {
|
|
174
|
-
it('addImage should not add images it cannot load/render', async () => {
|
|
175
|
-
const { cache } = createMockContext('http://example.com', {
|
|
176
|
-
proxy: undefined
|
|
177
|
-
});
|
|
178
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
179
|
-
deepStrictEqual(images.length, 0);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('addImage should add images if tainting enabled', async () => {
|
|
183
|
-
const { cache } = createMockContext('http://example.com', {
|
|
184
|
-
allowTaint: true,
|
|
185
|
-
proxy: undefined
|
|
186
|
-
});
|
|
187
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
188
|
-
deepStrictEqual(images.length, 1);
|
|
189
|
-
deepStrictEqual(images[0].src, 'http://html2canvas.hertzen.com/test.jpg');
|
|
190
|
-
deepStrictEqual(images[0].crossOrigin, undefined);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('addImage should add images if cors enabled', async () => {
|
|
194
|
-
const { cache } = createMockContext('http://example.com', { useCORS: true });
|
|
195
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
196
|
-
deepStrictEqual(images.length, 1);
|
|
197
|
-
deepStrictEqual(images[0].src, 'http://html2canvas.hertzen.com/test.jpg');
|
|
198
|
-
deepStrictEqual(images[0].crossOrigin, 'anonymous');
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('addImage should not add images if cors enabled but not supported', async () => {
|
|
202
|
-
setFeatures({ SUPPORT_CORS_IMAGES: false });
|
|
203
|
-
|
|
204
|
-
const { cache } = createMockContext('http://example.com', {
|
|
205
|
-
useCORS: true,
|
|
206
|
-
proxy: undefined
|
|
207
|
-
});
|
|
208
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
209
|
-
deepStrictEqual(images.length, 0);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('addImage should not add images to proxy if cors enabled', async () => {
|
|
213
|
-
const { cache } = createMockContext('http://example.com', { useCORS: true });
|
|
214
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
215
|
-
deepStrictEqual(images.length, 1);
|
|
216
|
-
deepStrictEqual(images[0].src, 'http://html2canvas.hertzen.com/test.jpg');
|
|
217
|
-
deepStrictEqual(images[0].crossOrigin, 'anonymous');
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it('addImage should use proxy ', async () => {
|
|
221
|
-
const { cache } = createMockContext('http://example.com');
|
|
222
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
223
|
-
deepStrictEqual(xhr.length, 1);
|
|
224
|
-
deepStrictEqual(
|
|
225
|
-
xhr[0].url,
|
|
226
|
-
`${proxy}?url=${encodeURIComponent('http://html2canvas.hertzen.com/test.jpg')}&responseType=text`
|
|
227
|
-
);
|
|
228
|
-
await xhr[0].load(200, '<data response>');
|
|
229
|
-
|
|
230
|
-
deepStrictEqual(images.length, 1);
|
|
231
|
-
deepStrictEqual(images[0].src, '<data response>');
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('proxy should respect imageTimeout', async () => {
|
|
235
|
-
const { cache } = createMockContext('http://example.com', {
|
|
236
|
-
imageTimeout: 10
|
|
237
|
-
});
|
|
238
|
-
await cache.addImage('http://html2canvas.hertzen.com/test.jpg');
|
|
239
|
-
|
|
240
|
-
deepStrictEqual(xhr.length, 1);
|
|
241
|
-
deepStrictEqual(
|
|
242
|
-
xhr[0].url,
|
|
243
|
-
`${proxy}?url=${encodeURIComponent('http://html2canvas.hertzen.com/test.jpg')}&responseType=text`
|
|
244
|
-
);
|
|
245
|
-
deepStrictEqual(xhr[0].timeout, 10);
|
|
246
|
-
if (xhr[0].ontimeout) {
|
|
247
|
-
xhr[0].ontimeout();
|
|
248
|
-
}
|
|
249
|
-
try {
|
|
250
|
-
await cache.match('http://html2canvas.hertzen.com/test.jpg');
|
|
251
|
-
fail('Expected result to timeout');
|
|
252
|
-
} catch (e) {}
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it('match should return cache entry', async () => {
|
|
257
|
-
const { cache } = createMockContext('http://example.com');
|
|
258
|
-
await cache.addImage('http://example.com/test.jpg');
|
|
259
|
-
|
|
260
|
-
if (images[0].onload) {
|
|
261
|
-
images[0].onload();
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const response = await cache.match('http://example.com/test.jpg');
|
|
265
|
-
|
|
266
|
-
deepStrictEqual((response as HTMLImageElement).src, 'http://example.com/test.jpg');
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
it('image should respect imageTimeout', async () => {
|
|
270
|
-
const { cache } = createMockContext('http://example.com', { imageTimeout: 10 });
|
|
271
|
-
cache.addImage('http://example.com/test.jpg');
|
|
272
|
-
|
|
273
|
-
try {
|
|
274
|
-
await cache.match('http://example.com/test.jpg');
|
|
275
|
-
fail('Expected result to timeout');
|
|
276
|
-
} catch (e) {}
|
|
277
|
-
});
|
|
278
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Logger } from '../logger';
|
|
2
|
-
|
|
3
|
-
describe('logger', () => {
|
|
4
|
-
let infoSpy: any;
|
|
5
|
-
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
infoSpy = vi.spyOn(console, 'info').mockImplementation(() => {
|
|
8
|
-
// do nothing
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
infoSpy.mockRestore();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should call console.info when logger enabled', () => {
|
|
17
|
-
const id = Math.random().toString();
|
|
18
|
-
const logger = new Logger({ id, enabled: true });
|
|
19
|
-
logger.info('testing');
|
|
20
|
-
expect(infoSpy).toHaveBeenLastCalledWith(id, expect.stringMatching(/\d+ms/), 'testing');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("shouldn't call console.info when logger disabled", () => {
|
|
24
|
-
const id = Math.random().toString();
|
|
25
|
-
const logger = new Logger({ id, enabled: false });
|
|
26
|
-
logger.info('testing');
|
|
27
|
-
expect(infoSpy).not.toHaveBeenCalled();
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { strictEqual } from 'assert';
|
|
2
|
-
import { createDefaultValidator, createStrictValidator } from '../validator';
|
|
3
|
-
|
|
4
|
-
describe('Validator', () => {
|
|
5
|
-
describe('URL validation', () => {
|
|
6
|
-
const validator = createDefaultValidator();
|
|
7
|
-
|
|
8
|
-
it('should accept valid HTTP URLs', () => {
|
|
9
|
-
const result = validator.validateUrl('http://example.com/test.jpg', 'image');
|
|
10
|
-
strictEqual(result.valid, true);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should accept valid HTTPS URLs', () => {
|
|
14
|
-
const result = validator.validateUrl('https://example.com/test.jpg', 'image');
|
|
15
|
-
strictEqual(result.valid, true);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should accept data URLs by default', () => {
|
|
19
|
-
const result = validator.validateUrl('data:image/png;base64,iVBORw0KGgo=', 'image');
|
|
20
|
-
strictEqual(result.valid, true);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should accept blob URLs', () => {
|
|
24
|
-
const result = validator.validateUrl('blob:http://example.com/uuid', 'image');
|
|
25
|
-
strictEqual(result.valid, true);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should reject invalid protocols', () => {
|
|
29
|
-
const result = validator.validateUrl('ftp://example.com/test.jpg', 'image');
|
|
30
|
-
strictEqual(result.valid, false);
|
|
31
|
-
strictEqual(result.error?.includes('Protocol'), true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should reject file:// URLs', () => {
|
|
35
|
-
const result = validator.validateUrl('file:///etc/passwd', 'image');
|
|
36
|
-
strictEqual(result.valid, false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should reject javascript: URLs', () => {
|
|
40
|
-
const result = validator.validateUrl('javascript:alert(1)', 'general');
|
|
41
|
-
strictEqual(result.valid, false);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should reject empty URLs', () => {
|
|
45
|
-
const result = validator.validateUrl('', 'image');
|
|
46
|
-
strictEqual(result.valid, false);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should reject non-string URLs', () => {
|
|
50
|
-
const result = validator.validateUrl(null as any, 'image');
|
|
51
|
-
strictEqual(result.valid, false);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should reject malformed URLs', () => {
|
|
55
|
-
const result = validator.validateUrl('not a url', 'image');
|
|
56
|
-
strictEqual(result.valid, false);
|
|
57
|
-
strictEqual(result.error?.includes('Invalid URL'), true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('Proxy URL validation (SSRF prevention)', () => {
|
|
62
|
-
it('should reject localhost for proxy URLs', () => {
|
|
63
|
-
const validator = createDefaultValidator();
|
|
64
|
-
const result = validator.validateUrl('http://localhost:8080/proxy', 'proxy');
|
|
65
|
-
strictEqual(result.valid, false);
|
|
66
|
-
strictEqual(result.error?.includes('Localhost'), true);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should reject 127.0.0.1 for proxy URLs', () => {
|
|
70
|
-
const validator = createDefaultValidator();
|
|
71
|
-
const result = validator.validateUrl('http://127.0.0.1/proxy', 'proxy');
|
|
72
|
-
strictEqual(result.valid, false);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should reject ::1 for proxy URLs', () => {
|
|
76
|
-
const validator = createDefaultValidator();
|
|
77
|
-
const result = validator.validateUrl('http://[::1]/proxy', 'proxy');
|
|
78
|
-
strictEqual(result.valid, false);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should reject private IP ranges (10.x.x.x)', () => {
|
|
82
|
-
const validator = createDefaultValidator();
|
|
83
|
-
const result = validator.validateUrl('http://10.0.0.1/proxy', 'proxy');
|
|
84
|
-
strictEqual(result.valid, false);
|
|
85
|
-
strictEqual(result.error?.includes('Private IP'), true);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('should reject private IP ranges (172.16-31.x.x)', () => {
|
|
89
|
-
const validator = createDefaultValidator();
|
|
90
|
-
const results = [
|
|
91
|
-
validator.validateUrl('http://172.16.0.1/proxy', 'proxy'),
|
|
92
|
-
validator.validateUrl('http://172.20.0.1/proxy', 'proxy'),
|
|
93
|
-
validator.validateUrl('http://172.31.255.254/proxy', 'proxy')
|
|
94
|
-
];
|
|
95
|
-
results.forEach((result) => strictEqual(result.valid, false));
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('should reject private IP ranges (192.168.x.x)', () => {
|
|
99
|
-
const validator = createDefaultValidator();
|
|
100
|
-
const result = validator.validateUrl('http://192.168.1.1/proxy', 'proxy');
|
|
101
|
-
strictEqual(result.valid, false);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should reject link-local addresses', () => {
|
|
105
|
-
const validator = createDefaultValidator();
|
|
106
|
-
const result = validator.validateUrl('http://169.254.1.1/proxy', 'proxy');
|
|
107
|
-
strictEqual(result.valid, false);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should accept public IPs for proxy URLs', () => {
|
|
111
|
-
const validator = createDefaultValidator();
|
|
112
|
-
const result = validator.validateUrl('https://8.8.8.8/proxy', 'proxy');
|
|
113
|
-
strictEqual(result.valid, true);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should enforce proxy domain whitelist', () => {
|
|
117
|
-
const validator = createStrictValidator(['example.com', 'trusted.org']);
|
|
118
|
-
|
|
119
|
-
const allowed = validator.validateUrl('https://example.com/proxy', 'proxy');
|
|
120
|
-
strictEqual(allowed.valid, true);
|
|
121
|
-
|
|
122
|
-
const notAllowed = validator.validateUrl('https://evil.com/proxy', 'proxy');
|
|
123
|
-
strictEqual(notAllowed.valid, false);
|
|
124
|
-
strictEqual(notAllowed.error?.includes('not in the allowed list'), true);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should allow subdomains of whitelisted domains', () => {
|
|
128
|
-
const validator = createStrictValidator(['example.com']);
|
|
129
|
-
const result = validator.validateUrl('https://api.example.com/proxy', 'proxy');
|
|
130
|
-
strictEqual(result.valid, true);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe('CSP nonce validation', () => {
|
|
135
|
-
const validator = createDefaultValidator();
|
|
136
|
-
|
|
137
|
-
it('should accept valid nonce', () => {
|
|
138
|
-
const result = validator.validateCspNonce('ABC123def456GHI789jkl');
|
|
139
|
-
strictEqual(result.valid, true);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should reject empty nonce', () => {
|
|
143
|
-
const result = validator.validateCspNonce('');
|
|
144
|
-
strictEqual(result.valid, false);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('should reject non-string nonce', () => {
|
|
148
|
-
const result = validator.validateCspNonce(123 as any);
|
|
149
|
-
strictEqual(result.valid, false);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('should reject too short nonce', () => {
|
|
153
|
-
const result = validator.validateCspNonce('short');
|
|
154
|
-
strictEqual(result.valid, false);
|
|
155
|
-
strictEqual(result.error?.includes('too short'), true);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should reject nonce with invalid characters', () => {
|
|
159
|
-
const result = validator.validateCspNonce('ABC<script>alert(1)</script>');
|
|
160
|
-
strictEqual(result.valid, false);
|
|
161
|
-
strictEqual(result.error?.includes('invalid characters'), true);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should accept base64-like nonces', () => {
|
|
165
|
-
const result = validator.validateCspNonce('AbCdEfGhIjKlMnOpQrStUvWxYz0123456789+/=');
|
|
166
|
-
strictEqual(result.valid, true);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('Image timeout validation', () => {
|
|
171
|
-
const validator = createDefaultValidator();
|
|
172
|
-
|
|
173
|
-
it('should accept valid timeout', () => {
|
|
174
|
-
const result = validator.validateImageTimeout(15000);
|
|
175
|
-
strictEqual(result.valid, true);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('should reject negative timeout', () => {
|
|
179
|
-
const result = validator.validateImageTimeout(-1000);
|
|
180
|
-
strictEqual(result.valid, false);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('should reject non-number timeout', () => {
|
|
184
|
-
const result = validator.validateImageTimeout('15000' as any);
|
|
185
|
-
strictEqual(result.valid, false);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('should reject NaN timeout', () => {
|
|
189
|
-
const result = validator.validateImageTimeout(NaN);
|
|
190
|
-
strictEqual(result.valid, false);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('should enforce maximum timeout', () => {
|
|
194
|
-
const strictValidator = createStrictValidator([]);
|
|
195
|
-
const result = strictValidator.validateImageTimeout(120000); // 2 minutes
|
|
196
|
-
strictEqual(result.valid, false);
|
|
197
|
-
strictEqual(result.error?.includes('exceeds maximum'), true);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('should accept timeout within limit', () => {
|
|
201
|
-
const strictValidator = createStrictValidator([]);
|
|
202
|
-
const result = strictValidator.validateImageTimeout(30000); // 30 seconds
|
|
203
|
-
strictEqual(result.valid, true);
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
describe('Dimensions validation', () => {
|
|
208
|
-
const validator = createDefaultValidator();
|
|
209
|
-
|
|
210
|
-
it('should accept valid dimensions', () => {
|
|
211
|
-
const result = validator.validateDimensions(800, 600);
|
|
212
|
-
strictEqual(result.valid, true);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it('should reject zero dimensions', () => {
|
|
216
|
-
const result = validator.validateDimensions(0, 600);
|
|
217
|
-
strictEqual(result.valid, false);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it('should reject negative dimensions', () => {
|
|
221
|
-
const result = validator.validateDimensions(800, -100);
|
|
222
|
-
strictEqual(result.valid, false);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('should reject NaN dimensions', () => {
|
|
226
|
-
const result = validator.validateDimensions(NaN, 600);
|
|
227
|
-
strictEqual(result.valid, false);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('should reject non-number dimensions', () => {
|
|
231
|
-
const result = validator.validateDimensions('800' as any, 600);
|
|
232
|
-
strictEqual(result.valid, false);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('should reject dimensions exceeding maximum', () => {
|
|
236
|
-
const result = validator.validateDimensions(40000, 600);
|
|
237
|
-
strictEqual(result.valid, false);
|
|
238
|
-
strictEqual(result.error?.includes('exceed maximum'), true);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('should accept dimensions at the limit', () => {
|
|
242
|
-
const result = validator.validateDimensions(32767, 32767);
|
|
243
|
-
strictEqual(result.valid, true);
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
describe('Scale validation', () => {
|
|
248
|
-
const validator = createDefaultValidator();
|
|
249
|
-
|
|
250
|
-
it('should accept valid scale', () => {
|
|
251
|
-
const result = validator.validateScale(2);
|
|
252
|
-
strictEqual(result.valid, true);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('should accept fractional scale', () => {
|
|
256
|
-
const result = validator.validateScale(0.5);
|
|
257
|
-
strictEqual(result.valid, true);
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it('should reject zero scale', () => {
|
|
261
|
-
const result = validator.validateScale(0);
|
|
262
|
-
strictEqual(result.valid, false);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should reject negative scale', () => {
|
|
266
|
-
const result = validator.validateScale(-2);
|
|
267
|
-
strictEqual(result.valid, false);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('should reject too large scale', () => {
|
|
271
|
-
const result = validator.validateScale(20);
|
|
272
|
-
strictEqual(result.valid, false);
|
|
273
|
-
strictEqual(result.error?.includes('too large'), true);
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
it('should reject NaN scale', () => {
|
|
277
|
-
const result = validator.validateScale(NaN);
|
|
278
|
-
strictEqual(result.valid, false);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
describe('Element validation', () => {
|
|
283
|
-
const validator = createDefaultValidator();
|
|
284
|
-
|
|
285
|
-
it('should reject null element', () => {
|
|
286
|
-
const result = validator.validateElement(null);
|
|
287
|
-
strictEqual(result.valid, false);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it('should reject undefined element', () => {
|
|
291
|
-
const result = validator.validateElement(undefined);
|
|
292
|
-
strictEqual(result.valid, false);
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('should reject non-object element', () => {
|
|
296
|
-
const result = validator.validateElement('not an element' as any);
|
|
297
|
-
strictEqual(result.valid, false);
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
// Note: Full HTMLElement testing requires DOM environment (jsdom/browser)
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
describe('Options validation', () => {
|
|
304
|
-
const validator = createDefaultValidator();
|
|
305
|
-
|
|
306
|
-
it('should accept valid options', () => {
|
|
307
|
-
const options = {
|
|
308
|
-
scale: 2,
|
|
309
|
-
width: 800,
|
|
310
|
-
height: 600,
|
|
311
|
-
imageTimeout: 15000
|
|
312
|
-
};
|
|
313
|
-
const result = validator.validateOptions(options);
|
|
314
|
-
strictEqual(result.valid, true);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it('should collect multiple errors', () => {
|
|
318
|
-
const options = {
|
|
319
|
-
scale: -1,
|
|
320
|
-
width: -800,
|
|
321
|
-
imageTimeout: -5000
|
|
322
|
-
};
|
|
323
|
-
const result = validator.validateOptions(options);
|
|
324
|
-
strictEqual(result.valid, false);
|
|
325
|
-
// Should contain multiple error messages
|
|
326
|
-
strictEqual(result.error?.includes('Scale'), true);
|
|
327
|
-
strictEqual(result.error?.includes('Dimensions'), true);
|
|
328
|
-
strictEqual(result.error?.includes('timeout'), true);
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it('should allow missing optional fields', () => {
|
|
332
|
-
const options = {};
|
|
333
|
-
const result = validator.validateOptions(options);
|
|
334
|
-
strictEqual(result.valid, true);
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe('Strict validator', () => {
|
|
339
|
-
const strictValidator = createStrictValidator(['trusted.com']);
|
|
340
|
-
|
|
341
|
-
it('should reject data URLs in strict mode', () => {
|
|
342
|
-
// Note: This would need implementation in createStrictValidator
|
|
343
|
-
// Currently it doesn't disable data URLs
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
it('should enforce shorter timeout in strict mode', () => {
|
|
347
|
-
const result = strictValidator.validateImageTimeout(120000);
|
|
348
|
-
strictEqual(result.valid, false);
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it('should enforce proxy whitelist in strict mode', () => {
|
|
352
|
-
const allowed = strictValidator.validateUrl('https://trusted.com/proxy', 'proxy');
|
|
353
|
-
strictEqual(allowed.valid, true);
|
|
354
|
-
|
|
355
|
-
const denied = strictValidator.validateUrl('https://untrusted.com/proxy', 'proxy');
|
|
356
|
-
strictEqual(denied.valid, false);
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
});
|
package/src/core/bitwise.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const contains = (bit: number, value: number): boolean => (bit & value) !== 0;
|