Skip to content

Commit 1826400

Browse files
committed
Defer clean up of temporary iframe and fix #219
Chrome runs into errors if the iframe is removed from the current document while we continue to operate on style sheet properties. Error was: Uncaught (in promise) TypeError: Cannot read properties of null (reading 'cssRules') at documentUtil.js:89:60 at Array.forEach (<anonymous>) at replaceSimpleSelectorsBy (documentUtil.js:80:52) at Object.module.lowercaseCssTypeSelectors (documentUtil.js:131:9) at Object.module.rewriteTagNameSelectorsToLowerCase (documentHelper.js:68:22) at Object.module.getSvgForDocument (document2svg.js:107:24) at document2svg.js:122:31
1 parent 9461b63 commit 1826400

File tree

4 files changed

+80
-13
lines changed

4 files changed

+80
-13
lines changed

src/browser.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,19 @@ var browser = (function (util, proxies, sanedomparsererror, theWindow) {
3939
iframeErrorsMessages = [],
4040
executeJsTimeout = options.executeJsTimeout || 0;
4141

42-
var doResolve = function () {
43-
var doc = iframe.contentDocument;
42+
var cleanUp = function () {
43+
// We have to defer removing the iframe from the current document, see https://github.com/cburgmer/rasterizeHTML.js/issues/219
4444
theWindow.document
4545
.getElementsByTagName("body")[0]
4646
.removeChild(iframe);
47+
};
48+
49+
var doResolve = function () {
50+
var doc = iframe.contentDocument;
4751
resolve({
4852
document: doc,
4953
errors: iframeErrorsMessages,
54+
cleanUp: cleanUp,
5055
});
5156
};
5257

src/rasterize.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ var rasterize = (function (
6363
return {
6464
document: document,
6565
errors: result.errors,
66+
cleanUp: result.cleanUp,
6667
};
6768
});
6869
};
@@ -82,20 +83,24 @@ var rasterize = (function (
8283
return {
8384
element: result.document.documentElement,
8485
errors: errors.concat(result.errors),
86+
cleanUp: result.cleanUp,
8587
};
8688
}
8789
);
8890
} else {
8991
return {
9092
element: element,
9193
errors: errors,
94+
cleanUp: function () {},
9295
};
9396
}
9497
})
9598
.then(function (result) {
9699
return doDraw(result.element, canvas, options).then(function (
97100
drawResult
98101
) {
102+
result.cleanUp();
103+
99104
return {
100105
image: drawResult.image,
101106
svg: drawResult.svg,

test/specs/browser.test.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ describe("Browser functions", function () {
7272
"dynamic content"
7373
);
7474

75+
result.cleanUp();
7576
done();
7677
});
7778
});
@@ -84,7 +85,8 @@ describe("Browser functions", function () {
8485
doc.documentElement,
8586
defaultOptionsWithViewport()
8687
)
87-
.then(function () {
88+
.then(function (result) {
89+
result.cleanUp();
8890
expect(document.querySelector("iframe")).toBe(null);
8991

9092
done();
@@ -105,6 +107,7 @@ describe("Browser functions", function () {
105107
"dynamic content"
106108
);
107109

110+
result.cleanUp();
108111
done();
109112
});
110113
});
@@ -120,7 +123,10 @@ describe("Browser functions", function () {
120123
doc.documentElement,
121124
defaultOptionsWithTimeout(10)
122125
)
123-
.then(callback);
126+
.then(function (result) {
127+
result.cleanUp();
128+
callback();
129+
});
124130

125131
// HACK fragile test. We need to wait for the iframe.onload to be triggered
126132
setTimeout(function () {
@@ -145,7 +151,10 @@ describe("Browser functions", function () {
145151
doc.documentElement,
146152
defaultOptionsWithViewport()
147153
)
148-
.then(callback);
154+
.then(function (result) {
155+
result.cleanUp();
156+
callback();
157+
});
149158

150159
// HACK fragile test. We need to wait for the iframe.onload to be triggered
151160
setTimeout(function () {
@@ -171,6 +180,7 @@ describe("Browser functions", function () {
171180
.then(function (result) {
172181
expect(result.document.body.innerHTML).toEqual("20");
173182

183+
result.cleanUp();
174184
done();
175185
});
176186
});
@@ -195,6 +205,7 @@ describe("Browser functions", function () {
195205
/(ReferenceError:\s+(.+\s+)?undefinedVar)|('undefinedVar' is undefined)/
196206
);
197207

208+
result.cleanUp();
198209
done();
199210
});
200211
});
@@ -212,6 +223,7 @@ describe("Browser functions", function () {
212223
.then(function (result) {
213224
expect(result.document.body.innerHTML).toEqual("1");
214225

226+
result.cleanUp();
215227
done();
216228
});
217229
});
@@ -234,6 +246,7 @@ describe("Browser functions", function () {
234246
.textContent.trim()
235247
).toEqual("The content");
236248

249+
result.cleanUp();
237250
done();
238251
});
239252
});
@@ -251,6 +264,7 @@ describe("Browser functions", function () {
251264
.then(function (result) {
252265
expect(result.document.body.innerHTML).toEqual("true");
253266

267+
result.cleanUp();
254268
done();
255269
});
256270
});
@@ -267,6 +281,7 @@ describe("Browser functions", function () {
267281
.then(function (result) {
268282
expect(result.document.body.innerHTML).toEqual("true");
269283

284+
result.cleanUp();
270285
done();
271286
});
272287
});
@@ -283,6 +298,7 @@ describe("Browser functions", function () {
283298
.then(function (result) {
284299
expect(result.document.body.innerHTML).toEqual("true");
285300

301+
result.cleanUp();
286302
done();
287303
});
288304
});
@@ -296,6 +312,7 @@ describe("Browser functions", function () {
296312
.then(function (result) {
297313
expect(result.document.doctype.name).toEqual("html");
298314

315+
result.cleanUp();
299316
done();
300317
});
301318
});

test/specs/rasterize.test.js

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ describe("Rasterize", function () {
4949

5050
beforeEach(function () {
5151
doc = document.implementation.createHTMLDocument("");
52-
53-
spyOn(document2svg, "drawDocumentAsSvg");
54-
spyOn(browser, "loadDocument");
55-
spyOn(svg2image, "renderSvg");
5652
});
5753

5854
describe("Rendering", function () {
5955
var callback;
6056

6157
beforeEach(function () {
58+
spyOn(document2svg, "drawDocumentAsSvg");
59+
spyOn(browser, "loadDocument");
60+
spyOn(svg2image, "renderSvg");
61+
6262
callback = jasmine.createSpy("drawCallback");
6363

6464
inlineReferences = spyOn(
@@ -195,7 +195,13 @@ describe("Rasterize", function () {
195195
var executeJavascript = spyOn(
196196
browser,
197197
"executeJavascript"
198-
).and.returnValue(Promise.resolve({ document: doc, errors: [] }));
198+
).and.returnValue(
199+
Promise.resolve({
200+
document: doc,
201+
errors: [],
202+
cleanUp: function () {},
203+
})
204+
);
199205

200206
rasterize
201207
.rasterize(doc.documentElement, null, {
@@ -218,7 +224,11 @@ describe("Rasterize", function () {
218224

219225
it("should inline scripts when executing JavaScript", function (done) {
220226
spyOn(browser, "executeJavascript").and.returnValue(
221-
Promise.resolve({ document: doc, errors: [] })
227+
Promise.resolve({
228+
document: doc,
229+
errors: [],
230+
cleanUp: function () {},
231+
})
222232
);
223233

224234
rasterize
@@ -237,7 +247,13 @@ describe("Rasterize", function () {
237247
var executeJavascript = spyOn(
238248
browser,
239249
"executeJavascript"
240-
).and.returnValue(Promise.resolve({ document: doc, errors: [] }));
250+
).and.returnValue(
251+
Promise.resolve({
252+
document: doc,
253+
errors: [],
254+
cleanUp: function () {},
255+
})
256+
);
241257

242258
rasterize
243259
.rasterize(doc.documentElement, null, {
@@ -259,6 +275,10 @@ describe("Rasterize", function () {
259275
var callback;
260276

261277
beforeEach(function () {
278+
spyOn(document2svg, "drawDocumentAsSvg");
279+
spyOn(browser, "loadDocument");
280+
spyOn(svg2image, "renderSvg");
281+
262282
callback = jasmine.createSpy("drawCallback");
263283

264284
spyOn(documentHelper, "persistInputValues");
@@ -290,7 +310,11 @@ describe("Rasterize", function () {
290310
withoutErrors()
291311
);
292312
spyOn(browser, "executeJavascript").and.returnValue(
293-
Promise.resolve({ document: doc, errors: ["the error"] })
313+
Promise.resolve({
314+
document: doc,
315+
errors: ["the error"],
316+
cleanUp: function () {},
317+
})
294318
);
295319
setUpDrawDocumentAsSvg(theSvg);
296320
setUpRenderSvg(rasterizedImage);
@@ -312,6 +336,10 @@ describe("Rasterize", function () {
312336
var callback, executeJavascript;
313337

314338
beforeEach(function () {
339+
spyOn(document2svg, "drawDocumentAsSvg");
340+
spyOn(browser, "loadDocument");
341+
spyOn(svg2image, "renderSvg");
342+
315343
callback = jasmine.createSpy("drawCallback");
316344

317345
inlineReferences = spyOn(
@@ -378,4 +406,16 @@ describe("Rasterize", function () {
378406
});
379407
});
380408
});
409+
410+
describe("rasterize integration", function () {
411+
it("should clean up the iframe when executing JavaScript", function (done) {
412+
rasterize
413+
.rasterize(doc.documentElement, undefined, { executeJs: true })
414+
.then(function () {
415+
expect(document.querySelector("iframe")).toBe(null);
416+
417+
done();
418+
});
419+
});
420+
});
381421
});

0 commit comments

Comments
 (0)