From 1d6caba6b57f18d9d6ccb15df35a8772898f1dde Mon Sep 17 00:00:00 2001 From: LavrovArtem Date: Mon, 4 Sep 2017 11:45:19 +0300 Subject: [PATCH] fix `The document.open function throws an error because document.defaultView returns null` (close #1272) (#1279) * fix `The document.open function throws an error because document.defaultView returns null` (close #1272) * test refactoring * fix review's issues * fix review's issues --- src/client/sandbox/node/document/index.js | 11 ++-- .../fixtures/sandbox/node/document-test.js | 55 +++++++++++++++---- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/client/sandbox/node/document/index.js b/src/client/sandbox/node/document/index.js index 7dcf1a09d3..961fbaa3e3 100644 --- a/src/client/sandbox/node/document/index.js +++ b/src/client/sandbox/node/document/index.js @@ -17,11 +17,10 @@ export default class DocumentSandbox extends SandboxBase { this.documentWriter = null; } - _isUninitializedIframeWithoutSrc (doc) { - const wnd = doc.defaultView; - const frameElement = getFrameElement(wnd); + _isUninitializedIframeWithoutSrc (win) { + const frameElement = getFrameElement(win); - return wnd !== wnd.top && frameElement && isIframeWithoutSrc(frameElement) && + return win !== win.top && frameElement && isIframeWithoutSrc(frameElement) && !IframeSandbox.isIframeInitialized(frameElement); } @@ -69,7 +68,7 @@ export default class DocumentSandbox extends SandboxBase { const documentSandbox = this; document.open = (...args) => { - const isUninitializedIframe = this._isUninitializedIframeWithoutSrc(document); + const isUninitializedIframe = this._isUninitializedIframeWithoutSrc(window); if (!isUninitializedIframe) this._beforeDocumentCleaned(); @@ -99,7 +98,7 @@ export default class DocumentSandbox extends SandboxBase { const result = nativeMethods.documentClose.apply(document, args); - if (!this._isUninitializedIframeWithoutSrc(document)) + if (!this._isUninitializedIframeWithoutSrc(window)) this._onDocumentClosed(); return result; diff --git a/test/client/fixtures/sandbox/node/document-test.js b/test/client/fixtures/sandbox/node/document-test.js index 174aaac13d..559049ed56 100644 --- a/test/client/fixtures/sandbox/node/document-test.js +++ b/test/client/fixtures/sandbox/node/document-test.js @@ -4,6 +4,7 @@ var SHADOW_UI_CLASSNAME = hammerhead.get('../shadow-ui/class-name'); var browserUtils = hammerhead.utils.browser; var nativeMethods = hammerhead.nativeMethods; var iframeSandbox = hammerhead.sandbox.iframe; +var Promise = hammerhead.Promise; QUnit.testStart(function () { // NOTE: The 'window.open' method used in QUnit. @@ -494,22 +495,56 @@ if (!browserUtils.isIE) { } test('an iframe should not contain self-removing scripts after document.close (GH-871)', function () { - var iframe = document.createElement('iframe'); + return createTestIframe() + .then(function (iframe) { + var iframeDocument = iframe.contentDocument; - iframe.id = 'test-gh-871'; + iframeDocument.designMode = 'On'; + iframeDocument.open(); + iframeDocument.write(''); + iframeDocument.close(); - document.body.appendChild(iframe); + var selfRemovingScripts = nativeMethods.querySelectorAll.call(iframeDocument, + '.' + SHADOW_UI_CLASSNAME.selfRemovingScript); + + strictEqual(selfRemovingScripts.length, 0); + }); +}); - var iframeDocument = iframe.contentDocument; +test('should not throw an error when document.defualtView is null (GH-1272)', function () { + return new Promise(function (resolve, reject) { + var iframe = document.createElement('iframe'); + var loadEventCount = 0; - iframeDocument.designMode = 'on'; - iframeDocument.open(); - iframeDocument.write(''); - iframeDocument.close(); + iframe.id = 'test' + Date.now(); + iframe.src = 'javascript:"";'; + iframe.onload = function () { + var doc = iframe.contentDocument; - strictEqual(nativeMethods.querySelectorAll.call(document, '.' + SHADOW_UI_CLASSNAME.selfRemovingScript).length, 0); + // NOTE: Without wrapping in 'setTimeout' function the error is not reproduced + setTimeout(function () { + try { + // NOTE: Chrome throw an error after second load + if (loadEventCount++ < 2) { + doc.open(); + doc.write('
' + loadEventCount + '
'); + doc.close(); + } + else + resolve(iframe); + } + catch (e) { + reject(e); + } + }, 100); + }; - iframe.parentNode.removeChild(iframe); + document.body.appendChild(iframe); + }) + .then(function (iframe) { + strictEqual(iframe.contentDocument.documentElement.innerText, '2'); + document.body.removeChild(iframe); + }); }); test('querySelector should return an element if a selector contains the href attribute with hash as a value (GH-922)', function () {