summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/webappapis/dynamic-markup-insertion')
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html67
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html12
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html13
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js3
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html16
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html16
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html13
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html16
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html16
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html17
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html11
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html25
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js28
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html27
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js24
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html23
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html25
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js3
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html17
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html21
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html23
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html29
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html27
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html28
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html26
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html30
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html29
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html27
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html11
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html24
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html2
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html24
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html35
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html27
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html35
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html54
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html42
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html77
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html25
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html6
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js3
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js36
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html71
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html27
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html55
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html12
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html17
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html41
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html15
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js119
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js69
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js69
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js179
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js104
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js31
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js98
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js117
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js26
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js14
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js127
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js39
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html17
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html27
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html10
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js12
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js308
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html61
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js29
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js29
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js60
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html31
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js22
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js57
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html26
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html24
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js74
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js25
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js71
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js65
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html7
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html13
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml11
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml11
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js8
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html2
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html3
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py5
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py3
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py8
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html3
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html9
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js106
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt1
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js23
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js20
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js19
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js13
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js18
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js26
-rw-r--r--testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js93
224 files changed, 5252 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html
new file mode 100644
index 0000000000..1584ca5f97
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document-close-with-pending-script.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>document.close called while a script is pending</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<body>
+ <script>
+ window.t = async_test();
+ // We want start a document load, create an non-blocking script load inside
+ // it, have the parser complete, then call document.open()/document.close()
+ // after the parser is done but before the non-blocking script load
+ // completes. After we do that, the document should reach the 'complete'
+ // ready state and the iframe's load event should fire.
+ var loadFired = false;
+ var i;
+
+ var finish = t.step_func_done(() => {
+ assert_equals(loadFired, true, "Should have fired a load event");
+ assert_equals(i.contentDocument.readyState, "complete",
+ "Should be fully loaded");
+ });
+
+ var checkForLoad = t.step_func(() => {
+ if (loadFired) {
+ finish();
+ } else {
+ i.addEventListener("load", finish);
+ }
+ });
+
+ window.parserDone = t.step_func(() => {
+ var doc = i.contentDocument;
+ i.onload = () => { loadFired = true; }
+ doc.open();
+ doc.close();
+ // It's not very clearly specced whether the document is
+ // supposed to be fully loaded at this point or not, so allow
+ // that to be the case, or to happen soonish.
+ assert_true(doc.readyState == "interactive" ||
+ doc.readyState == "complete", "Should be almost loaded");
+ if (doc.readyState == "complete") {
+ checkForLoad();
+ } else {
+ doc.addEventListener("readystatechange", checkForLoad);
+ }
+ });
+
+ t.step(() => {
+ i = document.createElement("iframe");
+ i.srcdoc = `
+ <script>
+ parent.t.step(() => {
+ var s = document.createElement("script");
+ s.src = "/common/slow.py";
+ document.documentElement.appendChild(s);
+ // Call into the parent async, so we finish our "end of parse"
+ // work before it runs.
+ document.addEventListener(
+ "DOMContentLoaded",
+ () => parent.t.step_timeout(parent.parserDone, 0));
+ });
+ <\/script>
+ `;
+ document.body.appendChild(i);
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml
new file mode 100644
index 0000000000..164d71d191
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/document.close-01.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>document.close in XHTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#closing-the-input-stream"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ document.close();
+ }, "document.close in XHTML should throw an INVALID_STATE_ERR ");
+}, "document.close in XHTML");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js
new file mode 100644
index 0000000000..d5c8469baf
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/load-event-after-location-set-during-write.window.js
@@ -0,0 +1,19 @@
+// Make sure that the load event for an iframe doesn't fire at the
+// point when a navigation triggered by document.write() starts in it,
+// but rather when that navigation completes.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ const doc = frame.contentDocument;
+ const url = URL.createObjectURL(new Blob(["PASS"], { type: "text/html"}));
+
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentDocument.body.textContent, "PASS",
+ "Why is our load event firing before the new document loaded?");
+ });
+
+ doc.open();
+ doc.write(`FAIL<script>location = "${url}"</` + "script>");
+ doc.close();
+}, "Setting location from document.write() call should not trigger load event until that load completes");
+
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html
new file mode 100644
index 0000000000..3ac6423f4a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/001.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("PASS");
+ assert_equals(document.body.textContent, "PASS");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html
new file mode 100644
index 0000000000..08975bca7b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/002.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html
new file mode 100644
index 0000000000..915e1f6d61
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/003.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<");
+ document.write("i>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html
new file mode 100644
index 0000000000..dd01725860
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/004.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i");
+ document.write(">Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html
new file mode 100644
index 0000000000..4c161c4d47
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i>");
+ document.write("Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js
new file mode 100644
index 0000000000..ebfd7e2585
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/005.js
@@ -0,0 +1 @@
+order.push(3); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html
new file mode 100644
index 0000000000..92bfb44c3a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id='test'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js
new file mode 100644
index 0000000000..ebfd7e2585
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/006.js
@@ -0,0 +1 @@
+order.push(3); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html
new file mode 100644
index 0000000000..753316b89c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i ");
+ document.write("id='test'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js
new file mode 100644
index 0000000000..31fcf18d49
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/007.js
@@ -0,0 +1,4 @@
+t.step(function() {
+ order.push(2);
+ document.write("<script>t.step(function() {order.push(3)})</script>");
+ }); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js
new file mode 100644
index 0000000000..ef90c722b7
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008-1.js
@@ -0,0 +1,3 @@
+t.step(function() {
+ order.push(3);
+ }); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html
new file mode 100644
index 0000000000..4818bc388f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i i");
+ document.write("d='test'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js
new file mode 100644
index 0000000000..367597515d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/008.js
@@ -0,0 +1,4 @@
+t.step(function() {
+ order.push(2);
+ document.write("<script src=\"008-1.js\"></script>");
+ }); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html
new file mode 100644
index 0000000000..d7b78333b8
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/009.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id");
+ document.write("='test'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js
new file mode 100644
index 0000000000..fd815bab77
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010-1.js
@@ -0,0 +1,4 @@
+t.step(function() {
+ order.push(4);
+ assert_equals(document.getElementsByTagName("meta").length, 1);
+ }); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html
new file mode 100644
index 0000000000..c8b9958258
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id=");
+ document.write("'test'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js
new file mode 100644
index 0000000000..bb328ad55a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/010.js
@@ -0,0 +1,4 @@
+t.step(function() {
+ order.push(3);
+ assert_equals(document.getElementsByTagName("meta").length, 0);
+ });
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js
new file mode 100644
index 0000000000..944b70d2d0
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011-1.js
@@ -0,0 +1,5 @@
+t.step(function() {
+ order.push(4);
+ document.write("<meta>");
+ assert_equals(document.getElementsByTagName("meta").length, 1);
+ }); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html
new file mode 100644
index 0000000000..33464429e6
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id='");
+ document.write("test'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js
new file mode 100644
index 0000000000..ce47bcd283
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/011.js
@@ -0,0 +1,5 @@
+t.step(function() {
+ order.push(3);
+ document.write("<script src='011-1.js'></script" + "><meta>");
+ assert_equals(document.getElementsByTagName("meta").length, 0);
+ }); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html
new file mode 100644
index 0000000000..c9902a4875
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id='te");
+ document.write("st'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js
new file mode 100644
index 0000000000..7ab4c6b386
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/012.js
@@ -0,0 +1,5 @@
+t.step(
+function() {
+ order.push(5);
+ assert_equals(document.getElementsByTagName("meta").length, 0);
+}); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html
new file mode 100644
index 0000000000..7b87d28976
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id='test");
+ document.write("'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js
new file mode 100644
index 0000000000..b5ce5f27da
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/013.js
@@ -0,0 +1 @@
+document.write('<svg><![CDATA['); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html
new file mode 100644
index 0000000000..75518a8981
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/014.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id='test'");
+ document.write(">Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html
new file mode 100644
index 0000000000..3dd79a63ef
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/015.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i id='test'");
+ document.write("class='a'>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute("id"), "test");
+ assert_equals(document.body.firstChild.getAttribute("class"), "a");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html
new file mode 100644
index 0000000000..4c2f58912a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/016.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<i>Filler Text");
+ document.write("</i><b>Filler Text");
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+ assert_equals(document.body.childNodes[1].localName, "b");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html
new file mode 100644
index 0000000000..8d1b24b06e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/017.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ var s = "<i id=test>Filler Text</i><b>Filler Text"
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+ assert_equals(document.body.firstChild.localName, "i");
+ assert_equals(document.body.firstChild.getAttribute('id'), "test");
+ assert_equals(document.body.firstChild.textContent, "Filler Text");
+ assert_equals(document.body.childNodes[1].localName, "b");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html
new file mode 100644
index 0000000000..cf8dddbc54
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/018.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+function() {
+ document.write("<body>");
+ var s = "<!--comment--><i>Filler Text</i>"
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+ assert_equals(document.body.firstChild.nodeType, document.COMMENT_NODE);
+ assert_equals(document.body.firstChild.data, "comment");
+ assert_equals(document.body.childNodes[1].localName, "i");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html
new file mode 100644
index 0000000000..5e988f79ef
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/019.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<i");
+});
+</script>
+>Filler Text</i>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "i");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html
new file mode 100644
index 0000000000..1d31bbf35d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/020.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><");
+});
+</script>!--comment-->
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].nodeType, document.COMMENT_NODE);
+ assert_equals(document.body.childNodes[0].data, "comment");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html
new file mode 100644
index 0000000000..500bb19398
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/021.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><sp");
+});
+</script>an>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html
new file mode 100644
index 0000000000..53ba299012
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/022.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span>");
+});
+</script>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html
new file mode 100644
index 0000000000..ca89e0e0bc
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/023.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span ");
+});
+</script>id=a>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html
new file mode 100644
index 0000000000..2a47d76cb3
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/024.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span i");
+});
+</script>d=a>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html
new file mode 100644
index 0000000000..31c68cf7df
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/025.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id");
+});
+</script>=a>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html
new file mode 100644
index 0000000000..a9bce7743e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/026.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id=");
+});
+</script>a>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html
new file mode 100644
index 0000000000..dcfd67c0f7
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/027.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id=a");
+});
+</script>>Filler Text</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html
new file mode 100644
index 0000000000..f5b7e9ef2b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/028.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id=a>Filler Text<");
+});
+</script>/span><b>Filler Text</b></span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+ assert_equals(document.body.childNodes[1].localName, "b");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html
new file mode 100644
index 0000000000..f005a72227
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/029.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id=a>Filler Text</");
+});
+</script>span><b>Filler Text</b></span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+ assert_equals(document.body.childNodes[1].localName, "b");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html
new file mode 100644
index 0000000000..cc361d3aaf
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/030.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id=a>Filler Text</sp");
+});
+</script>an><b>Filler Text</b></span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+ assert_equals(document.body.childNodes[1].localName, "b");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html
new file mode 100644
index 0000000000..32c97c5056
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/031.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span id=a>Filler Text</span");
+});
+</script>><b>Filler Text</b></span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "span");
+ assert_equals(document.body.childNodes[0].getAttribute("id"), "a");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+ assert_equals(document.body.childNodes[1].localName, "b");
+ assert_equals(document.body.childNodes[1].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html
new file mode 100644
index 0000000000..1a33408f1b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/032.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var tag_name_length = 100000;
+ var tag_name = "";
+ for (var i=0; i<tag_name_length; i++) {
+ tag_name += "a";
+ }
+ document.write("<body><" + tag_name + ">Filler Text</" + tag_name + ">");
+});
+</script>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html
new file mode 100644
index 0000000000..1b8e1c2706
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/033.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+test(
+ function() {
+ document.writeln("<i");
+ var s = " b='a'>Filler"
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]+"\n");
+ }
+ document.writeln("</i");
+ document.writeln(">");
+ assert_equals(document.body.childNodes[0].localName, "i");
+ assert_equals(document.body.childNodes[0].getAttribute("b"), "\na\n");
+ assert_equals(document.body.childNodes[0].textContent, "\nF\ni\nl\nl\ne\nr\n");
+ }
+);
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html
new file mode 100644
index 0000000000..abd481a64d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/034.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<svg><![CDATA[Filler Text]]></svg>";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "svg");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html
new file mode 100644
index 0000000000..a1e7f9ee67
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/035.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<svg><!";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script>[CDATA[Filler Text]]></svg>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "svg");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html
new file mode 100644
index 0000000000..8719e0598d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/036.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<svg><![CDATA[Filler Text]";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script>]></svg>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "svg");
+ assert_equals(document.body.childNodes[0].textContent, "Filler Text");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html
new file mode 100644
index 0000000000..cf0787ce76
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/037.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<body><!DOCTYPE html>";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script><script>
+t.step(function() {
+ //Nothing should be inserted into the DOM for the doctype node so
+ //just checking nothing odd happens
+ assert_equals(document.body.childNodes[0].localName, "script");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html
new file mode 100644
index 0000000000..4ae9d32b23
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/038.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<body><";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script>!DOCTYPE html><script>
+t.step(function() {
+ //Nothing should be inserted into the DOM for the doctype node so
+ //just checking nothing odd happens
+ assert_equals(document.body.childNodes[0].localName, "script");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html
new file mode 100644
index 0000000000..611a01390c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/039.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<body><!";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script>DOCTYPE html><script>
+t.step(function() {
+ //Nothing should be inserted into the DOM for the doctype node so
+ //just checking nothing odd happens
+ assert_equals(document.body.childNodes[0].localName, "script");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html
new file mode 100644
index 0000000000..d76deffa40
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/040.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>document.write entity</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = test(function() {
+ document.write("<body><span>&notin;abc");
+ assert_equals(document.body.childNodes[0].textContent, "\u2209abc");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html
new file mode 100644
index 0000000000..592711c94f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/041.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>document.write entity</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = test(function() {
+ var s = "<body><span>&notin;abc";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+ assert_equals(document.body.childNodes[0].textContent, "\u2209abc");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html
new file mode 100644
index 0000000000..e15f1d0c0f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/042.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>document.write entity</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span>&not");
+});
+</script>in;abc</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].textContent, "\u2209abc");
+})
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html
new file mode 100644
index 0000000000..4058e7a823
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/043.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>document.write entity</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><span>&");
+});
+</script>notabc</span>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].textContent, "\u00ACabc");
+})
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html
new file mode 100644
index 0000000000..4c9f50273c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/044.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<body><textarea><span>Filler</span></textarea>");
+});
+</script>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "textarea");
+ assert_equals(document.body.childNodes[0].textContent, "<span>Filler</span>");
+})
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html
new file mode 100644
index 0000000000..987eabf0f4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/045.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<body><textarea><span>Filler</span></textarea>";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "textarea");
+ assert_equals(document.body.childNodes[0].textContent, "<span>Filler</span>");
+})
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html
new file mode 100644
index 0000000000..e87e9cc825
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/046.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<body><textarea>";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script><span>Filler</span></textarea>
+<script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].localName, "textarea");
+ assert_equals(document.body.childNodes[0].textContent, "<span>Filler</span>");
+})
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html
new file mode 100644
index 0000000000..6a43faec51
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047-1.html
@@ -0,0 +1,7 @@
+<script>
+onload = opener.t.step_func_done(function() {
+ document.write("<body>Filler Text<div id='log'></div>");
+ opener.assert_equals(document.body.textContent, "Filler Text");
+});
+</script>
+<body>FAIL
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html
new file mode 100644
index 0000000000..677d3e1786
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/047.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+var win;
+var t = async_test(() => {
+ win = window.open("047-1.html");
+});
+t.add_cleanup(() => win.close());
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html
new file mode 100644
index 0000000000..0ec282f2bc
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/049.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>document.write plaintext</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<div id="log"></div><script>
+test(function() {
+ var s = "<table><tr><td>Text</tr><plaintext><tr><td>Filler ";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+ document.close();
+ assert_equals(document.body.childNodes[2].nodeType, document.ELEMENT_NODE);
+ assert_equals(document.body.childNodes[2].localName, "plaintext");
+ assert_equals(document.body.childNodes[2].textContent, "<tr><td>Filler ");
+ assert_equals(document.body.childNodes[3].nodeType, document.ELEMENT_NODE);
+ assert_equals(document.body.childNodes[3].localName, "table");
+ assert_equals(document.body.childNodes[3].textContent, "Text");
+});
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html
new file mode 100644
index 0000000000..0a37fa4c5f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/050.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>document.write plaintext</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<div id="log"></div><script>
+var t = async_test();
+
+t.step(function() {
+ document.write("<plaintext>");
+ assert_equals(document.body.childNodes[2].nodeType, document.ELEMENT_NODE);
+ assert_equals(document.body.childNodes[2].localName, "plaintext");
+ var s = "Filler ";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ assert_equals(document.body.childNodes[2].textContent, s.slice(0,i+1));
+ }
+ document.close();
+});
+
+onload = function() {
+ t.step(function() {
+ assert_equals(document.body.childNodes[2].textContent, "Filler Text\n");
+ });
+ t.done();
+}
+</script>Text
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html
new file mode 100644
index 0000000000..80ea279dad
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/051.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write \r\n</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="log"></div>
+
+<script>
+var t = async_test();
+
+t.step(function() {
+ document.write("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nA");
+})
+
+onload = function() {
+ t.step(function() {
+ const lastNode = document.getElementById('after');
+ assert_equals(lastNode.previousSibling.data, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nAB");
+ });
+ t.done();
+};
+</script>B<div id=after></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js
new file mode 100644
index 0000000000..5a91203874
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/contentType.window.js
@@ -0,0 +1,28 @@
+// META: script=/common/media.js
+
+const videoURL = getVideoURI("/images/pattern"),
+ videoMIMEType = getMediaContentType(videoURL);
+
+[
+ [videoURL, videoMIMEType, "video"],
+ ["/images/red.png", "image/png", "image"],
+ ["/common/text-plain.txt", "text/plain", "text"],
+ ["/common/blank.html", "text/html", "HTML"]
+].forEach(val => {
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.src = val[0];
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentDocument.contentType, val[1]);
+ frame.contentDocument.write("<b>Heya</b>");
+ assert_equals(frame.contentDocument.body.firstChild.localName, "b");
+ assert_equals(frame.contentDocument.body.firstChild.textContent, "Heya");
+ assert_equals(frame.contentDocument.contentType, val[1]);
+
+ // Make sure a load event is fired across browsers
+ // https://github.com/web-platform-tests/wpt/pull/10239
+ frame.contentDocument.close();
+ });
+ }, "document.write(): " + val[2] + " document");
+});
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml
new file mode 100644
index 0000000000..fc21d4e2bf
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-01.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>document.write in XHTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#document.write%28%29"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ document.write("Failure: document.write actually worked");
+ }, "document.write in XHTML should throw an INVALID_STATE_ERR ");
+}, "document.write in XHTML");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html
new file mode 100644
index 0000000000..4c25da8b68
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/document.write-02.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>document.write and null/undefined</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-write%28%29">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#documents-in-the-dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+ doc = iframe.contentDocument;
+ test(function() {
+ doc.open();
+ doc.write(null);
+ doc.close();
+ assert_equals(doc.documentElement.textContent, "null");
+ }, "document.write(null)");
+ test(function() {
+ doc.open();
+ doc.write(undefined);
+ doc.close();
+ assert_equals(doc.documentElement.textContent, "undefined");
+ }, "document.write(undefined)");
+}, "Calling document.write with null and undefined");
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js
new file mode 100644
index 0000000000..49d5051c25
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/during-readystatechange.window.js
@@ -0,0 +1,24 @@
+// This tests whether the insertion point gets reset before or after the readystatechange event.
+// See https://github.com/whatwg/html/pull/6613#discussion_r620171070.
+// Recall that resetting the insertion point means that document.write() performs the document open
+// steps and blows away previous content in the document.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { frame.remove(); });
+ frame.src = "../opening-the-input-stream/resources/dummy.html";
+ frame.onload = t.step_func_done(() => {
+ const states = [];
+ frame.contentDocument.onreadystatechange = t.step_func(() => {
+ if (frame.contentDocument.readyState === "interactive") {
+ assert_not_equals(frame.contentDocument.textContent, "", "Precondition check: dummy document is not empty");
+
+ frame.contentDocument.write("Some text");
+
+ // If the insertion point is reset before the readystatechange handler, then the
+ // document.write() call above will blow away the text originally in dummy.html, leaving only what we wrote.
+ assert_equals(frame.contentDocument.textContent, "Some text");
+ }
+ });
+ });
+}, "document.write() during readystatechange to interactive");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html
new file mode 100644
index 0000000000..0dc101b533
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/empty.html
@@ -0,0 +1 @@
+<html><body></body></html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html
new file mode 100644
index 0000000000..8b54560c6c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_001.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>document.write into iframe</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+test(
+function() {
+ var iframe = document.getElementById("test");
+ iframe.contentDocument.write("Filler Text");
+ iframe.contentDocument.close();
+ assert_equals(iframe.contentDocument.body.textContent, "Filler Text");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html
new file mode 100644
index 0000000000..f77819adb6
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_002.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write into iframe</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+test(
+function() {
+ var iframe = document.getElementById("test");
+ var s = "<i id='a'>Filler Text</i><b id=b>Filler Text</b>"
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s[i]);
+ }
+ iframe.contentDocument.close();
+ assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "Filler Text");
+ assert_equals(iframe.contentDocument.body.childNodes[0].localName, "i");
+ assert_equals(iframe.contentDocument.body.childNodes[0].getAttribute('id'), "a");
+ assert_equals(iframe.contentDocument.body.childNodes[1].textContent, "Filler Text");
+ assert_equals(iframe.contentDocument.body.childNodes[1].localName, "b");
+ assert_equals(iframe.contentDocument.body.childNodes[1].getAttribute('id'), "b");
+});
+</script>
+<div id="log"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html
new file mode 100644
index 0000000000..9865874da4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_003.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>document.write script into iframe</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+test(
+function() {
+ var iframe = document.getElementById("test");
+ var s = "<script>document.write(\"<i id='a'>Filler Text</i>\")</script" + "><b id=b>Filler Text</b>"
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s[i]);
+ }
+ iframe.contentDocument.close();
+ //Note: <script> ends up in <head>
+ assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "Filler Text");
+ assert_equals(iframe.contentDocument.body.childNodes[0].localName, "i");
+ assert_equals(iframe.contentDocument.body.childNodes[0].getAttribute('id'), "a");
+ assert_equals(iframe.contentDocument.body.childNodes[1].textContent, "Filler Text");
+ assert_equals(iframe.contentDocument.body.childNodes[1].localName, "b");
+ assert_equals(iframe.contentDocument.body.childNodes[1].getAttribute('id'), "b");
+});
+</script>
+<div id="log"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html
new file mode 100644
index 0000000000..a4d7b1ddad
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_004.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write script into iframe write back into parent</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+var t = async_test();
+var iframe = document.getElementById("test");
+var order = [];
+t.step(function() {
+ order.push(1);
+ var s = "<script>parent.order.push(2); parent.document.write('<script>order.push(3);</script'+'>'); parent.order.push(4)</script" + ">";
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s[i]);
+ }
+ iframe.contentDocument.close();
+ order.push(5);
+ assert_array_equals(order, [1,2,3,4,5])
+}
+);
+t.done();
+</script>
+<div id="log"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html
new file mode 100644
index 0000000000..7bc3ed6c29
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>document.write external script into iframe write back into parent</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+var t = async_test();
+var iframe = document.getElementById("test");
+var order = [];
+t.step(function() {
+ order.push(1);
+ var s = "<script src='iframe_005.js'></script" + ">";
+ iframe.contentDocument.write(s);
+ iframe.contentDocument.close();
+ order.push(2);
+ assert_array_equals(order, [1,2])
+}
+);
+addEventListener("load", function() {
+ t.step(function() {
+ assert_array_equals(order, [1,2,3,4,5])
+ });
+ t.done();
+}, false);
+</script>
+<div id="log"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js
new file mode 100644
index 0000000000..bf038f7004
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_005.js
@@ -0,0 +1,3 @@
+parent.order.push(3);
+document.write("<script>parent.order.push(4)</script>");
+parent.order.push(5); \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html
new file mode 100644
index 0000000000..d080ee3673
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_006.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write external script into iframe write back into parent</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+var t = async_test();
+var iframe = document.getElementById("test");
+var order = [];
+t.step(function() {
+ order.push(1);
+ var s = "<script>parent.order.push(2); parent.document.write('<script>order.push(3); iframe.contentDocument.write(\"<script>parent.order.push(4)</script\"+\">\");order.push(5);</script' + '>'); parent.order.push(6)</script"+">";
+ iframe.contentDocument.write(s);
+ iframe.contentDocument.close();
+ order.push(7);
+ assert_array_equals(order, [1,2,3,4,5,6,7]);
+});
+t.done();
+</script>
+<div id="log"></div> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html
new file mode 100644
index 0000000000..c00aa7062d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_007.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>document.write comment into iframe</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+test(function() {
+ var iframe = document.getElementById("test");
+ var s = "<!--Filler-->";
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s);
+ }
+ iframe.contentDocument.close();
+ assert_equals(iframe.contentDocument.childNodes[0].nodeType, document.COMMENT_NODE);
+ assert_equals(iframe.contentDocument.childNodes[0].data, "Filler");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html
new file mode 100644
index 0000000000..c814958d19
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_008.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>document.write plaintext into iframe</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+test(function() {
+ var iframe = document.getElementById("test");
+ var s = "<plaintext><span>Filler Text";
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s[i]);
+ }
+ iframe.contentDocument.close();
+ assert_equals(iframe.contentDocument.body.childNodes[0].nodeType, document.ELEMENT_NODE);
+ assert_equals(iframe.contentDocument.body.childNodes[0].localName, "plaintext");
+ assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "<span>Filler Text");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html
new file mode 100644
index 0000000000..8b271c7a03
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_009.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>document.write plaintext into iframe</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+test(function() {
+ var iframe = document.getElementById("test");
+ var s = "<table><tr><td>Text</tr><plaintext><tr><td>Filler ";
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s[i]);
+ }
+ iframe.contentDocument.close();
+ assert_equals(iframe.contentDocument.body.childNodes[0].nodeType, document.ELEMENT_NODE);
+ assert_equals(iframe.contentDocument.body.childNodes[0].localName, "plaintext");
+ assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "<tr><td>Filler ");
+ assert_equals(iframe.contentDocument.body.childNodes[1].nodeType, document.ELEMENT_NODE);
+ assert_equals(iframe.contentDocument.body.childNodes[1].localName, "table");
+ assert_equals(iframe.contentDocument.body.childNodes[1].textContent, "Text");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html
new file mode 100644
index 0000000000..8dc21a013a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/iframe_010.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>document.write plaintext</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<iframe id="test"></iframe>
+<script>
+var t = async_test();
+var iframe = document.getElementById("test");
+
+function check_dom() {
+ assert_equals(iframe.contentDocument.body.childNodes[0].localName, "plaintext")
+ assert_equals(iframe.contentDocument.body.childNodes[0].textContent, "Filler ")
+ assert_equals(iframe.contentDocument.body.childNodes[1].localName, "table")
+}
+
+t.step(function() {
+ var s = "<script>document.write('<table><plaintext>Filler '); document.close(); top.t.step(function() {top.check_dom()})</script" + ">";
+ for (var i=0; i<s.length; i++) {
+ iframe.contentDocument.write(s[i]);
+ }
+ t.done();
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html
new file mode 100644
index 0000000000..f97f597238
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed-iframe.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<script type=module>
+window.parent.document.test.step_timeout(() => {
+ document.write("document.write body contents\n")
+ document.close();
+ window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
+}, 0);
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html
new file mode 100644
index 0000000000..acdeab59ff
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-delayed.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>async document.write in a module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ // Expose {test} in the iframe for using the step_timeout helper.
+ document.test = t;
+ const iframe = document.createElement("iframe");
+
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let onLoadWasCalled = false;
+ iframe.onload = t.step_func(() => {
+ onLoadWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ // Don't call the event handler another time after document.write.
+ iframe.onload = null;
+ });
+ document.addEventListener("documentWriteDone", t.step_func_done(() => {
+ assert_true(onLoadWasCalled, "onload must be called");
+ assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n");
+ }));
+
+ iframe.src = "module-delayed-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html
new file mode 100644
index 0000000000..672bb953d6
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import-iframe.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script type=module>
+(async () => {
+ let module = await import("./module-dynamic-import.mjs");
+})();
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html
new file mode 100644
index 0000000000..5939968f05
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ const iframe = document.createElement("iframe");
+
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let onLoadWasCalled = false;
+ iframe.onload = t.step_func(() => {
+ onLoadWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ // Don't call the event handler another time after document.write.
+ iframe.onload = null;
+ });
+ document.addEventListener("documentWriteDone", t.step_func_done(() => {
+ assert_true(onLoadWasCalled, "onload must be called");
+ assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n");
+ }));
+
+ iframe.src = "module-dynamic-import-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs
new file mode 100644
index 0000000000..74d2427537
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-dynamic-import.mjs
@@ -0,0 +1,4 @@
+document.write("document.write body contents\n");
+document.close();
+
+window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html
new file mode 100644
index 0000000000..f8646df56b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-iframe.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script type=module>
+document.write("document.write body contents\n");
+document.close();
+window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html
new file mode 100644
index 0000000000..3ae1464653
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed-iframe.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<script type=module>
+import "./module-static-import-delayed.mjs"
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html
new file mode 100644
index 0000000000..a6e003907f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ // Expose {test} in the iframe for using the step_timeout helper.
+ document.test = t;
+ const iframe = document.createElement("iframe");
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let onLoadWasCalled = false;
+ iframe.onload = t.step_func(() => {
+ onLoadWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ // Don't call the event handler another time after document.write.
+ iframe.onload = null;
+ });
+ document.addEventListener("documentWriteDone", t.step_func_done(() => {
+ assert_true(onLoadWasCalled, "onload must be called");
+ assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n");
+ }));
+
+ iframe.src = "module-static-import-delayed-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs
new file mode 100644
index 0000000000..45478d6f63
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-delayed.mjs
@@ -0,0 +1,5 @@
+window.parent.document.test.step_timeout(() => {
+ document.write("document.write body contents\n")
+ document.close();
+ window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
+}, 0);
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html
new file mode 100644
index 0000000000..ed4f6d1c6c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import-iframe.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<script type=module>
+import "./module-static-import.mjs"
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html
new file mode 100644
index 0000000000..3cae88047e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ const iframe = document.createElement("iframe");
+
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let testEndWasCalled = false;
+ document.addEventListener("documentWriteDone", t.step_func(() => {
+ testEndWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ }));
+ iframe.onload = t.step_func_done(() => {
+ assert_true(testEndWasCalled, "onload must be called");
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ });
+
+ iframe.src = "module-static-import-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
+ß
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs
new file mode 100644
index 0000000000..74d2427537
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-static-import.mjs
@@ -0,0 +1,4 @@
+document.write("document.write body contents\n");
+document.close();
+
+window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html
new file mode 100644
index 0000000000..5629c47be7
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed-iframe.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<script type=module>
+let delay = new Promise(
+ resolve => window.parent.document.test.step_timeout(resolve, 0));
+
+delay.then(() => {
+ document.write("document.write body contents\n");
+ document.close();
+ window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
+});
+
+await delay;
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html
new file mode 100644
index 0000000000..5fa8216600
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-delayed.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ // Expose {test} in the iframe for using the step_timeout helper.
+ document.test = t;
+
+ const iframe = document.createElement("iframe");
+
+ iframe.onunhandledrejection = t.unreached_func("Unhandled promise rejection detected");
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let onLoadWasCalled = false;
+ iframe.onload = t.step_func(() => {
+ onLoadWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ iframe.onload = null;
+ });
+ document.addEventListener("documentWriteDone", t.step_func_done(() => {
+ assert_true(onLoadWasCalled, "onload must be called");
+ assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n");
+ }));
+
+ iframe.src = "module-tla-delayed-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html
new file mode 100644
index 0000000000..3e90fb2ea7
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise-iframe.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<script type=module>
+await new Promise(resolve => {
+ document.write("document.write body contents\n");
+ document.close();
+ window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
+ resolve();
+});
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html
new file mode 100644
index 0000000000..f60aa38e00
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-immediate-promise.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ // Expose {test} in the iframe for using the step_timeout helper.
+ document.test = t;
+
+ const iframe = document.createElement("iframe");
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let onLoadWasCalled = false;
+ iframe.onload = t.step_func(() => {
+ onLoadWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ // Don't call the event handler another time after document.write.
+ iframe.onload = null;
+ });
+ document.addEventListener("documentWriteDone", t.step_func_done(() => {
+ assert_false(onLoadWasCalled, "onload must not be called yet");
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ }));
+
+ iframe.src = "module-tla-immediate-promise-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html
new file mode 100644
index 0000000000..ec4a6ed6aa
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import-iframe.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<script type=module>
+await import("./module-tla-import.mjs");
+</script>
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html
new file mode 100644
index 0000000000..20645f4d78
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ const iframe = document.createElement("iframe");
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ let onLoadWasCalled = false;
+
+ iframe.onload = t.step_func(() => {
+ onLoadWasCalled = true;
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ // Don't call the event handler another time after document.write.
+ iframe.onload = null;
+ });
+ document.addEventListener("documentWriteDone", t.step_func_done(() => {
+ assert_true(onLoadWasCalled, "onload must be called");
+ assert_equals(iframe.contentDocument.body.textContent, "document.write body contents\n");
+ }));
+
+ iframe.src = "module-tla-import-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs
new file mode 100644
index 0000000000..74d2427537
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-import.mjs
@@ -0,0 +1,4 @@
+document.write("document.write body contents\n");
+document.close();
+
+window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html
new file mode 100644
index 0000000000..edc9e80cb3
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise-iframe.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<script type=module>
+await new Promise(resolve => {
+ window.parent.document.test.step_timeout(resolve, 0);
+ document.write("document.write body contents\n");
+ document.close();
+ window.parent.document.dispatchEvent(new CustomEvent("documentWriteDone"));
+});
+</script>
+
+Initial body contents
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html
new file mode 100644
index 0000000000..4f1281bcce
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module-tla-promise.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>document.write in an imported module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ // Expose {test} in the iframe for using the step_timeout helper.
+ document.test = t;
+
+ const iframe = document.createElement("iframe");
+ iframe.onerror = t.unreached_func("Error loading iframe");
+
+ document.addEventListener("documentWriteDone", t.step_func(() => {
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ }));
+ iframe.onload = t.step_func_done(() => {
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ });
+
+ iframe.src = "module-tla-promise-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html
new file mode 100644
index 0000000000..7e970d3fd9
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/module.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>document.write in a module</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ const iframe = document.createElement("iframe");
+
+ iframe.onerror = t.unreached_func("Error loading iframe");
+ document.addEventListener("documentWriteDone", t.step_func(() => {
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ }));
+ iframe.onload = t.step_func_done(() => {
+ assert_equals(iframe.contentDocument.body.textContent, "Initial body contents\n");
+ });
+
+ iframe.src = "module-iframe.html";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html
new file mode 100644
index 0000000000..c7a7a1db4e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-1.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body>You should see the word "worked" below<br><script>document.write("\u003cscript>document.write(\"\\u003cscript src='nested-document-write-external.js'>\\u003c/script>r\"); document.write(\"k\");\u003c/script>e"); document.write("d");</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html
new file mode 100644
index 0000000000..60b8eae1ef
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-2.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<body>
+You should see the word "worked" in the frame below.<br>
+<iframe></iframe>
+<script>
+var doc = document.getElementsByTagName("iframe")[0].contentDocument;
+doc.open(); doc.write("\u003cscript>document.write(\"\\u003cscript src='nested-document-write-external.js'>\\u003c/script>r\"); document.write(\"k\");\u003c/script>e"); doc.write("d"); doc.close();</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js
new file mode 100644
index 0000000000..bf91daf986
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/nested-document-write-external.js
@@ -0,0 +1 @@
+document.write("w"); document.write("o");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json
new file mode 100644
index 0000000000..08bd4d0d4e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/original-id.json
@@ -0,0 +1 @@
+{"original_id":"document.write()"} \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html
new file mode 100644
index 0000000000..43c7adb4d4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_001.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>document.write script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<script>t.done();<"+"/script>");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html
new file mode 100644
index 0000000000..3879d8489f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_002.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>document.write script executed synchronously</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ document.write("<script>t.step(function() {order.push(1);});<"+"/script>");
+ order.push(2);
+});
+</script>
+<script>
+t.step(function() {
+ order.push(3);
+ assert_array_equals(order, [1,2,3]);
+})
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html
new file mode 100644
index 0000000000..e669252f75
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_003.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>document.write script writing a further script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ document.write("<script>document.write('<script>t.done()</script'+'>')<"+"/script>");
+});
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html
new file mode 100644
index 0000000000..15fda325b1
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_004.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write script writing script; order of execution</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script>order.push(2); document.write('<script>order.push(3);</script'+'>'); order.push(4);<"+"/script>");
+ order.push(5);
+});
+</script>
+<script>
+t.step(function() {
+ assert_array_equals(order, [1,2,3,4,5]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html
new file mode 100644
index 0000000000..b99196c7d0
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_005.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>document.write external script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script src='005.js'><"+"/script>");
+ order.push(2);
+});
+</script>
+<script>
+order.push(4);
+t.step(function() {
+ assert_array_equals(order, [1,2,3,4]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html
new file mode 100644
index 0000000000..c8dd9a5f9a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_006.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>document.write external script followed by internal script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script src='006.js'><"+"/script><script>t.step(function(){order.push(4)})</script"+">");
+ order.push(2);
+});
+</script>
+<script>
+t.step(function() {
+ order.push(5);
+ assert_array_equals(order, [1,2,3,4,5]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html
new file mode 100644
index 0000000000..fbbe5b2f86
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_007.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write external script that document.writes inline script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+});
+</script>
+<script src="007.js"></script>
+<script>
+t.step(function() {
+ order.push(4);
+ assert_array_equals(order, [1,2,3,4]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html
new file mode 100644
index 0000000000..c5a44dc700
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_008.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write external script that document.writes external script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+});
+</script>
+<script src="008.js"></script>
+<script>
+t.step(function() {
+ order.push(4);
+ assert_array_equals(order, [1,2,3,4]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html
new file mode 100644
index 0000000000..d12d934ea0
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_009.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>document.write script that document.writes script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script>order.push(2); document.write('<script>order.push(3); document.write(\"<script>order.push(4);</script\"+\">\"); order.push(5);</script' + '>'); order.push(6);</script" + ">");
+ order.push(7);
+});
+</script>
+<script>
+t.step(function() {
+ assert_array_equals(order, [1,2,3,4,5,6,7]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html
new file mode 100644
index 0000000000..93728d6f27
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_010.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write external script tokenizer order</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script src='010.js'></script" + "><meta><script src='010-1.js'></script" + ">");
+ order.push(2);
+ assert_equals(document.getElementsByTagName("meta").length, 0);
+});
+</script>
+<script>
+t.step(function() {
+ order.push(5);
+ assert_equals(document.getElementsByTagName("meta").length, 1);
+ assert_array_equals(order, [1,2,3,4,5]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html
new file mode 100644
index 0000000000..2bbcaf976e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_011.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write external script that document.writes external script</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script src='011.js'></script" + "><meta>");
+ order.push(2);
+ assert_equals(document.getElementsByTagName("meta").length, 0);
+});
+</script>
+<script>
+t.step(function() {
+ order.push(5);
+ assert_equals(document.getElementsByTagName("meta").length, 3, "Number of meta elements at end");
+ assert_array_equals(order, [1,2,3,4,5]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html
new file mode 100644
index 0000000000..57755f4c94
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_012.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>document.write external script tokenizer order</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+var order = [];
+t.step(function() {
+ order.push(1);
+ document.write("<script>order.push(2); document.write('<script src=\"012.js\"></script' + '><meta>'); order.push(3); t.step(function() {assert_equals(document.getElementsByTagName('meta').length, 0)});</script" + "><meta>");
+ order.push(4);
+ assert_equals(document.getElementsByTagName("meta").length, 0);
+});
+</script>
+<script>
+t.step(function() {
+ order.push(6);
+ assert_equals(document.getElementsByTagName("meta").length, 2);
+ assert_array_equals(order, [1,2,3,4,5,6]);
+});
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html
new file mode 100644
index 0000000000..0e71e5eb0c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/script_013.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>document.write</title>
+<script src="/resources/testharness.js"></script><script src="/resources/testharnessreport.js"></script>
+<script>
+var t = async_test();
+t.step(function() {
+ var s = "<script src='013.js'><" + "/script></svg>]]><path></svg>";
+ for (var i=0; i<s.length; i++) {
+ document.write(s[i]);
+ }
+});
+</script><script>
+t.step(function() {
+ assert_equals(document.body.childNodes[0].nodeType, document.ELEMENT_NODE);
+ assert_equals(document.body.childNodes[0].localName, "svg");
+ assert_equals(document.body.childNodes[0].childNodes[0].nodeType, document.TEXT_NODE);
+ assert_equals(document.body.childNodes[0].childNodes[0].data, "</svg>");
+ assert_equals(document.body.childNodes[0].childNodes[1].nodeType, document.ELEMENT_NODE);
+ assert_equals(document.body.childNodes[0].childNodes[1].localName, "path");
+}
+);
+t.done();
+</script>
+<div id="log"></div>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html
new file mode 100644
index 0000000000..6faffd81de
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-write/write-active-document.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>document.write only writes to active documents</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body><div id="log"></div></body>
+<script>
+ async_test(function(t) {
+ var child = document.createElement("iframe");
+ child.src = "empty.html?1";
+ child.onload = t.step_func(function() {
+ var child1 = child.contentDocument;
+ var link = child1.createElement("a");
+ link.href = "data:text/html,Clicked.";
+ link.innerText = "Link.";
+ child1.body.appendChild(link);
+ var grandchild = child1.createElement("iframe");
+ grandchild.src = "empty.html?2";
+ grandchild.onload = t.step_func(function() {
+ var grandchild1 = grandchild.contentDocument;
+ child.onload = t.step_func(function() {
+ // This is a write to an inactive document
+ child1.write('WRITE HAPPENED');
+ assert_equals(child1.body.lastChild.tagName, "IFRAME");
+ // This is a write to an active but not fully active document
+ grandchild1.write('WRITE HAPPENED');
+ assert_equals(grandchild1.body.innerHTML, "WRITE HAPPENED");
+ t.done();
+ });
+ link.click();
+ });
+ child1.body.appendChild(grandchild);
+ });
+ document.body.appendChild(child);
+ });
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml
new file mode 100644
index 0000000000..cb5ec3a33a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-01.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>document.writeln in XHTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#document.writeln%28%29"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ document.writeln("Failure: document.writeln actually worked");
+ }, "document.writeln in XHTML should throw an INVALID_STATE_ERR ");
+}, "document.writeln in XHTML");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html
new file mode 100644
index 0000000000..2a64ac7561
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-02.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>document.writeln and null/undefined</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-writeln%28%29">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#documents-in-the-dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+ doc = iframe.contentDocument;
+ test(function() {
+ doc.open();
+ doc.writeln(null);
+ doc.close();
+ assert_equals(doc.documentElement.textContent, "null\n");
+ }, "document.writeln(null)");
+ test(function() {
+ doc.open();
+ doc.writeln(undefined);
+ doc.close();
+ assert_equals(doc.documentElement.textContent, "undefined\n");
+ }, "document.writeln(undefined)");
+}, "Calling document.writeln with null and undefined");
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html
new file mode 100644
index 0000000000..df9a7a15c2
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/document.writeln-03.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>document.writeln with multiple arguments</title>
+<link rel="author" title="Sebmaster" href="mailto:wpt@smayr.name">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-writeln%28%29">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#documents-in-the-dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+ var doc = iframe.contentDocument;
+ doc.open();
+ doc.writeln('a', 'b');
+ doc.close();
+ assert_equals(doc.documentElement.textContent, "ab\n");
+}, "Calling document.writeln with multiple arguments");
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json
new file mode 100644
index 0000000000..0cc32be6a2
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/document-writeln/original-id.json
@@ -0,0 +1 @@
+{"original_id":"document.writeln()"} \ No newline at end of file
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html
new file mode 100644
index 0000000000..1debcafa3b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-encoding.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="windows-1252"> <!-- intentional to make sure the results are UTF-8 anyway -->
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/pull/9538">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- This was adapted from DOMParser-parseFromString-encoding.html -->
+
+<script>
+function assertEncoding(doc) {
+ assert_equals(doc.charset, "UTF-8", "document.charset");
+ assert_equals(doc.characterSet, "UTF-8", "document.characterSet");
+ assert_equals(doc.inputEncoding, "UTF-8", "document.characterSet");
+}
+
+setup(() => {
+ assert_equals(document.characterSet, "windows-1252", "the meta charset must be in effect, making the main document windows-1252");
+});
+
+test(() => {
+ const doc = Document.parseHTMLUnsafe('');
+ assertEncoding(doc);
+}, 'Parse empty string');
+
+test(() => {
+ const doc = Document.parseHTMLUnsafe(`<meta charset="latin2">`);
+ assertEncoding(doc);
+}, "meta charset latin2");
+
+test(() => {
+ const doc = Document.parseHTMLUnsafe(`<?xml version="1.0" encoding="latin2"?><x/>`);
+ assertEncoding(doc);
+}, "XML declaration");
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html
new file mode 100644
index 0000000000..cd092a6034
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-style-attribute.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This test was adapted from style_attribute_html.html -->
+<meta charset=utf-8>
+<title>Style attribute in HTML</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+var div;
+setup(function() {
+ var input = '<div style="color: red">Foo</div>';
+ var doc = Document.parseHTMLUnsafe(input);
+ div = doc.querySelector('div');
+});
+
+test(function() {
+ var style = div.style;
+ assert_equals(style.cssText, 'color: red;');
+ assert_equals(style.color, 'red');
+ assert_equals(div.getAttribute("style"), 'color: red',
+ 'Value of style attribute should match the string value that was set');
+}, 'Parsing of initial style attribute');
+
+test(function() {
+ var style = div.style;
+ div.setAttribute('style', 'color:: invalid');
+ assert_equals(style.cssText, '');
+ assert_equals(style.color, '');
+ assert_equals(div.getAttribute('style'), 'color:: invalid',
+ 'Value of style attribute should match the string value that was set');
+}, 'Parsing of invalid style attribute');
+
+test(function() {
+ var style = div.style;
+ div.setAttribute('style', 'color: green');
+ assert_equals(style.cssText, 'color: green;');
+ assert_equals(style.color, 'green');
+ assert_equals(div.getAttribute('style'), 'color: green',
+ 'Value of style attribute should match the string value that was set');
+}, 'Parsing of style attribute');
+
+test(function() {
+ var style = div.style;
+ style.backgroundColor = 'blue';
+ assert_equals(style.cssText, 'color: green; background-color: blue;',
+ 'Should not drop the existing style');
+ assert_equals(style.color, 'green',
+ 'Should not drop the existing style');
+ assert_equals(div.getAttribute('style'), 'color: green; background-color: blue;',
+ 'Should update style attribute');
+}, 'Update style.backgroundColor');
+
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html
new file mode 100644
index 0000000000..a8eab59511
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base-pushstate.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This test was adapted from DOMParser-parseFromString-url-base-pushstate.html -->
+<title>parseHTMLUnsafe test of how the document's URL is set (base, pushstate)</title>
+<base href="/fake/base-from-outer-frame">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html" onload="window.resolveLoadPromise();"></iframe>
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-outer-frame");
+</script>
+<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html
new file mode 100644
index 0000000000..62b2c09aae
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-base.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This was adapted from DOMParser-parseFromString-url-base.html -->
+<title>parseHTMLUnsafe test of how the document's URL is set (base, no pushstate)</title>
+<base href="/fake/base-from-outer-frame">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html" onload="window.resolveLoadPromise();"></iframe>
+<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html
new file mode 100644
index 0000000000..41335ef035
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-moretests.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This test was adapted from DOMParser-parseFromString-url-moretests.html -->
+<meta charset=utf-8>
+<title>Document.parseHTMLUnsafe: Document's url</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var iframe = document.createElement("iframe");
+ iframe.onload = this.step_func(function() {
+ var child = iframe.contentWindow;
+
+ test(function() {
+ var doc = Document.parseHTMLUnsafe("<html></html>");
+ assert_equals(doc.URL, "about:blank");
+ }, "Parent window");
+
+ test(function() {
+ var doc = child.Document.parseHTMLUnsafe("<html></html>");
+ assert_equals(doc.URL, "about:blank");
+ }, "Child window");
+
+ var dpBeforeNavigation = child.Document, urlBeforeNavigation = child.document.URL;
+ iframe.onload = this.step_func_done(function() {
+ test(function() {
+ var doc = dpBeforeNavigation.parseHTMLUnsafe("<html></html>");
+ assert_equals(doc.URL, "about:blank");
+ }, "Child window crossing navigation");
+
+ test(function() {
+ var doc = child.Document.parseHTMLUnsafe("<html></html>");
+ assert_equals(doc.URL, "about:blank");
+ }, "Child window after navigation");
+ });
+ iframe.src = "/common/blank.html?2";
+ });
+ iframe.src = "/common/blank.html?1";
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html
new file mode 100644
index 0000000000..7930bf0ddb
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url-pushstate.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This test was adapted from DOMParser-parseFromString-url-pushstate.html -->
+<title>parseHTMLUnsafe test of how the document's URL is set (no base, pushstate)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html" onload="window.resolveLoadPromise();"></iframe>
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-outer-frame");
+</script>
+<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html
new file mode 100644
index 0000000000..911e183706
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe-url.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This test was adapted from DOMParser-parseFromString-url.html -->
+<title>parseHTMLUnsafe test of how the document's URL is set (no pushstate, no base)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe src="resources/parseHTMLUnsafe-iframe.html" onload="window.resolveLoadPromise();"></iframe>
+<script src="resources/parseHTMLUnsafe-url-tests.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html
new file mode 100644
index 0000000000..2a89370825
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Document-parseHTMLUnsafe.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This was adapted from DOMParser-parseFromString-html.html -->
+<title>parseHTMLUnsafe basic test of HTML parsing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// |expected| should be an object indicating the expected type of node.
+function assert_node(actual, expected) {
+ assert_true(actual instanceof expected.type,
+ 'Node type mismatch: actual = ' + actual.constructor.name + ', expected = ' + expected.type.name);
+ if (typeof(expected.id) !== 'undefined')
+ assert_equals(actual.id, expected.id, expected.idMessage);
+}
+
+var doc;
+setup(function() {
+ doc = Document.parseHTMLUnsafe('<html id="root"><head></head><body></body></html>');
+});
+
+test(function() {
+ var root = doc.documentElement;
+ assert_node(root, { type: HTMLHtmlElement, id: 'root',
+ idMessage: 'documentElement id attribute should be root.' });
+}, 'Parsing of id attribute');
+
+test(function() {
+ assert_equals(doc.contentType, "text/html")
+}, 'contentType');
+
+test(function() {
+ assert_equals(doc.compatMode, "BackCompat")
+}, 'compatMode');
+
+test(function() {
+ doc = Document.parseHTMLUnsafe('<!DOCTYPE html><html id="root"><head></head><body></body></html>');
+ assert_equals(doc.compatMode, "CSS1Compat")
+}, 'compatMode for a proper DOCTYPE');
+
+// URL- and encoding-related stuff tested separately.
+
+test(function() {
+ assert_equals(doc.location, null,
+ 'The document must have a location value of null.');
+}, 'Location value');
+
+test(function() {
+ var htmldoc = Document.parseHTMLUnsafe("<!DOCTYPE foo></><foo></multiple></>");
+ assert_equals(htmldoc.documentElement.localName, "html");
+ assert_equals(htmldoc.documentElement.namespaceURI, "http://www.w3.org/1999/xhtml");
+}, "Document.parseHTMLUnsafe parses HTML tag soup with no problems");
+
+test(function() {
+ const doc = Document.parseHTMLUnsafe('<noembed>&lt;a&gt;</noembed>');
+ assert_equals(doc.querySelector('noembed').textContent, '&lt;a&gt;');
+}, 'Document.parseHTMLUnsafe should handle the content of <noembed> as raw text');
+
+test(() => {
+ const doc = Document.parseHTMLUnsafe(`
+<html><body>
+<style>
+ @import url(/dummy.css)
+</style>
+<script>document.x = 8<\/script>
+</body></html>`);
+
+ assert_not_equals(doc.querySelector('script'), null, 'script must be found');
+ assert_equals(doc.x, undefined, 'script must not be executed on the inner document');
+ assert_equals(document.x, undefined, 'script must not be executed on the outer document');
+}, 'script is found synchronously even when there is a css import');
+
+test(() => {
+ const doc = Document.parseHTMLUnsafe(`<body><noscript><p id="test1">test1<p id="test2">test2</noscript>`);
+ assert_node(doc.body.firstChild.childNodes[0], { type: HTMLParagraphElement, id: 'test1' });
+ assert_node(doc.body.firstChild.childNodes[1], { type: HTMLParagraphElement, id: 'test2' });
+}, 'must be parsed with scripting disabled, so noscript works');
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html
new file mode 100644
index 0000000000..4a9e300afc
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/Element-setHTMLUnsafe-04.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>setHTMLUnsafe in HTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel=author href="mailto:jarhar@chromium.org">
+<!-- This test was adapted from innerhtml-04.html -->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+function testIsChild(p, c) {
+ assert_equals(p.firstChild, c);
+ assert_equals(c.parentNode, p);
+}
+test(function() {
+ var p = document.createElement('p');
+ var b = p.appendChild(document.createElement('b'));
+ var t = b.appendChild(document.createTextNode("foo"));
+ testIsChild(p, b);
+ testIsChild(b, t);
+ assert_equals(t.data, "foo");
+ p.setHTMLUnsafe("");
+ testIsChild(b, t);
+ assert_equals(t.data, "foo");
+}, "setHTMLUnsafe should leave the removed children alone.")
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html
new file mode 100644
index 0000000000..53b855968c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base-pushstate.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does parseHTMLUnsafe stuff with base and pushstates itself</title>
+<base href="/fake/base-from-iframe">
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-iframe");
+</script>
+<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html
new file mode 100644
index 0000000000..6977e93811
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-base.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does parseHTMLUnsafe stuff with base</title>
+<base href="/fake/base-from-iframe">
+
+<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html
new file mode 100644
index 0000000000..5e1fae0441
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe-pushstate.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does parseHTMLUnsafe stuff and pushstates itself</title>
+
+<script>
+"use strict";
+history.pushState(null, "", "/fake/push-state-from-iframe");
+</script>
+<script src="/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html
new file mode 100644
index 0000000000..f47d9605fc
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>An iframe that does parseHTMLUnsafe stuff</title>
+<script src="parseHTMLUnsafe-iframe.js"></script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js
new file mode 100644
index 0000000000..4a0b56869b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-iframe.js
@@ -0,0 +1,3 @@
+window.doParse = (html) => {
+ return Document.parseHTMLUnsafe(html);
+};
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js
new file mode 100644
index 0000000000..88344d127c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/resources/parseHTMLUnsafe-url-tests.js
@@ -0,0 +1,36 @@
+const loadPromise = new Promise(resolve => { window.resolveLoadPromise = resolve; });
+
+function assertURL(doc) {
+ assert_equals(doc.URL, "about:blank", "document.URL");
+ assert_equals(doc.documentURI, "about:blank", "document.documentURI");
+ assert_equals(doc.baseURI, "about:blank", "document.baseURI");
+}
+
+const inputs = {
+ valid: "<html></html>",
+ "invalid XML": `<span x:test="testing">1</span>`
+};
+
+for (const [inputName, input] of Object.entries(inputs)) {
+ test(() => {
+ const doc = Document.parseHTMLUnsafe(input);
+
+ assertURL(doc);
+ }, `${inputName}: created normally`);
+
+ promise_test(async () => {
+ await loadPromise;
+
+ const doc = frames[0].Document.parseHTMLUnsafe(input);
+
+ assertURL(doc);
+ }, `${inputName}: created using another iframe's parseHTMLUnsafe from this frame`);
+
+ promise_test(async () => {
+ await loadPromise;
+
+ const doc = frames[0].doParse(input);
+
+ assertURL(doc);
+ }, `${inputName}: created using another iframe's parseHTMLUnsafe from that frame`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html
new file mode 100644
index 0000000000..3aa14516f2
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-CEReactions.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/issues/9957">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+class MyElement extends HTMLElement {
+ constructor() {
+ super();
+ this.numConnectedCallback = 0;
+ this.numDisconnectedCallback = 0;
+ this.attributeChangedCalls = [];
+ }
+
+ connectedCallback() {
+ this.numConnectedCallback++;
+ }
+
+ disconnectedCallback() {
+ this.numDisconnectedCallback++;
+ }
+
+ static observedAttributes = ['foo'];
+ attributeChangedCallback(name, oldValue, newValue) {
+ this.attributeChangedCalls.push({name, oldValue, newValue});
+ }
+}
+customElements.define('my-element', MyElement);
+
+['Element', 'ShadowRoot'].forEach(containerType => {
+ test(() => {
+ let container = null;
+ if (containerType === 'Element') {
+ container = document.createElement('div');
+ document.body.appendChild(container);
+ } else if (containerType === 'ShadowRoot') {
+ const host = document.createElement('div');
+ document.body.appendChild(host);
+ container = host.attachShadow({mode: 'closed'});
+ }
+
+ container.setHTMLUnsafe('<my-element>');
+ const myElement1 = container.querySelector('my-element');
+ assert_equals(myElement1.numConnectedCallback, 1,
+ 'myElement1.numConnectedCallback after first setHTMLUnsafe.');
+ assert_equals(myElement1.numDisconnectedCallback, 0,
+ 'myElement1.numDisconnectedCallback after first setHTMLUnsafe.');
+ assert_equals(JSON.stringify(myElement1.attributeChangedCalls),
+ JSON.stringify([]),
+ 'myElement1.attributeChangedCalls after first setHTMLUnsafe.');
+
+ container.setHTMLUnsafe('<my-element foo=bar>');
+ const myElement2 = container.querySelector('my-element');
+ assert_equals(myElement1.numConnectedCallback, 1,
+ 'myElement1.numConnectedCallback after second setHTMLUnsafe.');
+ assert_equals(myElement1.numDisconnectedCallback, 1,
+ 'myElement1.numDisconnectedCallback after second setHTMLUnsafe.');
+ assert_array_equals(myElement1.attributeChangedCalls, [],
+ 'myElement1.attributeChangedCalls after second setHTMLUnsafe.');
+ assert_equals(myElement2.numConnectedCallback, 1,
+ 'myElement2.numConnectedCallback after second setHTMLUnsafe.');
+ assert_equals(myElement2.numDisconnectedCallback, 0,
+ 'myElement2.numDisconnectedCallback after second setHTMLUnsafe.');
+ assert_equals(JSON.stringify(myElement2.attributeChangedCalls),
+ JSON.stringify([{name: 'foo', oldValue: null, newValue: 'bar'}]),
+ 'myElement2.attributeChangedCalls after second setHTMLUnsafe.');
+ }, `${containerType}.setHTMLUnsafe should trigger custom element reactions.`);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html
new file mode 100644
index 0000000000..d7211e97f1
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe-xml.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/pull/9538">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+test(() => {
+ const xmlDoc = document.implementation.createDocument(null, 'root', null);
+ assert_equals(xmlDoc.contentType, 'application/xml');
+ // Intentionally unclosed and misnested tags
+ xmlDoc.documentElement.setHTMLUnsafe('<p><foo><b><i>test</b></i>');
+ assert_equals(xmlDoc.documentElement.innerHTML,
+ '<p xmlns="http://www.w3.org/1999/xhtml"><foo><b><i>test</i></b></foo></p>',
+ 'Element.setHTMLUnsafe should use the HTML parser in XML documents.');
+}, 'setHTMLUnsafe should still parse HTML even in XML documents.');
+
+test(() => {
+ const svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'root', null);
+ assert_equals(svgDoc.contentType, 'image/svg+xml');
+ // Intentionally unclosed and misnested tags
+ svgDoc.documentElement.setHTMLUnsafe('<p><foo><b><i>test</b></i>');
+ assert_equals(svgDoc.documentElement.innerHTML,
+ '<p xmlns="http://www.w3.org/1999/xhtml"><foo><b><i>test</i></b></foo></p>',
+ 'Element.setHTMLUnsafe should use the HTML parser in SVG documents.');
+}, 'setHTMLUnsafe should still parse HTML even in SVG documents.');
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html
new file mode 100644
index 0000000000..1c0b115569
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/html-unsafe-methods/setHTMLUnsafe.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/pull/9538">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+for (const containerType of ['Element', 'ShadowRoot']) {
+ const createContainer = () => {
+ if (containerType == 'ShadowRoot') {
+ return document.createElement('div').attachShadow({mode: 'open'});
+ } else if (containerType == 'Element') {
+ return document.createElement('div');
+ }
+ };
+
+ test(() => {
+ const container = createContainer();
+ container.setHTMLUnsafe('<span title=hello>world</span>');
+
+ assert_equals(container.children.length, 1, 'Only one child node should be created.');
+ assert_equals(container.firstChild.tagName, 'SPAN', 'The child element should be a span.');
+ assert_equals(container.firstChild.getAttribute('title'), 'hello',
+ 'The title attribute should be set to hello.');
+ assert_equals(container.firstChild.childNodes.length, 1,
+ 'The span should have one child.');
+ assert_true(container.firstChild.childNodes[0] instanceof Text,
+ 'The spans child should be a text node.');
+ assert_equals(container.firstChild.textContent, 'world',
+ 'The spans textContent should be world.');
+ }, `${containerType}: setHTMLUnsafe with no shadowdom.`);
+
+ test(() => {
+ const container = createContainer();
+ container.setHTMLUnsafe(`<div><template shadowrootmode=open><div>hello</div></template></div>`);
+
+ assert_equals(container.children.length, 1, 'One child should be created in the container.');
+ const shadowRoot = container.firstChild.shadowRoot;
+ assert_true(!!shadowRoot, 'The containers child should have a ShadowRoot.');
+ assert_equals(shadowRoot.children.length, 1, 'One child should be created in the ShadowRoot.');
+ assert_equals(shadowRoot.firstChild.textContent, 'hello',
+ 'The ShadowRoots childs textContent should be hello.');
+ }, `${containerType}: setHTMLUnsafe with shadowdom.`);
+}
+
+test(() => {
+ const template = document.createElement('template');
+ template.setHTMLUnsafe('<div>hello world</div>');
+
+ assert_equals(template.children.length, 0, 'template should not have any child nodes.');
+ assert_equals(template.content.children.length, 1, 'template content should have a child div.');
+ assert_equals(template.content.children[0].textContent, 'hello world', 'text content should be set.');
+}, 'template.setHTMLUnsafe() should modify template content fragment rather than actual children.');
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html
new file mode 100644
index 0000000000..5584bf9afb
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/002.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>document.open during parsing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ var log = document.getElementById("log");
+ assert_equals(document.open(), document);
+ assert_equals(document.getElementById("log"), log);
+})
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html
new file mode 100644
index 0000000000..3fb443a993
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/004.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Reuse of document object after document.open</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe src="/common/blank.html"></iframe>
+<script>
+var t = async_test();
+var iframe;
+onload = t.step_func(function() {
+ var iframe = document.getElementsByTagName("iframe")[0];
+ var handle = iframe.contentDocument;
+ iframe.contentDocument.test_state = 1;
+ assert_equals(iframe.contentDocument.open(), handle);
+ assert_equals(iframe.contentDocument.test_state, 1);
+ assert_equals(iframe.contentDocument, handle);
+ t.done();
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html
new file mode 100644
index 0000000000..1dcb92615d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/006.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Cancelling error after document.open</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe src="/common/blank.html"></iframe>
+<script>
+var t = async_test();
+var iframe;
+onload = t.step_func(function() {
+ var iframe = document.getElementsByTagName("iframe")[0];
+ var img = iframe.contentDocument.createElement("img");
+ img.onerror = t.step_func(function() {assert_unreached()})
+ img.src = "missing";
+ iframe.contentDocument.body.appendChild(img);
+ assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
+ setTimeout(function() {t.done();}, 500);
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html
new file mode 100644
index 0000000000..37973fd52e
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011-1.html
@@ -0,0 +1,5 @@
+<script>
+parent.t.step(() => { parent.assert_equals(document.open(), document); });
+setTimeout(parent.t.step_func(function() {parent.t.done()}), 0);
+document.close();
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html
new file mode 100644
index 0000000000..2acc884c54
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/011.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Timeout after document.open</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+</script>
+<iframe src="011-1.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html
new file mode 100644
index 0000000000..644b30827d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012-1.html
@@ -0,0 +1,7 @@
+<script>
+onload = parent.t.step_func(function() {
+ parent.assert_equals(document.open(), document);
+ setTimeout(parent.t.step_func(function() {parent.t.done()}), 0);
+ document.close();
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html
new file mode 100644
index 0000000000..518454858d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/012.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Timeout after document.open in load event</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+</script>
+<iframe src="012-1.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html
new file mode 100644
index 0000000000..ea321238ed
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013-1.html
@@ -0,0 +1,7 @@
+<script>
+addEventListener("DOMContentLoaded", parent.t.step_func(function() {
+ parent.assert_equals(document.open(), document);
+ setTimeout(parent.t.step_func(function() {parent.t.done()}), 0);
+ document.close();
+}), false);
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html
new file mode 100644
index 0000000000..5749361aa8
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/013.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Timeout after document.open in DOMContentLoaded event</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+</script>
+<iframe src="013-1.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html
new file mode 100644
index 0000000000..0e97808116
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014-1.html
@@ -0,0 +1,9 @@
+<script>
+onload = parent.t.step_func(function() {
+ setTimeout(parent.t.step_func(function() {
+ parent.assert_equals(document.open(), document);
+ setTimeout(parent.t.step_func(function() {parent.t.done()}), 0);
+ document.close();
+ }), 100)
+});
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html
new file mode 100644
index 0000000000..b4e4b17cf4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/014.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Timeout after document.open after document is completely loaded</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+</script>
+<iframe src="014-1.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html
new file mode 100644
index 0000000000..c325bd0801
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015-1.html
@@ -0,0 +1,17 @@
+<script>
+onload = function() {
+ window.test_prop = 1;
+ parent.tests[0].step(function() {parent.assert_equals(test_prop, 1)});
+ parent.tests[0].step(function() {parent.assert_equals(document.open(), document)});
+ document.write("<script>test_prop = 2;<\/script>");
+ document.close();
+ parent.tests[0].step(function() {parent.assert_equals(test_prop, 2)});
+ parent.tests[1].step(function() {parent.assert_equals(window.test_prop, 2)});
+ parent.tests[2].step(function() {parent.assert_equals(get_this(), window)});
+ parent.tests_done();
+};
+
+function get_this() {
+ return this;
+}
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html
new file mode 100644
index 0000000000..cce9e65d4c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/015.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Window vs global scope after document.open</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var tests = [async_test("global scope unchanged"),
+ async_test("window object unchanged"),
+ async_test("this is the window object")];
+function tests_done() {
+ tests.forEach(function(t) {t.done()});
+}
+</script>
+<iframe src="015-1.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html
new file mode 100644
index 0000000000..ceeeb64df6
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016-1.html
@@ -0,0 +1,41 @@
+<script>
+window.test_prop = 1;
+</script>
+<script>
+onload = function() {
+ parent.tests[0].step(function() {
+ parent.assert_equals(document.open(), document);
+ });
+ document.write("<script>test_prop = 2; timeout_fired=false;<\/script>");
+ document.close();
+
+ setTimeout(function() {
+ parent.tests[0].step(function() {
+ parent.assert_equals(test_prop, 2, "Global scope from original window timeout");
+ parent.assert_equals(window.test_prop, 2, "Window property from original window timeout")
+ });
+ parent.tests[1].step(function() {
+ var t = get_this();
+ parent.assert_equals(t.test_prop, 2, "Window property from original window timeout");
+ parent.assert_equals(t, window, "Global scope from original window timeout");
+ });
+ }, 0);
+
+ window.setTimeout(function() {
+ parent.tests[2].step(function() {
+ parent.assert_equals(test_prop, 2, "Global scope from original window timeout");
+ parent.assert_equals(window.test_prop, 2, "Window property from original window timeout")
+ });
+ parent.tests[3].step(function() {
+ var t = get_this();
+ parent.assert_equals(t.test_prop, 2, "Window property from original window timeout");
+ parent.assert_equals(t, window, "Global scope from original window timeout");
+ });
+ parent.tests_done();
+ }, 100);
+};
+
+function get_this() {
+ return this;
+}
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html
new file mode 100644
index 0000000000..1c70fce591
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/016.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>setTimeout document.open</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var tests = [async_test("Timeout on original window, scope"),
+ async_test("Timeout on original window, this object"),
+ async_test("Timeout on new window, scope"),
+ async_test("Timeout on new window, this object")];
+function tests_done() {
+ tests.forEach(function(t) {t.done()});
+}
+</script>
+<iframe src="016-1.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js
new file mode 100644
index 0000000000..8d045b9e0a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-immediate.window.js
@@ -0,0 +1,119 @@
+// The following tests deal with the <meta http-equiv=refresh> pragma and the
+// `Refresh` header. The spec is still hazy on the precise behavior in those
+// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/meta-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through <meta> refresh with timeout 0 (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/meta-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through <meta> refresh with timeout 0 (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "resources/meta-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through <meta> refresh with timeout 0 (image loading)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/http-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+
+ frame.contentDocument.open();
+ });
+ frame.src = "resources/http-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "resources/http-refresh.py?0";
+}, "document.open() aborts documents that are queued for navigation through Refresh header with timeout 0 (image loading)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js
new file mode 100644
index 0000000000..8c6c1267c4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-header.window.js
@@ -0,0 +1,69 @@
+// The following tests deal with the <meta http-equiv=refresh> pragma and the
+// `Refresh` header. The spec is still hazy on the precise behavior in those
+// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline.
+//
+// This is separate from abort-refresh-multisecond-meta.window.js to avoid
+// browser interventions that limit the number of connections in a tab.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ client.onerror = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.onabort = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.send();
+
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/http-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 1-sec timeout (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.step_func_done(() => {
+ assert_true(happened);
+ }),
+ t.unreached_func("Fetch should have succeeded")
+ );
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/http-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 1-sec timeout (fetch())");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ img.onerror = t.unreached_func("Image loading should not have errored");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ });
+ frame.src = "resources/http-refresh.py?4";
+}, "document.open() does NOT abort documents that are queued for navigation through Refresh header with 4-sec timeout (image loading)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js
new file mode 100644
index 0000000000..2895f959e5
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-refresh-multisecond-meta.window.js
@@ -0,0 +1,69 @@
+// The following tests deal with the <meta http-equiv=refresh> pragma and the
+// `Refresh` header. The spec is still hazy on the precise behavior in those
+// cases but we use https://github.com/whatwg/html/issues/4003 as a guideline.
+//
+// This is separate from abort-refresh-multisecond-header.window.js to avoid
+// browser interventions that limit the number of connections in a tab.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ client.onerror = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.onabort = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.send();
+
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/meta-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through <meta> refresh with 1-sec timeout (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.step_func_done(() => {
+ assert_true(happened);
+ }),
+ t.unreached_func("Fetch should have succeeded")
+ );
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "resources/meta-refresh.py?1";
+}, "document.open() does NOT abort documents that are queued for navigation through <meta> refresh with 1-sec timeout (fetch())");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ img.onerror = t.unreached_func("Image loading should not have errored");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ });
+ frame.src = "resources/meta-refresh.py?4";
+}, "document.open() does NOT abort documents that are queued for navigation through <meta> refresh with 4-sec timeout (image loading)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js
new file mode 100644
index 0000000000..e3efeffb8b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js
@@ -0,0 +1,179 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ // The abort event handler is called synchronously in Chrome but
+ // asynchronously in Firefox. See https://crbug.com/879620.
+ client.onabort = t.step_func_done();
+ client.send();
+ frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL);
+ frame.contentDocument.open();
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are navigating through Location (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done(() => {
+ assert_true(happened);
+ }));
+ frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL);
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are navigating through Location (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL);
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are navigating through Location (image loading)");
+
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ div.innerHTML = "<iframe src='/common/slow.py'></iframe>";
+ const frame = div.childNodes[0];
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+ frame.contentDocument.open();
+}, "document.open() aborts documents that are navigating through iframe loading (XMLHttpRequest)");
+
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ div.innerHTML = "<iframe src='/common/slow.py'></iframe>";
+ const frame = div.childNodes[0];
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+ frame.contentDocument.open();
+}, "document.open() aborts documents that are navigating through iframe loading (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+//
+// We use /common/slow.py here as the source of the iframe, to prevent the
+// situation where when document.open() is called the initial about:blank
+// document has already become inactive.
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ div.innerHTML = "<iframe src='/common/slow.py'></iframe>";
+ const frame = div.childNodes[0];
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+}, "document.open() aborts documents that are navigating through iframe loading (image loading)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a"));
+ link.href = new URL("resources/dummy.html", document.URL);
+
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onabort = t.step_func_done();
+ client.send();
+
+ link.click();
+ frame.contentDocument.open();
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are queued for navigation through .click() (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a"));
+ link.href = new URL("resources/dummy.html", document.URL);
+
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.unreached_func("Fetch should have been aborted"),
+ t.step_func_done());
+
+ link.click();
+ frame.contentDocument.open();
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are queued for navigation through .click() (fetch())");
+
+// We cannot test for img element's error event for this test, as Firefox does
+// not fire the event if the fetch is aborted while Chrome does.
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a"));
+ link.href = new URL("resources/dummy.html", document.URL);
+
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.unreached_func("Image loading should not have succeeded");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ link.click();
+ frame.contentDocument.open();
+ happened = true;
+ });
+ // If 3 seconds have passed and the image has still not loaded, we consider
+ // it aborted. slow-png.py only sleeps for 2 wallclock seconds.
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 3000);
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() aborts documents that are queued for navigation through .click() (image loading)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js
new file mode 100644
index 0000000000..b2f05cf056
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js
@@ -0,0 +1,104 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const client = new frame.contentWindow.XMLHttpRequest();
+ client.open("GET", "/common/blank.html");
+ client.onload = t.step_func_done(e => {
+ assert_true(happened);
+ });
+ client.onerror = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.onabort = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded");
+ client.send();
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (XMLHttpRequest)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ frame.contentWindow.fetch("/common/blank.html").then(
+ t.step_func_done(() => {
+ assert_true(happened);
+ }),
+ t.unreached_func("Fetch should have succeeded")
+ );
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (fetch())");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const img = frame.contentDocument.createElement("img");
+ img.src = new URL("resources/slow-png.py", document.URL);
+ img.onload = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ img.onerror = t.unreached_func("Image loading should not have errored");
+ // The image fetch starts in a microtask, so let's be sure to test after
+ // the fetch has started.
+ t.step_timeout(() => {
+ frame.contentDocument.open();
+ happened = true;
+ });
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (image loading)");
+
+async_test(t => {
+ const __SERVER__NAME = "{{host}}";
+ const __PORT = {{ports[ws][0]}};
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`);
+ ws.onopen = t.step_func_done(() => {
+ assert_true(happened);
+ });
+ ws.onclose = t.unreached_func("WebSocket fetch should have succeeded");
+ ws.onerror = t.unreached_func("WebSocket should have no error");
+ frame.contentDocument.open();
+ happened = true;
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (establish a WebSocket connection)");
+
+// An already established WebSocket connection shouldn't be terminated during
+// an "abort a document" anyway. Test just for completeness.
+async_test(t => {
+ const __SERVER__NAME = "{{host}}";
+ const __PORT = {{ports[ws][0]}};
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ frame.onload = null;
+ let happened = false;
+ const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`);
+ ws.onopen = t.step_func(() => {
+ t.step_timeout(t.step_func_done(() => {
+ assert_true(happened);
+ }), 100);
+ frame.contentDocument.open();
+ happened = true;
+ });
+ ws.onclose = t.unreached_func("WebSocket should not be closed");
+ ws.onerror = t.unreached_func("WebSocket should have no error");
+ });
+ frame.src = "/common/blank.html";
+}, "document.open() does not abort documents that are not navigating (already established WebSocket connection)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js
new file mode 100644
index 0000000000..ba7278ef18
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/aborted-parser.window.js
@@ -0,0 +1,31 @@
+// document.open() bails out early if there is an active parser with non-zero
+// script nesting level or if a load was aborted while there was an active
+// parser. window.stop() aborts the current parser, so once it has been called
+// while a parser is active, document.open() will no longer do anything to that
+// document,
+
+window.handlers = {};
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.src = "resources/aborted-parser-frame.html";
+ window.handlers.afterOpen = t.step_func_done(() => {
+ const openCalled = frame.contentDocument.childNodes.length === 0;
+ assert_false(openCalled, "child document should not be empty");
+ assert_equals(frame.contentDocument.querySelector("p").textContent,
+ "Text", "Should still have our paragraph");
+ });
+}, "document.open() after parser is aborted");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.src = "resources/aborted-parser-async-frame.html";
+ window.handlers.afterOpenAsync = t.step_func_done(() => {
+ const openCalled = frame.contentDocument.childNodes.length === 0;
+ assert_false(openCalled, "child document should not be empty");
+ assert_equals(frame.contentDocument.querySelector("p").textContent,
+ "Text", "Should still have our paragraph");
+ });
+}, "async document.open() after parser is aborted");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js
new file mode 100644
index 0000000000..f96710999a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/active.window.js
@@ -0,0 +1,98 @@
+function assertOpenIsEffective(doc, initialNodeCount) {
+ assert_equals(doc.childNodes.length, initialNodeCount);
+
+ // Test direct document.open() call.
+ assert_equals(doc.open(), doc);
+ assert_equals(doc.childNodes.length, 0, "after open: no nodes in document");
+ doc.write("<!DOCTYPE html>");
+ assert_equals(doc.childNodes.length, 1, "after write: doctype node in document");
+ doc.close();
+ assert_equals(doc.childNodes.length, 2, "after parser close: doctype node and an html element in document");
+
+ // Test implicit document.open() call through write(). Since we called
+ // doc.close() above, which sets the insertion point of the parser to
+ // undefined, document.write() will run the document open steps.
+ doc.write();
+ assert_equals(doc.childNodes.length, 0, "after implicit open: no nodes in document");
+ doc.write("<!DOCTYPE html>");
+ assert_equals(doc.childNodes.length, 1, "after write: doctype node in document");
+ doc.close();
+ assert_equals(doc.childNodes.length, 2, "after parser close: doctype node and an html element in document");
+}
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ assertOpenIsEffective(frame.contentDocument, 1);
+}, "document.open() removes the document's children (fully active document)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ const childFrame = frame.contentDocument.querySelector("iframe");
+ const childDoc = childFrame.contentDocument;
+ const childWin = childFrame.contentWindow;
+
+ // Right now childDoc is still fully active.
+
+ frame.onload = t.step_func_done(() => {
+ // Now childDoc is still active but no longer fully active.
+ assertOpenIsEffective(childDoc, 1);
+ });
+ frame.src = "/common/blank.html";
+ });
+ frame.src = "resources/page-with-frame.html";
+}, "document.open() removes the document's children (active but not fully active document)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ const doc = frame.contentDocument;
+
+ // Right now the frame is connected and it has an active document.
+ frame.remove();
+
+ // Now the frame is no longer connected. Its document is no longer active.
+ assertOpenIsEffective(doc, 1);
+}, "document.open() removes the document's children (non-active document with an associated Window object; frame is removed)");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.src = "resources/dummy.html";
+
+ frame.onload = t.step_func(() => {
+ const firstDocument = frame.contentDocument;
+ // Right now the frame is connected and it has an active document.
+
+ frame.onload = t.step_func_done(() => {
+ // Now even though the frame is still connected, its document is no
+ // longer active.
+ assert_not_equals(frame.contentDocument, firstDocument);
+ assertOpenIsEffective(firstDocument, 2);
+ });
+
+ frame.src = "/common/blank.html";
+ });
+}, "document.open() removes the document's children (non-active document with an associated Window object; navigated away)");
+
+test(t => {
+ const doc = document.implementation.createHTMLDocument();
+ assertOpenIsEffective(doc, 2);
+}, "document.open() removes the document's children (non-active document without an associated Window object; createHTMLDocument)");
+
+test(t => {
+ const doc = new DOMParser().parseFromString("", "text/html");
+ assertOpenIsEffective(doc, 1);
+}, "document.open() removes the document's children (non-active document without an associated Window object; DOMParser)");
+
+async_test(t => {
+ const xhr = new XMLHttpRequest();
+ xhr.onload = t.step_func_done(() => {
+ assert_equals(xhr.status, 200);
+ assertOpenIsEffective(xhr.responseXML, 2);
+ });
+ xhr.responseType = "document";
+ xhr.open("GET", "resources/dummy.html");
+ xhr.send();
+}, "document.open() removes the document's children (non-active document without an associated Window object; XMLHttpRequest)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js
new file mode 100644
index 0000000000..b20c3e3f31
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-origin.sub.window.js
@@ -0,0 +1,117 @@
+document.domain = "{{host}}";
+
+// In many cases in this test, we want to delay execution of a piece of code so
+// that the entry settings object would be the top-level page. A microtask is
+// perfect for this purpose as it is executed in the "clean up after running
+// script" algorithm, which is generally called right after the callback.
+function setEntryToTopLevel(cb) {
+ Promise.resolve().then(cb);
+}
+
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframe.remove(); });
+ iframe.onload = t.step_func_done(() => {
+ // Since this is called as an event handler on an element of this window,
+ // the entry settings object is that of this browsing context.
+ assert_throws_dom(
+ "InvalidStateError",
+ iframe.contentWindow.DOMException,
+ () => {
+ iframe.contentDocument.open();
+ },
+ "opening an XML document should throw an InvalidStateError"
+ );
+ });
+ const frameURL = new URL("resources/bailout-order-xml-with-domain-frame.sub.xhtml", document.URL);
+ frameURL.port = "{{ports[http][1]}}";
+ iframe.src = frameURL.href;
+}, "document.open should throw an InvalidStateError with XML document even if it is cross-origin");
+
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframe.remove(); });
+ window.onCustomElementReady = t.step_func(() => {
+ window.onCustomElementReady = t.unreached_func("onCustomElementReady called again");
+ // Here, the entry settings object is still the iframe's, as the function
+ // is called from a custom element constructor in the iframe document.
+ // Delay execution in such a way that makes the entry settings object the
+ // top-level page's, but without delaying too much that the
+ // throw-on-dynamic-markup-insertion counter gets decremented (which is
+ // what this test tries to pit against the cross-origin document check).
+ //
+ // "Clean up after running script" is executed through the "construct" Web
+ // IDL algorithm in "create an element", called by "create an element for a
+ // token" in the parser.
+ setEntryToTopLevel(t.step_func_done(() => {
+ assert_throws_dom(
+ "InvalidStateError",
+ iframe.contentWindow.DOMException,
+ () => {
+ iframe.contentDocument.open();
+ },
+ "opening a document when the throw-on-dynamic-markup-insertion counter is incremented should throw an InvalidStateError"
+ );
+ }));
+ });
+ const frameURL = new URL("resources/bailout-order-custom-element-with-domain-frame.sub.html", document.URL);
+ frameURL.port = "{{ports[http][1]}}";
+ iframe.src = frameURL.href;
+}, "document.open should throw an InvalidStateError when the throw-on-dynamic-markup-insertion counter is incremented even if the document is cross-origin");
+
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframe.remove(); });
+ self.testSynchronousScript = t.step_func(() => {
+ // Here, the entry settings object is still the iframe's, as the function
+ // is synchronously called from a <script> element in the iframe's
+ // document.
+ //
+ // "Clean up after running script" is executed when the </script> tag is
+ // seen by the HTML parser.
+ setEntryToTopLevel(t.step_func_done(() => {
+ assert_throws_dom(
+ "SecurityError",
+ iframe.contentWindow.DOMException,
+ () => {
+ iframe.contentDocument.open();
+ },
+ "opening a same origin-domain (but not same origin) document should throw a SecurityError"
+ );
+ }));
+ });
+ const frameURL = new URL("resources/bailout-order-synchronous-script-with-domain-frame.sub.html", document.URL);
+ frameURL.port = "{{ports[http][1]}}";
+ iframe.src = frameURL.href;
+}, "document.open should throw a SecurityError with cross-origin document even when there is an active parser executing script");
+
+for (const ev of ["beforeunload", "pagehide", "unload"]) {
+ async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframe.remove(); });
+ iframe.addEventListener("load", t.step_func(() => {
+ iframe.contentWindow.addEventListener(ev, t.step_func(() => {
+ // Here, the entry settings object should be the top-level page's, as
+ // the callback context of this event listener is the incumbent
+ // settings object, which is the this page. However, due to a Chrome
+ // bug (https://crbug.com/606900), the entry settings object may be
+ // mis-set to the iframe's.
+ //
+ // "Clean up after running script" is called in the task that
+ // navigates.
+ setEntryToTopLevel(t.step_func_done(() => {
+ assert_throws_dom(
+ "SecurityError",
+ iframe.contentWindow.DOMException,
+ () => {
+ iframe.contentDocument.open();
+ },
+ "opening a same origin-domain (but not same origin) document should throw a SecurityError"
+ );
+ }));
+ }));
+ iframe.src = "about:blank";
+ }), { once: true });
+ iframe.src = "http://{{host}}:{{ports[http][1]}}/common/domain-setter.sub.html";
+ }, `document.open should throw a SecurityError with cross-origin document even when the ignore-opens-during-unload counter is greater than 0 (during ${ev} event)`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js
new file mode 100644
index 0000000000..45a67f925b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-exception-vs-return-xml.window.js
@@ -0,0 +1,26 @@
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframe.remove(); });
+ self.testSynchronousScript = t.step_func_done(() => {
+ assert_throws_dom("InvalidStateError", iframe.contentWindow.DOMException, () => {
+ iframe.contentDocument.open();
+ }, "opening an XML document should throw");
+ });
+ iframe.src = "resources/bailout-order-xml-with-synchronous-script-frame.xhtml";
+}, "document.open should throw an InvalidStateError with XML document even when there is an active parser executing script");
+
+for (const ev of ["beforeunload", "pagehide", "unload"]) {
+ async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframe.remove(); });
+ iframe.addEventListener("load", t.step_func(() => {
+ iframe.contentWindow.addEventListener(ev, t.step_func_done(() => {
+ assert_throws_dom("InvalidStateError", iframe.contentWindow.DOMException, () => {
+ iframe.contentDocument.open();
+ }, "opening an XML document should throw");
+ }));
+ iframe.src = "about:blank";
+ }), { once: true });
+ iframe.src = "/common/dummy.xhtml";
+ }, `document.open should throw an InvalidStateError with XML document even when the ignore-opens-during-unload counter is greater than 0 (during ${ev} event)`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js
new file mode 100644
index 0000000000..98ffba20a1
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-ignore-opens-during-unload.window.js
@@ -0,0 +1,18 @@
+// META: script=resources/document-open-side-effects.js
+
+for (const ev of ["unload", "beforeunload", "pagehide"]) {
+ async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/blank.html";
+ iframe.onload = t.step_func(() => {
+ iframe.contentWindow.addEventListener(ev, t.step_func_done(() => {
+ const origURL = iframe.contentDocument.URL;
+ assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`);
+ assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
+ assertOpenHasNoSideEffects(iframe.contentDocument, origURL, `ignore-opens-during-unload counter is greater than 0 during ${ev} event`);
+ }));
+ iframe.src = "about:blank";
+ });
+ }, `document.open bailout should not have any side effects (ignore-opens-during-unload is greater than 0 during ${ev} event)`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js
new file mode 100644
index 0000000000..f5edd7aed9
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-same-origin-domain.sub.window.js
@@ -0,0 +1,14 @@
+// META: script=/html/resources/common.js
+// META: script=resources/document-open-side-effects.js
+
+document.domain = "{{host}}";
+
+testInIFrame("http://{{host}}:{{ports[http][1]}}/common/domain-setter.sub.html", (ctx) => {
+ const iframe = ctx.iframes[0];
+ const origURL = iframe.contentDocument.URL;
+ assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "same origin-domain (but not same origin) document");
+ assert_throws_dom("SecurityError", iframe.contentWindow.DOMException, () => {
+ ctx.iframes[0].contentDocument.open();
+ }, "document.open() should throw a SecurityError on a same origin-domain (but not same origin) document");
+ assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "same origin-domain (but not same origin) document");
+}, "document.open bailout should not have any side effects (same origin-domain (but not same origin) document)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js
new file mode 100644
index 0000000000..fb26c70a9c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-synchronous-script.window.js
@@ -0,0 +1,19 @@
+// META: script=resources/document-open-side-effects.js
+
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ self.testSynchronousScript = t.step_func(() => {
+ // Here, the entry settings object is still the iframe's. Delay it in such
+ // a way that makes the entry settings object the top-level page's, but
+ // without delaying too much that the parser becomes inactive. A microtask
+ // is perfect as it's executed in "clean up after running script".
+ Promise.resolve().then(t.step_func_done(() => {
+ const origURL = iframe.contentDocument.URL;
+ assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "active parser whose script nesting level is greater than 0");
+ assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
+ assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "active parser whose script nesting level is greater than 0");
+ }));
+ });
+ iframe.src = "resources/bailout-order-synchronous-script-frame.html";
+}, "document.open bailout should not have any side effects (active parser whose script nesting level is greater than 0)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js
new file mode 100644
index 0000000000..bbfc015c68
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/bailout-side-effects-xml.window.js
@@ -0,0 +1,20 @@
+// META: script=resources/document-open-side-effects.js
+
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/dummy.xhtml";
+ iframe.onload = t.step_func_done(() => {
+ const origURL = iframe.contentDocument.URL;
+ assertDocumentIsReadyForSideEffectsTest(iframe.contentDocument, "XML document");
+ assert_throws_dom(
+ "InvalidStateError",
+ iframe.contentWindow.DOMException,
+ () => {
+ iframe.contentDocument.open();
+ },
+ "document.open() should throw on XML documents"
+ );
+ assertOpenHasNoSideEffects(iframe.contentDocument, origURL, "XML document");
+ });
+}, "document.open bailout should not have any side effects (XML document)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js
new file mode 100644
index 0000000000..1e2f891c17
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/beforeunload.window.js
@@ -0,0 +1,18 @@
+// In an earlier version of the HTML Standard, document open steps had "prompt
+// to unload document" as a step. Test that this no longer happens.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.src = "/common/blank.html";
+ frame.onload = t.step_func(() => {
+ frame.contentWindow.onbeforeunload = t.unreached_func("beforeunload should not be fired");
+ frame.contentDocument.open();
+ t.step_timeout(t.step_func_done(() => {
+ // If the beforeunload event has still not fired by this point, we
+ // consider the test a success. `frame.remove()` above will allow the
+ // `load` event to be fired on the top-level Window, thus unblocking
+ // testharness.
+ }), 500);
+ });
+}, "document.open() should not fire a beforeunload event");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js
new file mode 100644
index 0000000000..3809c2e081
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/crbug-583445-regression.window.js
@@ -0,0 +1,127 @@
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/common/dispatcher/dispatcher.js
+//
+// This is a regression test for crbug.com/583445. It checks an obscure bug in
+// Chromium's handling of `document.open()` whereby the URL change would affect
+// the document's origin after a javascript navigation.
+//
+// See also dcheng@'s comments on the original code review in which he
+// introduced the precursor to this test:
+// https://codereview.chromium.org/1675473002.
+
+function nextMessage() {
+ return new Promise((resolve) => {
+ window.addEventListener("message", (e) => { resolve(e.data); }, {
+ once: true
+ });
+ });
+}
+
+promise_test(async (t) => {
+ // Embed a cross-origin frame A and set up remote code execution.
+ const iframeA = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { iframeA.remove(); });
+
+ const uuidA = token();
+ iframeA.src = remoteExecutorUrl(uuidA, { host: get_host_info().REMOTE_HOST });
+ const ctxA = new RemoteContext(uuidA);
+
+ // Frame A embeds a cross-origin frame B, which is same-origin with the
+ // top-level frame. Frame B is the center of this test: it is where we will
+ // verify that a bug does not grant it UXSS in frame A.
+ //
+ // Though we could reach into `iframeA.frames[0]` to get a proxy to frame B
+ // and use `setTimeout()` like below to execute code inside it, we set up
+ // remote code execution using `dispatcher.js` for better ergonomics.
+ const uuidB = token();
+ await ctxA.execute_script((url) => {
+ const iframeB = document.createElement("iframe");
+ iframeB.src = url;
+ document.body.appendChild(iframeB);
+ }, [remoteExecutorUrl(uuidB).href]);
+
+ // Start listening for a message, which will come as a result of executing
+ // the code below in frame B.
+ const message = nextMessage();
+
+ const ctxB = new RemoteContext(uuidB);
+ await ctxB.execute_script(() => {
+ // Frame B embeds an `about:blank` frame C.
+ const iframeC = document.body.appendChild(document.createElement("iframe"));
+
+ // We wish to execute code inside frame C, but it is important to this test
+ // that its URL remain `about:blank`, so we cannot use `dispatcher.js`.
+ // Instead we rely on `setTimeout()`.
+ //
+ // We use `setTimeout(string, ...)` instead of `setTimeout(function, ...)`
+ // as the given script executes against the target window's global object
+ // and does not capture any local variables.
+ //
+ // In order to have nice syntax highlighting and avoid quote-escaping hell,
+ // we use a trick employed by `dispatcher.js`. We rely on the fact that
+ // functions in JS have a stringifier that returns their source code. Thus
+ // `"(" + func + ")()"` is a string that executes `func()` when evaluated.
+ iframeC.contentWindow.setTimeout("(" + (() => {
+ // This executes in frame C.
+
+ // Frame C calls `document.open()` on its parent, which results in B's
+ // URL being set to `about:blank` (C's URL).
+ //
+ // However, just before `document.open()` is called, B schedules a
+ // self-navigation to a `javascript:` URL. This will occur after
+ // `document.open()`, so the document will navigate from `about:blank` to
+ // the new URL.
+ //
+ // This should not result in B's origin changing, so B should remain
+ // same-origin with the top-level frame.
+ //
+ // Due to crbug.com/583445, this used to behave wrongly in Chromium. The
+ // navigation code incorrectly assumed that B's origin should be inherited
+ // from its parent A because B's URL was `about:blank`.
+ //
+ // It is important to schedule this from within the child, as this
+ // guarantees that `document.open()` will be called before the navigation.
+ // A previous version of this test scheduled this from within frame B
+ // right after scheduling the call to `document.open()`, but that ran the
+ // risk of races depending on which timeout fired first.
+ parent.window.setTimeout("(" + (() => {
+ // This executes in frame B.
+
+ location = "javascript:(" + (() => {
+ /* This also executes in frame B.
+ *
+ * Note that because this whole function gets stuffed in a JS URL,
+ * single-line comments do not work, as they affect the following
+ * lines. */
+
+ let error;
+ try {
+ /* This will fail with a `SecurityError` if frame B is no longer
+ * same-origin with the top-level frame. */
+ top.window.testSameOrigin = true;
+ } catch (e) {
+ error = e;
+ }
+
+ top.postMessage({
+ error: error?.toString(),
+ }, "*");
+
+ }) + ")()";
+
+ }) + ")()", 0);
+
+ // This executes in frame C.
+ parent.document.open();
+
+ }) + ")()", 0);
+ });
+
+ // Await the message from frame B after its navigation.
+ const { error } = await message;
+ assert_equals(error, undefined, "error accessing top frame from frame B");
+ assert_true(window.testSameOrigin, "top frame testSameOrigin is mutated");
+
+}, "Regression test for crbug.com/583445");
+
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js
new file mode 100644
index 0000000000..1ad06b3d37
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/custom-element.window.js
@@ -0,0 +1,39 @@
+// The document open steps have:
+//
+// 2. If document's throw-on-dynamic-markup-insertion counter is greater than
+// 0, then throw an "InvalidStateError" DOMException.
+//
+// The throw-on-dynamic-markup-insertion counter is only incremented when the
+// parser creates a custom element, not when createElement is called. Test for
+// this.
+//
+// See: https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#document-open-steps
+
+const noError = Symbol("no error");
+let err = noError;
+
+class CustomElement extends HTMLElement {
+ constructor() {
+ super();
+ try {
+ assert_equals(document.open(), document);
+ } catch (e) {
+ err = e;
+ }
+ }
+}
+customElements.define("custom-element", CustomElement);
+
+test(t => {
+ err = noError;
+ document.createElement("custom-element");
+ assert_equals(err, noError);
+}, "document.open() works in custom element constructor for createElement()");
+
+test(t => {
+ err = noError;
+ document.write("<custom-element></custom-element>");
+ assert_throws_dom("InvalidStateError", () => {
+ throw err;
+ });
+}, "document.open() is forbidden in custom element constructor when creating element from parser");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html
new file mode 100644
index 0000000000..5596382f22
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document-open-cancels-javascript-url-navigation.html
@@ -0,0 +1,17 @@
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = t.step_func_done(() => assert_equals(i.contentDocument.body.innerText, "PASS"));
+
+ var i = document.createElement('iframe');
+ i.id ='i';
+ i.src = "javascript:'FAIL'";
+ document.body.appendChild(i);
+ i.contentDocument.open();
+ i.contentDocument.write("PASS")
+ i.contentDocument.close();
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml
new file mode 100644
index 0000000000..c02b3e4db5
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-01.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>document.open in XHTML</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#opening-the-input-stream"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom("INVALID_STATE_ERR", function() {
+ document.open();
+ }, "document.open in XHTML should throw an INVALID_STATE_ERR ");
+}, "document.open in XHTML");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html
new file mode 100644
index 0000000000..c7e67a0cf7
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-02.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>document.open with three arguments</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-open">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+function open() {
+ assert_unreached("The call should be redirected to the real window.open")
+}
+test(function(t) {
+ var w;
+ t.add_cleanup(function() {try {w.close()} catch(e) {}});
+ w = document.open("/resources/testharness.js", "", "");
+ assert_true(w instanceof w.Window, "Expected a window");
+}, "document.open should redirect to window.open when called with three arguments");
+
+test(function() {
+ var parser = new DOMParser();
+ var doc = parser.parseFromString("", "text/html");
+ assert_equals(doc.defaultView, null);
+ assert_throws_dom("INVALID_ACCESS_ERR", function() {
+ doc.open("/resources/testharness.js", "", "");
+ });
+}, "document.open should throw when it has no window and is called with three arguments");
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html
new file mode 100644
index 0000000000..a4b370cea4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03-frame.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script>
+onload = function() {
+ document.open();
+ document.close();
+ parent.report(window.setTimeout === setTimeout, true, "setTimeout");
+ parent.report(window === this, true, "this");
+ parent.done();
+}
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html
new file mode 100644
index 0000000000..e446d70219
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/document.open-03.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>document.open and no singleton replacement</title>
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-document-open">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var t = async_test();
+function report(actual, expected, message) {
+ t.step(function() {
+ assert_equals(actual, expected, message);
+ });
+}
+function done() {
+ t.done();
+}
+</script>
+<iframe src=document.open-03-frame.html></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js
new file mode 100644
index 0000000000..f0d133a532
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/encoding.window.js
@@ -0,0 +1,12 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ frame.src = "resources/encoding-frame.html";
+ frame.onload = t.step_func_done(t => {
+ // Using toLowerCase() to avoid an Edge bug
+ assert_equals(frame.contentDocument.characterSet.toLowerCase(), "shift_jis", "precondition");
+ assert_equals(frame.contentDocument.open(), frame.contentDocument);
+ assert_equals(frame.contentDocument.characterSet.toLowerCase(), "shift_jis", "actual test");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.characterSet.toLowerCase(), "shift_jis", "might as well");
+ });
+}, "doucment.open() and the document's encoding");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js
new file mode 100644
index 0000000000..df07124d81
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/event-listeners.window.js
@@ -0,0 +1,308 @@
+// Many of the active-related test cases in this file came from
+// active.window.js. However, we cannot test the "navigated away" non-active
+// case right now due to https://github.com/whatwg/html/issues/3997.
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ body = frame.contentDocument.body;
+ t.add_cleanup(() => frame.remove());
+ const div = body.appendChild(frame.contentDocument.createElement("div"));
+ div.addEventListener("click", t.unreached_func("element event listener not removed"));
+ frame.contentDocument.open();
+ div.click();
+ frame.contentDocument.close();
+}, "Standard event listeners are to be removed");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ body = frame.contentDocument.body;
+ t.add_cleanup(() => frame.remove());
+ frame.contentDocument.addEventListener("x", t.unreached_func("document event listener not removed"));
+ body.addEventListener("x", t.unreached_func("body event listener not removed"));
+ frame.contentDocument.open();
+ frame.contentDocument.dispatchEvent(new Event("x"));
+ body.dispatchEvent(new Event("x"));
+ frame.contentDocument.close();
+}, "Custom event listeners are to be removed");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ body = frame.contentDocument.body;
+ t.add_cleanup(() => frame.remove());
+ // Focus on the current window so that the frame's window is blurred.
+ window.focus();
+ assert_false(frame.contentDocument.hasFocus());
+ frame.contentWindow.addEventListener("focus", t.unreached_func("window event listener not removed"));
+ body.onfocus = t.unreached_func("body event listener not removed");
+ frame.contentDocument.open();
+ assert_equals(body.onfocus, null);
+ frame.contentWindow.focus();
+ frame.contentDocument.close();
+}, "Standard event listeners are to be removed from Window");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ const childFrame = frame.contentDocument.querySelector("iframe");
+ const childWin = childFrame.contentWindow;
+ const childDoc = childFrame.contentDocument;
+ const childBody = childDoc.body;
+
+ // Right now childDoc is still fully active.
+
+ frame.onload = t.step_func_done(() => {
+ // Focus on the current window so that the frame's window is blurred.
+ window.focus();
+ // Now childDoc is still active but no longer fully active.
+ childWin.addEventListener("focus", t.unreached_func("window event listener not removed"));
+ childBody.onfocus = t.unreached_func("body event listener not removed");
+
+ childDoc.open();
+ assert_equals(childBody.onfocus, null);
+
+ // Now try to fire the focus event two different ways.
+ childWin.focus();
+ const focusEvent = new FocusEvent("focus");
+ childWin.dispatchEvent(focusEvent);
+ childDoc.close();
+ });
+ frame.src = "/common/blank.html";
+ });
+ frame.src = "resources/page-with-frame.html";
+}, "Standard event listeners are to be removed from Window for an active but not fully active document");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ const win = frame.contentWindow;
+ const doc = frame.contentDocument;
+ const body = doc.body;
+
+ // Right now the frame is connected and it has an active document.
+ frame.remove();
+
+ win.addEventListener("focus", t.unreached_func("window event listener not removed"));
+ body.onfocus = t.unreached_func("body event listener not removed");
+ doc.open();
+ assert_equals(body.onfocus, null);
+
+ // Now try to fire the focus event two different ways.
+ win.focus();
+ const focusEvent = new FocusEvent("focus");
+ win.dispatchEvent(focusEvent);
+ doc.close();
+}, "Standard event listeners are to be removed from Window for a non-active document that is the associated Document of a Window (frame is removed)");
+
+test(t => {
+ let winHappened = 0;
+ const winListener = t.step_func(() => { winHappened++; });
+ window.addEventListener("focus", winListener);
+ t.add_cleanup(() => { window.removeEventListener("focus", winListener); });
+
+ let bodyHappened = 0;
+ const bodyListener = t.step_func(() => { bodyHappened++; });
+ document.body.onfocus = bodyListener;
+ t.add_cleanup(() => { document.body.onfocus = null; });
+
+ const doc = document.implementation.createHTMLDocument();
+ doc.open();
+
+ const focusEvent = new FocusEvent("focus");
+ window.dispatchEvent(focusEvent);
+
+ assert_equals(winHappened, 1);
+ assert_equals(bodyHappened, 1);
+}, "Standard event listeners are NOT to be removed from Window for a Window-less document (createHTMLDocument)");
+
+test(t => {
+ let winHappened = 0;
+ const winListener = t.step_func(() => { winHappened++; });
+ window.addEventListener("focus", winListener);
+ t.add_cleanup(() => { window.removeEventListener("focus", winListener); });
+
+ let bodyHappened = 0;
+ const bodyListener = t.step_func(() => { bodyHappened++; });
+ document.body.onfocus = bodyListener;
+ t.add_cleanup(() => { document.body.onfocus = null; });
+
+ const doc = new DOMParser().parseFromString("", "text/html");
+ doc.open();
+
+ const focusEvent = new FocusEvent("focus");
+ window.dispatchEvent(focusEvent);
+
+ assert_equals(winHappened, 1);
+ assert_equals(bodyHappened, 1);
+}, "Standard event listeners are NOT to be removed from Window for a Window-less document (DOMParser)");
+
+async_test(t => {
+ const xhr = new XMLHttpRequest();
+ xhr.onload = t.step_func_done(() => {
+ assert_equals(xhr.status, 200);
+ const doc = xhr.responseXML;
+
+ let winHappened = 0;
+ const winListener = t.step_func(() => { winHappened++; });
+ window.addEventListener("focus", winListener);
+ t.add_cleanup(() => { window.removeEventListener("focus", winListener); });
+
+ let bodyHappened = 0;
+ const bodyListener = t.step_func(() => { bodyHappened++; });
+ document.body.onfocus = bodyListener;
+ t.add_cleanup(() => { document.body.onfocus = null; });
+
+ doc.open();
+
+ const focusEvent = new FocusEvent("focus");
+ window.dispatchEvent(focusEvent);
+
+ assert_equals(winHappened, 1);
+ assert_equals(bodyHappened, 1);
+ });
+ xhr.responseType = "document";
+ xhr.open("GET", "resources/dummy.html");
+ xhr.send();
+}, "Standard event listeners are NOT to be removed from Window for a Window-less document (XMLHttpRequest)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.contentWindow.addEventListener("x", t.unreached_func("window event listener not removed"));
+ frame.contentDocument.open();
+ frame.contentWindow.dispatchEvent(new Event("x"));
+ frame.contentDocument.close();
+}, "Custom event listeners are to be removed from Window");
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ const childFrame = frame.contentDocument.querySelector("iframe");
+ const childDoc = childFrame.contentDocument;
+ const childWin = childFrame.contentWindow;
+
+ // Right now childDoc is still fully active.
+
+ frame.onload = t.step_func_done(() => {
+ // Now childDoc is still active but no longer fully active.
+ childWin.addEventListener("x", t.unreached_func("window event listener not removed"));
+ childDoc.open();
+ childWin.dispatchEvent(new Event("x"));
+ childDoc.close();
+ });
+ frame.src = "/common/blank.html";
+ });
+ frame.src = "resources/page-with-frame.html";
+}, "Custom event listeners are to be removed from Window for an active but not fully active document");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ const win = frame.contentWindow;
+ const doc = frame.contentDocument;
+
+ // Right now the frame is connected and it has an active document.
+ frame.remove();
+
+ win.addEventListener("x", t.unreached_func("window event listener not removed"));
+ doc.open();
+ win.dispatchEvent(new Event("x"));
+ doc.close();
+}, "Custom event listeners are to be removed from Window for a non-active document that is the associated Document of a Window (frame is removed)");
+
+test(t => {
+ const doc = document.implementation.createHTMLDocument();
+ let happened = false;
+ window.addEventListener("createHTMLDocumentTest", t.step_func(() => { happened = true; }));
+ doc.open();
+ window.dispatchEvent(new Event("createHTMLDocumentTest"));
+ assert_true(happened);
+}, "Custom event listeners are NOT to be removed from Window for a Window-less document (createHTMLDocument)");
+
+test(t => {
+ const doc = new DOMParser().parseFromString("", "text/html");
+ let happened = false;
+ window.addEventListener("DOMParserTest", t.step_func(() => { happened = true; }));
+ doc.open();
+ window.dispatchEvent(new Event("DOMParserTest"));
+ assert_true(happened);
+}, "Custom event listeners are NOT to be removed from Window for a Window-less document (DOMParser)");
+
+async_test(t => {
+ const xhr = new XMLHttpRequest();
+ xhr.onload = t.step_func_done(() => {
+ assert_equals(xhr.status, 200);
+ const doc = xhr.responseXML;
+ let happened = false;
+ window.addEventListener("XHRTest", t.step_func(() => { happened = true; }));
+ doc.open();
+ window.dispatchEvent(new Event("XHRTest"));
+ assert_true(happened);
+ });
+ xhr.responseType = "document";
+ xhr.open("GET", "resources/dummy.html");
+ xhr.send();
+}, "Custom event listeners are NOT to be removed from Window for a Window-less document (XMLHttpRequest)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ body = frame.contentDocument.body;
+ t.add_cleanup(() => frame.remove());
+ const div = body.appendChild(frame.contentDocument.createElement("div"));
+ div.onclick = t.unreached_func("element event listener not removed");
+ frame.contentDocument.open();
+ assert_equals(div.onclick, null);
+ const e = frame.contentDocument.createEvent("mouseevents")
+ e.initEvent("click", false, false);
+ div.dispatchEvent(e);
+ frame.contentDocument.close();
+}, "IDL attribute event handlers are to be deactivated");
+
+var thrower;
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ body = frame.contentDocument.body;
+ t.add_cleanup(() => frame.remove());
+ const div = body.appendChild(frame.contentDocument.createElement("div"));
+ thrower = t.step_func(() => { throw new Error('element event listener not removed'); });
+ div.setAttribute("onclick", "parent.thrower()");
+ assert_not_equals(div.onclick, null);
+ frame.contentDocument.open();
+ assert_equals(div.getAttribute("onclick"), "parent.thrower()");
+ assert_equals(div.onclick, null);
+ const e = frame.contentDocument.createEvent("mouseevents")
+ e.initEvent("click", false, false);
+ div.dispatchEvent(e);
+ frame.contentDocument.close();
+}, "Content attribute event handlers are to be deactivated");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ let once = false;
+ frame.contentDocument.addEventListener("x", () => {
+ frame.contentDocument.open();
+ once = true;
+ });
+ frame.contentDocument.addEventListener("x", t.unreached_func("second event listener not removed"));
+ frame.contentDocument.dispatchEvent(new Event("x"));
+ assert_true(once);
+ frame.contentDocument.close();
+}, "Event listeners are to be removed with immediate effect");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ shadow = frame.contentDocument.body.attachShadow({ mode: "closed" }),
+ shadowChild = shadow.appendChild(document.createElement("div")),
+ shadowShadow = shadowChild.attachShadow({ mode: "open" }),
+ nodes = [shadow, shadowChild, shadowShadow];
+ t.add_cleanup(() => frame.remove());
+ nodes.forEach(node => {
+ node.addEventListener("x", t.unreached_func(node + "'s event listener not removed"));
+ });
+ frame.contentDocument.open();
+ nodes.forEach(node => {
+ node.dispatchEvent(new Event("x"));
+ });
+ frame.contentDocument.close();
+}, "Event listeners are to be removed from shadow trees as well");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html
new file mode 100644
index 0000000000..7d03a885f0
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/form-control-state.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Writing out a document with form controls with values</title>
+<link rel="author" href="mailto:bzbarsky@mit.edu"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+function asyncHop(t, arg) {
+ return new Promise(res => t.step_timeout(res.bind(null, arg), 0));
+}
+
+function loadPromise(t, iframe) {
+ var p = new Promise(res =>
+ iframe.addEventListener("load", res.bind(null, iframe), { once: true }));
+ // We need to do one trip through the event loop to make sure we're
+ // not still under the load event firing when we start doing our
+ // document.open bits.
+ return p.then(asyncHop.bind(null, t));
+}
+
+async function createIframe(t) {
+ var i = document.createElement("iframe");
+ t.add_cleanup(() => i.remove());
+ var p = loadPromise(t, i);
+ document.body.appendChild(i);
+ return p;
+}
+
+async function replaceIframe(t, i, text) {
+ var p = loadPromise(t, i);
+ var doc = i.contentDocument;
+ doc.open();
+ doc.write(text);
+ doc.close();
+ return p;
+}
+
+promise_test(async function(t) {
+ var i = await createIframe(t);
+ var str = "<textarea>123</textarea>";
+ await replaceIframe(t, i, str);
+ i.contentDocument.querySelector("textarea").value = "abc";
+ await replaceIframe(t, i, str);
+ assert_equals(i.contentDocument.querySelector("textarea").value, "123");
+}, "textarea state");
+
+promise_test(async function(t) {
+ var i = await createIframe(t);
+ var str = "<input value='123'>";
+ await replaceIframe(t, i, str);
+ i.contentDocument.querySelector("input").value = "abc";
+ await replaceIframe(t, i, str);
+ assert_equals(i.contentDocument.querySelector("input").value, "123");
+}, "input state");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js
new file mode 100644
index 0000000000..7fb172a141
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history-state.window.js
@@ -0,0 +1,29 @@
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/blank.html";
+ iframe.onload = t.step_func_done(() => {
+ const win = iframe.contentWindow;
+ const doc = iframe.contentDocument;
+ assert_equals(win.history.state, null);
+ win.history.replaceState("state", "");
+ assert_equals(win.history.state, "state");
+ assert_equals(doc.open(), doc);
+ assert_equals(win.history.state, "state");
+ });
+}, "history.state is kept by document.open()");
+
+async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/blank.html";
+ iframe.onload = t.step_func_done(() => {
+ const win = iframe.contentWindow;
+ const doc = iframe.contentDocument;
+ assert_equals(win.history.state, null);
+ win.history.replaceState("state", "");
+ assert_equals(win.history.state, "state");
+ assert_equals(doc.open("", "replace"), doc);
+ assert_equals(win.history.state, "state");
+ });
+}, "history.state is kept by document.open() (with historical replace parameter set)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js
new file mode 100644
index 0000000000..0134da24f0
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/history.window.js
@@ -0,0 +1,29 @@
+// Historically, document.open() created an entry in the session history so
+// that the original page could be seen by going back. Test that this behavior
+// no longer occurs.
+//
+// This test uses window.open() for variety, as most other tests in this
+// directory use document.open(). An <iframe> would probably work also. We can
+// always add an <iframe>-based test later if it is deemed necessary.
+
+const t = async_test("document.open should not add an entry to the session history");
+
+const frameURL = new URL("resources/history-frame.html", document.URL).href;
+
+let origLength;
+window.onFrameLoaded = t.step_func(() => {
+ window.onFrameLoaded = t.unreached_func("onFrameLoaded should only be called once");
+ assert_equals(win.document.URL, frameURL);
+ assert_true(win.document.body.textContent.includes("Old"));
+ origLength = win.history.length;
+});
+window.onDocumentOpen = t.step_func_done(() => {
+ window.onDocumentOpen = t.unreached_func("onDocumentOpen should only be called once");
+ assert_equals(win.document.URL, frameURL);
+ assert_true(win.document.body.textContent.includes("New"));
+ assert_not_equals(origLength, undefined);
+ assert_equals(win.history.length, origLength);
+});
+
+const win = window.open(frameURL);
+t.add_cleanup(() => win.close());
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js
new file mode 100644
index 0000000000..43506a22a4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/ignore-opens-during-unload.window.js
@@ -0,0 +1,60 @@
+for (const [ev, target] of [
+ ["beforeunload", iframe => iframe.contentWindow],
+ ["pagehide", iframe => iframe.contentWindow],
+ ["unload", iframe => iframe.contentWindow],
+ ["visibilitychange", iframe => iframe.contentDocument],
+]) {
+ async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/blank.html";
+ iframe.onload = t.step_func(() => {
+ target(iframe).addEventListener(ev, t.step_func_done(() => {
+ assert_not_equals(iframe.contentDocument.childNodes.length, 0);
+ assert_equals(iframe.contentDocument.open(), iframe.contentDocument);
+ assert_not_equals(iframe.contentDocument.childNodes.length, 0);
+ }));
+ iframe.src = "about:blank";
+ });
+ }, `document.open should bail out when ignore-opens-during-unload is greater than 0 during ${ev} event (in top-level browsing context)`);
+
+ async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/blank.html?1";
+ iframe.onload = t.step_func(() => {
+ const doc = iframe.contentDocument;
+ const innerIframe = doc.body.appendChild(doc.createElement("iframe"));
+ innerIframe.src = "/common/blank.html?2";
+ innerIframe.onload = t.step_func(() => {
+ // Navigate the parent, listen on the child, and open() the parent.
+ target(innerIframe).addEventListener(ev, t.step_func_done(() => {
+ assert_not_equals(iframe.contentDocument.childNodes.length, 0);
+ iframe.contentDocument.open();
+ assert_not_equals(iframe.contentDocument.childNodes.length, 0);
+ }));
+ iframe.src = "about:blank";
+ });
+ });
+ }, `document.open should bail out when ignore-opens-during-unload is greater than 0 during ${ev} event (open(parent) while unloading parent and child)`);
+
+ async_test(t => {
+ const iframe = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "/common/blank.html?1";
+ iframe.onload = t.step_func(() => {
+ const doc = iframe.contentDocument;
+ const innerIframe = doc.body.appendChild(doc.createElement("iframe"));
+ innerIframe.src = "/common/blank.html?2";
+ innerIframe.onload = t.step_func(() => {
+ // Navigate the child, listen on the child, and open() the parent.
+ target(innerIframe).addEventListener(ev, t.step_func_done(() => {
+ assert_not_equals(iframe.contentDocument.childNodes.length, 0);
+ iframe.contentDocument.open();
+ assert_equals(iframe.contentDocument.childNodes.length, 0);
+ }));
+ innerIframe.src = "about:blank";
+ });
+ });
+ }, `document.open should bail out when ignore-opens-during-unload is greater than 0 during ${ev} event (open(parent) while unloading child only)`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html
new file mode 100644
index 0000000000..a3bdd86ee6
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/location-set-and-document-open.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<body>
+ <script>
+ var t = async_test("Location sets should cancel current navigation and prevent later document.open() from doing anything");
+
+ var finishTest = t.step_func_done(function() {
+ assert_equals(frames[0].document.body.textContent, "PASS",
+ "Should not have FAIL in our textContent");
+ });
+
+ t.step(function() {
+ var i = document.createElement("iframe");
+ i.srcdoc = `
+ <script>
+ var blob = new Blob(["PASS"], { type: "text/html" });
+ var url = URL.createObjectURL(blob);
+ location.href = url;
+ frameElement.onload = parent.finishTest;
+ document.open();
+ document.write("FAIL");
+ document.close();
+ <\/script>`;
+ document.body.appendChild(i);
+ });
+
+ </script>
+</body>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js
new file mode 100644
index 0000000000..4efbb863c6
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-events.window.js
@@ -0,0 +1,22 @@
+// In an ideal world this test would eventually be obsolete due to mutation events disappearing. Or
+// would have to change to account for mutation events not firing synchronously. Neither seems
+// realistic to the author though.
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ frame.contentWindow.addEventListener("DOMNodeInserted", t.unreached_func());
+ frame.contentWindow.addEventListener("DOMNodeInserted", t.unreached_func(), true);
+ frame.contentWindow.addEventListener("DOMNodeInsertedIntoDocument", t.unreached_func(), true);
+ frame.contentWindow.addEventListener("DOMNodeRemoved", t.unreached_func());
+ frame.contentWindow.addEventListener("DOMNodeRemoved", t.unreached_func(), true);
+ frame.contentWindow.addEventListener("DOMNodeRemovedFromDocument", t.unreached_func(), true);
+ frame.contentWindow.addEventListener("DOMSubtreeModified", t.unreached_func());
+ frame.contentWindow.addEventListener("DOMSubtreeModified", t.unreached_func(), true);
+ assert_equals(frame.contentDocument.documentElement.localName, "html");
+ assert_equals(frame.contentDocument.open(), frame.contentDocument);
+ assert_equals(frame.contentDocument.documentElement, null);
+ frame.contentDocument.write("<div>heya</div>");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.documentElement.localName, "html");
+ frame.remove();
+}, "document.open(), the HTML parser, and mutation events");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js
new file mode 100644
index 0000000000..34e73146a9
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/mutation-observer.window.js
@@ -0,0 +1,19 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { frame.remove(); });
+ const originalHTMLElement = frame.contentDocument.documentElement;
+ assert_equals(originalHTMLElement.localName, "html");
+ const observer = new frame.contentWindow.MutationObserver(t.step_func_done(records => {
+ // Even though we passed `subtree: true` to observer.observe, due to the
+ // fact that "replace all" algorithm removes children with the "suppress
+ // observers flag" set, we still only get the html element as the sole
+ // removed node.
+ assert_equals(records.length, 1);
+ assert_equals(records[0].type, "childList");
+ assert_equals(records[0].target, frame.contentDocument);
+ assert_array_equals(records[0].addedNodes, []);
+ assert_array_equals(records[0].removedNodes, [originalHTMLElement]);
+ }));
+ observer.observe(frame.contentDocument, { childList: true, subtree: true });
+ assert_equals(frame.contentDocument.open(), frame.contentDocument);
+}, "document.open() should inform mutation observer of node removal");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js
new file mode 100644
index 0000000000..d4a9296fca
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/no-new-global.window.js
@@ -0,0 +1,57 @@
+// In an earlier version of the HTML Standard, document open steps created a
+// new JavaScript realm and migrated the existing objects to use the new realm.
+// Test that this no longer happens.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ // Ensure a load event gets dispatched to unblock testharness
+ t.add_cleanup(() => frame.remove());
+ frame.src = "resources/global-variables-frame.html";
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentWindow.hey, "You", "precondition");
+ frame.contentDocument.open();
+ assert_equals(frame.contentWindow.hey, "You", "actual check");
+ });
+}, "Obtaining a variable from a global whose document had open() invoked");
+
+function testIdentity(desc, frameToObject, frameToConstructor) {
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ // Ensure a load event gets dispatched to unblock testharness
+ t.add_cleanup(() => frame.remove());
+ frame.src = "/common/blank.html";
+ frame.onload = t.step_func_done(() => {
+ const obj = frameToObject(frame);
+ frame.contentDocument.open();
+ assert_equals(frameToObject(frame), obj);
+ });
+ }, `${desc} maintains object identity through open()`);
+
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ // Ensure a load event gets dispatched to unblock testharness
+ t.add_cleanup(() => frame.remove());
+ frame.src = "/common/blank.html";
+ frame.onload = t.step_func_done(() => {
+ const obj = frameToObject(frame);
+ const origProto = Object.getPrototypeOf(obj);
+ const origCtor = frameToConstructor(frame);
+ const sym = Symbol();
+ obj[sym] = "foo";
+ frame.contentDocument.open();
+ assert_equals(frameToObject(frame)[sym], "foo");
+ assert_true(frameToObject(frame) instanceof origCtor);
+ assert_equals(Object.getPrototypeOf(frameToObject(frame)), origProto);
+ assert_equals(frameToConstructor(frame), origCtor);
+ });
+ }, `${desc} maintains its prototype and properties through open()`);
+}
+
+testIdentity("Document", frame => frame.contentDocument, frame => frame.contentWindow.Document);
+testIdentity("WindowProxy", frame => frame.contentWindow, frame => frame.contentWindow.Window);
+testIdentity("BarProp", frame => frame.contentWindow.locationbar, frame => frame.contentWindow.BarProp);
+testIdentity("History", frame => frame.contentWindow.history, frame => frame.contentWindow.History);
+testIdentity("localStorage", frame => frame.contentWindow.localStorage, frame => frame.contentWindow.Storage);
+testIdentity("Location", frame => frame.contentWindow.location, frame => frame.contentWindow.Location);
+testIdentity("sessionStorage", frame => frame.contentWindow.sessionStorage, frame => frame.contentWindow.Storage);
+testIdentity("Navigator", frame => frame.contentWindow.navigator, frame => frame.contentWindow.Navigator);
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html
new file mode 100644
index 0000000000..118be71af1
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-basic.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>Origin check in document.open() - Basic usage</title>
+<link rel="author" title="Jochen Eisinger" href="mailto:jochen@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#opening-the-input-stream">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/resources/common.js"></script>
+<body>
+<script>
+testInIFrame(undefined, (ctx) => {
+ try {
+ ctx.iframes[0].contentDocument.open();
+ } catch (e) {
+ assert_unreached("Opening a same origin document throws");
+ }
+}, "It should be possible to open same origin documents.");
+
+testInIFrame(undefined, (ctx) => {
+ try {
+ ctx.iframes[0].contentDocument.write("");
+ } catch (e) {
+ assert_unreached("Implicitly opening a same origin document throws");
+ }
+}, "It should be possible to implicitly open same origin documents.");
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html
new file mode 100644
index 0000000000..ba4ef3bae8
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/origin-check-in-document-open-same-origin-domain.sub.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>Origin check in document.open() - same origin-domain (but not same origin) documents</title>
+<link rel="author" title="Jochen Eisinger" href="mailto:jochen@chromium.org">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#opening-the-input-stream">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/resources/common.js"></script>
+<body>
+<script>
+testInIFrame("http://{{host}}:{{ports[http][1]}}/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html", (ctx) => {
+ document.domain = document.domain;
+ let doc = ctx.iframes[0].contentDocument;
+ let constructor = ctx.iframes[0].contentWindow.DOMException;
+ assert_throws_dom("SecurityError", constructor, doc.open.bind(doc), "Opening a same origin-domain (but not same origin) document doesn't throw.");
+}, "It should not be possible to open same origin-domain (but not same origin) documents.");
+
+testInIFrame("http://{{host}}:{{ports[http][1]}}/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html", (ctx) => {
+ document.domain = document.domain;
+ let doc = ctx.iframes[0].contentDocument;
+ let constructor = ctx.iframes[0].contentWindow.DOMException;
+ assert_throws_dom("SecurityError", constructor, doc.write.bind(doc, ""), "Implicitly opening a same origin-domain (but not same origin) document doesn't throw.");
+}, "It should not be possible to implicitly open same origin-domain (but not same origin) documents.");
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js
new file mode 100644
index 0000000000..0ff0bb9944
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/quirks.window.js
@@ -0,0 +1,74 @@
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.contentDocument.close());
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+ frame.contentDocument.open();
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+}, "document.open() sets document to no-quirks mode (write no doctype)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.contentDocument.close());
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+ frame.contentDocument.open();
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.write("<!doctype html public");
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.write(" \"-//IETF//DTD HTML 3//\"");
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.write(">");
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+}, "document.open() sets document to no-quirks mode (write old doctype)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.contentDocument.close());
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+ frame.contentDocument.open();
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.write("<!doctype html");
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.write(">");
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+}, "document.open() sets document to no-quirks mode (write new doctype)");
+
+// This tests the document.open() call in fact sets the document to no-quirks
+// mode, not limited-quirks mode. It is derived from
+// quirks/blocks-ignore-line-height.html in WPT, as there is no direct way to
+// distinguish between a no-quirks document and a limited-quirks document. It
+// assumes that the user agent passes the linked test, which at the time of
+// writing is all major web browsers.
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.contentDocument.close());
+ assert_equals(frame.contentDocument.compatMode, "BackCompat");
+ frame.contentDocument.open();
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+
+ // Create the DOM tree manually rather than going through document.write() to
+ // bypass the parser, which resets the document mode.
+ const html = frame.contentDocument.appendChild(frame.contentDocument.createElement("html"));
+ const body = html.appendChild(frame.contentDocument.createElement("body"));
+ assert_equals(frame.contentDocument.body, body);
+ body.innerHTML = `
+ <style>#ref { display:block }</style>
+ <div id=test><font size=1>x</font></div>
+ <font id=ref size=1>x</font>
+ <div id=s_ref>x</div>
+ `;
+ assert_equals(frame.contentDocument.compatMode, "CSS1Compat");
+
+ const idTest = frame.contentDocument.getElementById("test");
+ const idRef = frame.contentDocument.getElementById("ref");
+ const idSRef = frame.contentDocument.getElementById("s_ref");
+ assert_equals(frame.contentWindow.getComputedStyle(idTest).height,
+ frame.contentWindow.getComputedStyle(idSRef).height);
+ assert_not_equals(frame.contentWindow.getComputedStyle(idTest).height,
+ frame.contentWindow.getComputedStyle(idRef).height);
+}, "document.open() sets document to no-quirks mode, not limited-quirks mode");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js
new file mode 100644
index 0000000000..729a958700
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/readiness.window.js
@@ -0,0 +1,25 @@
+// This tests the behavior of dynamic markup insertion APIs with a document's
+// readiness.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { frame.remove(); });
+ frame.src = "/common/blank.html";
+ frame.onload = t.step_func_done(() => {
+ const states = [];
+ frame.contentDocument.onreadystatechange = t.step_func(() => {
+ states.push(frame.contentDocument.readyState);
+ });
+ assert_equals(frame.contentDocument.readyState, "complete");
+ assert_array_equals(states, []);
+
+ // When open() is called, it first removes the event listeners and handlers
+ // from all nodes in the DOM tree. Then, after a new parser is created and
+ // initialized, it changes the current document readiness to "loading".
+ // However, because all event listeners are removed, we cannot observe the
+ // readystatechange event fired for "loading" inside open().
+ frame.contentDocument.open();
+ assert_equals(frame.contentDocument.readyState, "loading");
+ assert_array_equals(states, []);
+ });
+}, "document.open() and readiness");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js
new file mode 100644
index 0000000000..279020f64d
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/reload.window.js
@@ -0,0 +1,71 @@
+// This test tests for the nonexistence of a reload override buffer, which is
+// used in a previous version of the HTML Standard to make reloads of a
+// document.open()'d document load the written-to document rather than doing an
+// actual reload of the document's URL.
+//
+// This test has a somewhat interesting structure compared to the other tests
+// in this directory. It eschews the <iframe> structure used by other tests,
+// since when the child frame is reloaded it would adopt the URL of the test
+// page (the responsible document of the entry settings object), and the spec
+// forbids navigation in nested browsing contexts to the same URL as their
+// parent. To work around that, we use window.open() which does not suffer from
+// that restriction.
+//
+// In any case, this test as the caller of `document.open()` would be used both
+// as the test file and as part of the test file. The `if (window.name !==
+// "opened-dummy-window")` condition controls what role this file plays.
+
+if (window.name !== "opened-dummy-window") {
+ async_test(t => {
+ const testURL = document.URL;
+ const dummyURL = new URL("resources/dummy.html", document.URL).href;
+
+ // 1. Open an auxiliary window.
+ const win = window.open("resources/dummy.html", "opened-dummy-window");
+ t.add_cleanup(() => { win.close(); });
+
+ win.addEventListener("load", t.step_func(() => {
+ // The timeout seems to be necessary for Firefox, which when `load` is
+ // called may still have an active parser.
+ t.step_timeout(() => {
+ const doc = win.document;
+ assert_true(doc.body.textContent.includes("Dummy"), "precondition");
+ assert_equals(doc.URL, dummyURL, "precondition");
+
+ window.onChildLoad = t.step_func(message => {
+ // 3. The dynamically overwritten content will trigger this function,
+ // which puts in place the actual test.
+
+ assert_equals(message, "Written", "script on written page is executed");
+ assert_true(win.document.body.textContent.includes("Content"), "page is written to");
+ assert_equals(win.document.URL, testURL, "postcondition: after document.write()");
+ assert_equals(win.document, doc, "document.open should not change the document object");
+ window.onChildLoad = t.step_func_done(message => {
+ // 6. This function should be called from the if (opener) branch of
+ // this file. It would throw an assertion error if the overwritten
+ // content was executed instead.
+ assert_equals(message, "Done!", "actual test");
+ assert_true(win.document.body.textContent.includes("Back to the test"), "test is reloaded");
+ assert_equals(win.document.URL, testURL, "postcondition: after reload");
+ assert_not_equals(win.document, doc, "reload should change the document object");
+ });
+
+ // 4. Reload the pop-up window. Because of the doc.open() call, this
+ // pop-up window will reload to the same URL as this test itself.
+ win.location.reload();
+ });
+
+ // 2. When it is loaded, dynamically overwrite its content.
+ assert_equals(doc.open(), doc);
+ assert_equals(doc.URL, testURL, "postcondition: after document.open()");
+ doc.write("<p>Content</p><script>opener.onChildLoad('Written');</script>");
+ doc.close();
+ }, 100);
+ }), { once: true });
+ }, "Reloading a document.open()'d page should reload the URL of the entry realm's responsible document");
+} else {
+ document.write("<p>Back to the test</p>");
+ // 5. Since this window is window.open()'d, opener refers to the test window.
+ // Inform the opener that reload succeeded.
+ opener.onChildLoad("Done!");
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js
new file mode 100644
index 0000000000..7442bc4925
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/remove-initial-about-blankness.window.js
@@ -0,0 +1,65 @@
+// This tests the issues discussed in https://github.com/whatwg/html/issues/4299
+// and fixed in https://github.com/whatwg/html/pull/6567.
+
+// Note: because browsers do not interoperate on the spec's notion of window reuse (see e.g. https://crbug.com/778318)
+// we pick a specific interoperable test case, which is "currently on initial about:blank, but loading something".
+
+async_test(t => {
+ const iframe = document.createElement("iframe");
+
+ // We can't just leave it at the actual initial about:blank because of the interop issues mentioned above.
+ // So put it in the "currently on initial about:blank, but loading something" state which interoperably does Window
+ // reuse.
+ iframe.src = "/common/blank.html";
+
+ // Create the Window object. It will be for the initial about:blank since the load of /common/blank.html hasn't
+ // completed.
+ document.body.append(iframe);
+
+ // Store a string on that Window object so we can later test if it's reused.
+ iframe.contentWindow.persistedString = "Hello world!";
+
+ // This will reset the initial about:blank-ness. But, it will also cancel any ongoing loads.
+ iframe.contentDocument.open();
+
+ // So, re-start the load of /common/blank.html.
+ iframe.src = "/common/blank.html";
+
+ // When the load finally happens, will it reuse the Window object or not?
+ // Because document.open() resets the initial about:blank-ness, it will *not* reuse the Window object.
+ // The point of the test is to assert that.
+ iframe.addEventListener("load", t.step_func_done(() => {
+ assert_equals(
+ iframe.contentDocument.URL,
+ iframe.src,
+ "Prerequisite check: we are getting the right load event"
+ );
+
+ assert_equals(iframe.contentWindow.persistedString, undefined);
+ }), { once: true });
+}, "document.open() removes the initial about:blank-ness of the document");
+
+// This test is redundant with others in WPT but it's intended to make it clear that document.open() is the
+// distinguishing factor. It does the same exact thing but without document.open() and with the resulting final assert
+// flipped.
+async_test(t => {
+ const iframe = document.createElement("iframe");
+ iframe.src = "/common/blank.html";
+ document.body.append(iframe);
+
+ iframe.contentWindow.persistedString = "Hello world!";
+
+ // NO document.open() call.
+
+ iframe.src = "/common/blank.html";
+
+ iframe.addEventListener("load", t.step_func_done(() => {
+ assert_equals(
+ iframe.contentDocument.URL,
+ iframe.src,
+ "Prerequisite check: we are getting the right load event"
+ );
+
+ assert_equals(iframe.contentWindow.persistedString, "Hello world!");
+ }), { once: true });
+}, "Double-check: without document.open(), Window reuse indeed happens");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html
new file mode 100644
index 0000000000..d5535630be
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-async-frame.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<p>Text</p>
+<script>
+window.stop();
+parent.step_timeout(() => {
+ document.open();
+ parent.handlers.afterOpenAsync();
+}, 10);
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html
new file mode 100644
index 0000000000..d9ec23590b
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/aborted-parser-frame.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<p>Text</p>
+<script>
+window.stop();
+document.open();
+parent.handlers.afterOpen();
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html
new file mode 100644
index 0000000000..4de97e8ed1
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-custom-element-with-domain-frame.sub.html
@@ -0,0 +1,13 @@
+<p>Text</p>
+<script>
+document.domain = "{{host}}";
+
+class CustomElement extends HTMLElement {
+ constructor() {
+ super();
+ parent.onCustomElementReady();
+ }
+}
+customElements.define("custom-element", CustomElement);
+</script>
+<custom-element></custom-element>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html
new file mode 100644
index 0000000000..632b2934ac
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-frame.html
@@ -0,0 +1,4 @@
+<p>Text</p>
+<script>
+parent.testSynchronousScript();
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html
new file mode 100644
index 0000000000..7ca7b5f44c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-synchronous-script-with-domain-frame.sub.html
@@ -0,0 +1,5 @@
+<p>Text</p>
+<script>
+document.domain = "{{host}}";
+parent.testSynchronousScript();
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml
new file mode 100644
index 0000000000..b054c0fe3a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-domain-frame.sub.xhtml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head><title>XHTML document with domain set</title></head>
+ <body>
+ <p>Text</p>
+ <script>
+ document.domain = "{{host}}";
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml
new file mode 100644
index 0000000000..00fc71eccf
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/bailout-order-xml-with-synchronous-script-frame.xhtml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head><title>XHTML document with hook to run script from a script tag</title></head>
+ <body>
+ <p>Text</p>
+ <script>
+ parent.testSynchronousScript();
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js
new file mode 100644
index 0000000000..7cb86dcba0
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/document-open-side-effects.js
@@ -0,0 +1,8 @@
+function assertDocumentIsReadyForSideEffectsTest(doc, description) {
+ assert_not_equals(doc.childNodes.length, 0, `document should not be empty before side effects test (${description})`);
+}
+
+function assertOpenHasNoSideEffects(doc, originalURL, description) {
+ assert_not_equals(doc.childNodes.length, 0, `document nodes should not be cleared (${description})`);
+ assert_equals(doc.URL, originalURL, `The original URL should be kept (${description})`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html
new file mode 100644
index 0000000000..a092f4e2d7
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/dummy.html
@@ -0,0 +1,2 @@
+<!-- Like /common/blank.html, but with some content in it. -->
+<p>Dummy</p>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html
new file mode 100644
index 0000000000..843c3a2c79
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/encoding-frame.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<meta charset=ms932>
+<p>Encoded in Shift_JIS.</p>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html
new file mode 100644
index 0000000000..0fe189914c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/global-variables-frame.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<script>
+hey = "You";
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html
new file mode 100644
index 0000000000..2404105b09
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/history-frame.html
@@ -0,0 +1,20 @@
+<script>
+function queueTest() {
+ // The timeout is necessary to avoid the parser still being active when
+ // `document.open()` is called and becoming a no-op.
+ //
+ // We also cannot use setTimeout(..., 0), as the parser is terminated in a
+ // task with DOM manipulation task source while the timeout is run in a task
+ // on the timer task source. The order is therefore not guaranteed. Let's
+ // play it safer and use some actual timeout.
+ setTimeout(() => {
+ document.open();
+ document.write("<p>New content</p>");
+ document.close();
+ opener.onDocumentOpen();
+ }, 200);
+}
+</script>
+<body onload="opener.onFrameLoaded(); queueTest();">
+<p>Old content</p>
+</body>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py
new file mode 100644
index 0000000000..161a34b6b5
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/http-refresh.py
@@ -0,0 +1,5 @@
+from wptserve.utils import isomorphic_encode
+
+def main(request, response):
+ time = isomorphic_encode(request.url_parts.query) if request.url_parts.query else b'0'
+ return 200, [(b'Refresh', time), (b'Content-Type', b"text/html")], b''
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py
new file mode 100644
index 0000000000..2dfbab6e76
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/meta-refresh.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ time = request.url_parts.query if request.url_parts.query else u'0'
+ return 200, [[b'Content-Type', b'text/html']], u'<meta http-equiv=refresh content=%s>' % time
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html
new file mode 100644
index 0000000000..a1ab01e072
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/page-with-frame.html
@@ -0,0 +1 @@
+<iframe src="/common/blank.html"></iframe>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html
new file mode 100644
index 0000000000..a92a7ae39f
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/set-document-domain.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<script>
+document.domain = document.domain;
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py
new file mode 100644
index 0000000000..fced22aa26
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py
@@ -0,0 +1,8 @@
+import time
+from base64 import decodebytes
+
+png_response = decodebytes(b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==')
+
+def main(request, response):
+ time.sleep(2)
+ return 200, [], png_response
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html
new file mode 100644
index 0000000000..bd78d8ee52
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-incumbent-frame.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<script>
+window.callDocumentMethod = methodName => document[methodName]();
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html
new file mode 100644
index 0000000000..b2c050768c
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-entry-document-timer-frame.html
@@ -0,0 +1,3 @@
+<script>
+setTimeout(parent.timerTest, 10);
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html
new file mode 100644
index 0000000000..be483ff0ae
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/url-frame.html
@@ -0,0 +1,9 @@
+<script>
+onload = () => {
+ const beforeURL = document.URL;
+ document.open();
+ const afterURL = document.URL;
+ document.close();
+ parent.testDone(beforeURL, afterURL);
+}
+</script>
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js
new file mode 100644
index 0000000000..887adcb739
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.js
@@ -0,0 +1,106 @@
+// An older version of the HTML Standard mandated that document.open() remove
+// all tasks associated with the document on which open() is called. This step
+// has been proposed to be removed. This series of tests ensures that this step
+// is no longer executed.
+//
+// This file comprehensively (but not exhaustively) tests for many queued tasks
+// that may be observable. Each taskTest() call in fact runs two tests: the
+// first one "tasks without document.open()" does not actually run
+// document.open(), just to test that the tested task works ordinarily; the
+// second actually calls document.open() to test if the method call removes
+// that specific task from the queue.
+
+// This is necessary to allow the promise rejection test below.
+setup({
+ allow_uncaught_exception: true
+});
+
+function taskTest(description, testBody) {
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ // The empty HTML seems to be necessary to cajole Chrome and Safari into
+ // firing a load event asynchronously, which is necessary to make sure the
+ // frame's document doesn't have a parser associated with it.
+ // See: https://crbug.com/569511
+ frame.src = "/common/blank.html";
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ // Make sure there is no parser. Firefox seems to have an additional
+ // non-spec-compliant readiness state "uninitialized", so test for the
+ // two known valid readiness states instead.
+ // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1191683
+ assert_in_array(frame.contentDocument.readyState, ["interactive", "complete"]);
+ testBody(t, frame, doc => {});
+ });
+ }, `tasks without document.open() (${description})`);
+
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ // The empty HTML seems to be necessary to cajole Chrome into firing a load
+ // event, which is necessary to make sure the frame's document doesn't have
+ // a parser associated with it.
+ // See: https://crbug.com/569511
+ frame.src = "/common/blank.html";
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ // Make sure there is no parser. Firefox seems to have an additional
+ // non-spec-compliant readiness state "uninitialized", so test for the
+ // two known valid readiness states instead.
+ // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1191683
+ assert_in_array(frame.contentDocument.readyState, ["interactive", "complete"]);
+ testBody(t, frame, doc => doc.open());
+ });
+ }, `document.open() and tasks (${description})`);
+}
+
+taskTest("timeout", (t, frame, open) => {
+ frame.contentWindow.setTimeout(t.step_func_done(), 100);
+ open(frame.contentDocument);
+});
+
+taskTest("window message", (t, frame, open) => {
+ let counter = 0;
+ frame.contentWindow.postMessage(undefined, "*");
+ open(frame.contentDocument);
+ frame.contentWindow.postMessage(undefined, "*");
+ frame.contentWindow.onmessage = t.step_func(e => {
+ assert_equals(e.data, undefined);
+ counter++;
+ assert_less_than_equal(counter, 2);
+ if (counter == 2) {
+ t.done();
+ }
+ });
+});
+
+taskTest("canvas.toBlob()", (t, frame, open) => {
+ const canvas = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("canvas"));
+ canvas.toBlob(t.step_func_done());
+ open(frame.contentDocument);
+});
+
+taskTest("MessagePort", (t, frame, open) => {
+ frame.contentWindow.eval(`({ port1, port2 } = new MessageChannel());`);
+ frame.contentWindow.port2.onmessage = t.step_func_done(ev => {
+ assert_equals(ev.data, "Hello world");
+ });
+ frame.contentWindow.port1.postMessage("Hello world");
+ open(frame.contentDocument);
+});
+
+taskTest("Promise rejection", (t, frame, open) => {
+ // There is currently some ambiguity on which Window object the
+ // unhandledrejection event should be fired on. Here, let's account for that
+ // ambiguity and allow event fired on _any_ global to pass this test.
+ // See:
+ // - https://github.com/whatwg/html/issues/958,
+ // - https://bugs.webkit.org/show_bug.cgi?id=187822
+ const promise = frame.contentWindow.eval("Promise.reject(42);");
+ open(frame.contentDocument);
+ const listener = t.step_func_done(ev => {
+ assert_equals(ev.promise, promise);
+ assert_equals(ev.reason, 42);
+ });
+ frame.contentWindow.onunhandledrejection = listener;
+ window.onunhandledrejection = listener;
+});
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt
new file mode 100644
index 0000000000..3e715502b9
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext-subframe.txt
@@ -0,0 +1 @@
+Some text.
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js
new file mode 100644
index 0000000000..ab1d9706a4
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument-plaintext.window.js
@@ -0,0 +1,23 @@
+["replace",
+ "NOBODY",
+ "@ FD ;",
+ "it does not matter, you see \f",
+ "text/plain",
+ "text/xml",
+ "application/octet-stream",
+ "\0"].forEach(type => {
+ async_test(t => {
+ const frame = document.createElement("iframe");
+ frame.src = "type-argument-plaintext-subframe.txt";
+ document.body.appendChild(frame);
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentDocument.open(type), frame.contentDocument);
+ frame.contentDocument.write("<B>heya</b>");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.body.firstChild.localName, "b");
+ assert_equals(frame.contentDocument.body.textContent, "heya");
+ assert_equals(frame.contentDocument.contentType, "text/plain");
+ });
+ }, "document.open() on plaintext document with type set to: " + type + " (type argument is supposed to be ignored)");
+});
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js
new file mode 100644
index 0000000000..9174008da3
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/type-argument.window.js
@@ -0,0 +1,20 @@
+["replace",
+ "NOBODY",
+ "@ FD ;",
+ "it does not matter, you see \f",
+ "text/plain",
+ "text/xml",
+ "application/octet-stream",
+ "\0"].forEach(type => {
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ assert_equals(frame.contentDocument.open(type), frame.contentDocument);
+ frame.contentDocument.write("<B>heya</b>");
+ frame.contentDocument.close();
+ assert_equals(frame.contentDocument.body.firstChild.localName, "b");
+ assert_equals(frame.contentDocument.body.textContent, "heya");
+ assert_equals(frame.contentDocument.contentType, "text/html");
+ t.done();
+ }, "document.open() with type set to: " + type + " (type argument is supposed to be ignored)");
+});
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js
new file mode 100644
index 0000000000..e275a4987a
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/unload.window.js
@@ -0,0 +1,19 @@
+// In an earlier version of the HTML Standard, document open steps had "unload
+// document" as a step. Test that this no longer happens.
+
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.src = "/common/blank.html";
+ frame.onload = t.step_func(() => {
+ frame.contentWindow.onpagehide = t.unreached_func("onpagehide got called");
+ frame.contentDocument.onvisibilitychange = t.unreached_func("onvisibilitychange got called");
+ frame.contentWindow.onunload = t.unreached_func("onunload got called");
+ frame.contentDocument.open();
+ t.step_timeout(t.step_func_done(() => {
+ // If none of the three events have been fired by this point, we consider
+ // the test a success. `frame.remove()` above will allow the `load` event
+ // to be fired on the top-level Window, thus unblocking testharness.
+ }), 500);
+ });
+}, "document.open(): Do not fire pagehide, visibilitychange, or unload events");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js
new file mode 100644
index 0000000000..f20b4341e3
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document-sync-call.window.js
@@ -0,0 +1,13 @@
+for (const methodName of ["open", "write", "writeln"]) {
+ async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => { frame.remove(); });
+ const frameURL = new URL("resources/url-entry-document-incumbent-frame.html", document.URL).href;
+ frame.onload = t.step_func_done(() => {
+ assert_equals(frame.contentDocument.URL, frameURL);
+ frame.contentWindow.callDocumentMethod(methodName);
+ assert_equals(frame.contentDocument.URL, document.URL);
+ });
+ frame.src = frameURL;
+ }, `document.${methodName}() changes document's URL to the entry global object's associate document's (sync call)`);
+}
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js
new file mode 100644
index 0000000000..c3a1c3a874
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-entry-document.window.js
@@ -0,0 +1,18 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ const frameURL = new URL("resources/url-entry-document-timer-frame.html", document.URL).href;
+ window.timerTest = t.step_func_done(() => {
+ assert_equals(frame.contentDocument.URL, frameURL);
+ assert_equals(frame.contentWindow.location.href, frameURL);
+
+ // In this case, the entry settings object was set when this function is
+ // executed in the timer task through Web IDL's "invoke a callback
+ // function" algorithm, to be the relevant settings object of this
+ // function. Therefore the URL of this document would be inherited.
+ assert_equals(frame.contentDocument.open(), frame.contentDocument);
+ assert_equals(frame.contentDocument.URL, document.URL);
+ assert_equals(frame.contentWindow.location.href, document.URL);
+ });
+ frame.src = frameURL;
+}, "document.open() changes document's URL to the entry settings object's responsible document's (through timeouts)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js
new file mode 100644
index 0000000000..0c528935b5
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url-fragment.window.js
@@ -0,0 +1,26 @@
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe")),
+ urlSansHash = document.URL;
+ t.add_cleanup(() => { frame.remove(); });
+ assert_equals(frame.contentDocument.URL, "about:blank");
+ assert_equals(frame.contentWindow.location.href, "about:blank");
+ self.onhashchange = t.step_func_done(() => {
+ frame.contentDocument.open();
+ assert_equals(frame.contentDocument.URL, urlSansHash);
+ assert_equals(frame.contentWindow.location.href, urlSansHash);
+ });
+ self.location.hash = "heya";
+}, "document.open() and document's URL containing a fragment (entry is not relevant)");
+
+window.testDone = undefined;
+async_test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"))
+ t.add_cleanup(() => { frame.remove(); });
+ frame.src = "resources/url-frame.html#heya";
+ window.testDone = t.step_func_done((beforeURL, afterURL) => {
+ assert_equals(beforeURL, frame.src);
+ assert_equals(afterURL, frame.src);
+ assert_equals(frame.contentDocument.URL, frame.src);
+ assert_equals(frame.contentWindow.location.href, frame.src);
+ });
+}, "document.open() and document's URL containing a fragment (entry is relevant)");
diff --git a/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js
new file mode 100644
index 0000000000..4e7c649f45
--- /dev/null
+++ b/testing/web-platform/tests/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/url.window.js
@@ -0,0 +1,93 @@
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ assert_equals(frame.contentDocument.URL, "about:blank");
+ assert_equals(frame.contentWindow.location.href, "about:blank");
+ assert_equals(frame.contentDocument.open(), frame.contentDocument);
+ assert_equals(frame.contentDocument.URL, document.URL);
+ assert_equals(frame.contentWindow.location.href, document.URL);
+}, "document.open() changes document's URL (fully active document)");
+
+async_test(t => {
+ const blankURL = new URL("/common/blank.html", document.URL).href;
+ const frameURL = new URL("resources/page-with-frame.html", document.URL).href;
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ frame.onload = t.step_func(() => {
+ assert_equals(frame.contentDocument.URL, frameURL);
+ assert_equals(frame.contentWindow.location.href, frameURL);
+ const childFrame = frame.contentDocument.querySelector("iframe");
+ const childDoc = childFrame.contentDocument;
+ const childWin = childFrame.contentWindow;
+ assert_equals(childDoc.URL, blankURL);
+ assert_equals(childWin.location.href, blankURL);
+
+ // Right now childDoc is still fully active.
+
+ frame.onload = t.step_func_done(() => {
+ // Now childDoc is still active but no longer fully active.
+ assert_equals(childDoc.open(), childDoc);
+ assert_equals(childDoc.URL, blankURL);
+ assert_equals(childWin.location.href, blankURL);
+ });
+ frame.src = "/common/blank.html";
+ });
+ frame.src = frameURL;
+}, "document.open() does not change document's URL (active but not fully active document)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ const doc = frame.contentDocument;
+
+ // We do not test for win.location.href in this test due to
+ // https://github.com/whatwg/html/issues/3959.
+
+ // Right now the frame is connected and it has an active document.
+ assert_equals(doc.URL, "about:blank");
+
+ frame.remove();
+
+ // Now the frame is no longer connected. Its document is no longer active.
+ assert_equals(doc.URL, "about:blank");
+ assert_equals(doc.open(), doc);
+ assert_equals(doc.URL, "about:blank");
+}, "document.open() does not change document's URL (non-active document with an associated Window object; frame is removed)");
+
+async_test(t => {
+ const frame = document.createElement("iframe");
+ t.add_cleanup(() => frame.remove());
+
+ // We do not test for win.location.href in this test due to
+ // https://github.com/whatwg/html/issues/3959.
+
+ frame.onload = t.step_func(() => {
+ const doc = frame.contentDocument;
+ // Right now the frame is connected and it has an active document.
+ assert_equals(doc.URL, "about:blank");
+
+ frame.onload = t.step_func_done(() => {
+ // Now even though the frame is still connected, its document is no
+ // longer active.
+ assert_not_equals(frame.contentDocument, doc);
+ assert_equals(doc.URL, "about:blank");
+ assert_equals(doc.open(), doc);
+ assert_equals(doc.URL, "about:blank");
+ });
+
+ frame.src = "/common/blank.html";
+ });
+
+ // We need to connect the frame after the load event is set up to mitigate
+ // against https://crbug.com/569511.
+ document.body.appendChild(frame);
+}, "document.open() does not change document's URL (non-active document with an associated Window object; navigated away)");
+
+test(t => {
+ const frame = document.body.appendChild(document.createElement("iframe"));
+ t.add_cleanup(() => frame.remove());
+ const doc = frame.contentDocument.implementation.createHTMLDocument();
+ assert_equals(doc.URL, "about:blank");
+ assert_equals(doc.open(), doc);
+ assert_equals(doc.URL, "about:blank");
+}, "document.open() does not change document's URL (non-active document without an associated Window object)");