diff options
Diffstat (limited to 'testing/web-platform/tests/page-visibility')
22 files changed, 1084 insertions, 0 deletions
diff --git a/testing/web-platform/tests/page-visibility/META.yml b/testing/web-platform/tests/page-visibility/META.yml new file mode 100644 index 0000000000..9b9aea8e8b --- /dev/null +++ b/testing/web-platform/tests/page-visibility/META.yml @@ -0,0 +1,4 @@ +spec: https://w3c.github.io/page-visibility/ +suggested_reviewers: + - plehegar + - igrigorik diff --git a/testing/web-platform/tests/page-visibility/iframe-session-history.html b/testing/web-platform/tests/page-visibility/iframe-session-history.html new file mode 100644 index 0000000000..e023215316 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/iframe-session-history.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<title>Test the correct sequence of pagevisibility-related events in conjunction with history navigation</title> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org"> +<link rel="help" href="https://www.w3.org/TR/page-visibility-2/"> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> + +const iframePath1 = 'resources/iframe-post-load.html?v=1' +const iframePath2 = 'resources/iframe-post-load.html?v=2' + +function waitForLoad(iframe) { + return new Promise(resolve => { + const callback = e => { + if (e.data === 'load') { + window.removeEventListener('message', callback) + resolve() + } + } + + window.addEventListener('message', callback) + }) +} + +function assert_sequence(sequence) { + assert_equals(sequence.length, 2) + assert_equals(sequence[0].type, 'pagehide') + assert_equals(sequence[0].target, '#document') + assert_equals(sequence[0].visibilityState, 'visible') + assert_equals(sequence[0].cancelable, true) + assert_equals(sequence[1].type, 'visibilitychange') + assert_equals(sequence[1].target, '#document') + assert_equals(sequence[1].visibilityState, 'hidden') + assert_equals(sequence[1].cancelable, false) +} +promise_test(async t => { + const iframe = document.createElement('iframe'); + iframe.src = iframePath1; + document.body.appendChild(iframe); + let sequence = []; + t.add_cleanup(() => iframe.remove()); + iframe.src = iframePath1; + await waitForLoad(iframe); + const handler = t.step_func(event => sequence.push({ + type: event.type, + target: event.target.nodeName, + cancelable: event.cancelable, + visibilityState: iframe.contentWindow.document.visibilityState + })); + iframe.contentWindow.document.addEventListener('visibilitychange', handler); + iframe.contentWindow.addEventListener('pagehide', handler); + iframe.contentWindow.location.href = iframePath2; + await waitForLoad(iframe); + assert_sequence(sequence); + sequence = []; + iframe.contentWindow.addEventListener('pagehide', handler); + iframe.contentWindow.document.addEventListener('visibilitychange', handler); + iframe.contentWindow.history.back(); + await waitForLoad(iframe); + assert_sequence(sequence); +}, "pagehide should be called before visibilitychange, and visibilityState should be set to hidden at the right time"); +</script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/page-visibility/iframe-unload.html b/testing/web-platform/tests/page-visibility/iframe-unload.html new file mode 100644 index 0000000000..6d049a846d --- /dev/null +++ b/testing/web-platform/tests/page-visibility/iframe-unload.html @@ -0,0 +1,49 @@ +<html> +<title>visibilitychange fires on unload with iframes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + +var frameDocs = []; +var docsLoaded = 0; +var numFrames = 3; + +var ast = new async_test("visibilitychange fires on unload with iframes"); + +function startTest() { + if (++docsLoaded < numFrames) + return; + + ast.step(function () { + frameDocs.push(window[0].document); + frameDocs.push(window[0][0].document); + frameDocs.push(window[0][1].document); + + for (var i = 0; i < frameDocs.length; ++i) { + frameDocs[i].addEventListener( + "visibilitychange", + onVisibilityChange.bind(null, i), false); + } + + document.body.removeChild(document.getElementById("frame1")); + }); +} + +var checkedFrames = 0; + +function onVisibilityChange(i) { + ast.step(function () { + assert_equals(frameDocs[i].visibilityState, "hidden"); + }); + if (++checkedFrames >= numFrames) { + ast.done(); + } +} + + + +</script> +<iframe id="frame1" src="resources/iframe-with-subframes.html"></iframe> +</body> +</html> diff --git a/testing/web-platform/tests/page-visibility/minimize.html b/testing/web-platform/tests/page-visibility/minimize.html new file mode 100644 index 0000000000..ca834f74b6 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/minimize.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<title>Test different scenarios of how browser interactions are reflected by page visibility</title> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org"> +<link rel="help" href="https://www.w3.org/TR/page-visibility-2/"> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/window_state_context.js"></script> +<script> + +const iframePath = 'resources/blank_page_green.html' + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + assert_equals(document.visibilityState, "visible"); + assert_equals(document.hidden, false); + await minimize(); + assert_equals(document.visibilityState, "hidden"); + assert_equals(document.hidden, true); + await restore() + assert_equals(document.visibilityState, "visible"); + assert_equals(document.hidden, false); +}, "visibilityState & hidden should be affected by window being minimized/restored"); + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + const events = []; + const callback = () => events.push(document.visibilityState); + document.addEventListener('visibilitychange', callback); + t.add_cleanup(() => document.removeEventListener('visibilitychange', callback)); + await minimize(); + await restore(); + assert_array_equals(events, ['hidden', 'visible']); +}, "visibilitychange event should be fired when minimized/restored") + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + const events = []; + const iframe = document.createElement('iframe'); + iframe.src = iframePath; + document.body.appendChild(iframe); + t.add_cleanup(() => iframe.remove()); + await new Promise(resolve => iframe.onload = resolve); + const callback = () => events.push(iframe.contentWindow.document.visibilityState); + iframe.contentWindow.addEventListener('visibilitychange', callback); + await minimize(); + await restore(); + iframe.contentWindow.removeEventListener('visibilitychange', callback); + assert_array_equals(events, ['hidden', 'visible']); +}, "iframe should receive visibility events when top level window is shown/hidden"); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/page-visibility/onvisibilitychange.html b/testing/web-platform/tests/page-visibility/onvisibilitychange.html new file mode 100644 index 0000000000..f854084280 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/onvisibilitychange.html @@ -0,0 +1,16 @@ +<!doctype html> +<title>onvisibilitychange attribute is a proper event handler</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var ast = new async_test("onvisibilitychange attribute is a proper event handler"); +function startTest() { + var iframe1 = document.getElementById("frame1"); + iframe1.contentWindow.document.onvisibilitychange = ast.step_func(function() { + ast.done(); + }); + frame1.parentNode.removeChild(frame1); +} +</script> +<iframe id="frame1" src='resources/iframe.html'></iframe> diff --git a/testing/web-platform/tests/page-visibility/resources/blank_page_green.html b/testing/web-platform/tests/page-visibility/resources/blank_page_green.html new file mode 100644 index 0000000000..b8a1947b77 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/blank_page_green.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> + <head> + <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> + <title>Green Test Page</title> + </head> + <body style="background-color:#00FF00;"> + <h1>Placeholder</h1> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/resources/iframe-post-load.html b/testing/web-platform/tests/page-visibility/resources/iframe-post-load.html new file mode 100644 index 0000000000..5c8f2e3a08 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/iframe-post-load.html @@ -0,0 +1,8 @@ +<!doctype html> +<html> +<head> +<script> +window.addEventListener('load', () => parent.postMessage('load', '*')) +</script> +</body> +</html> diff --git a/testing/web-platform/tests/page-visibility/resources/iframe-with-subframes.html b/testing/web-platform/tests/page-visibility/resources/iframe-with-subframes.html new file mode 100644 index 0000000000..febb954369 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/iframe-with-subframes.html @@ -0,0 +1,6 @@ +<html> +<body onload="parent.startTest()"> +<iframe id="subIframe1" onload="parent.parent.startTest()"></iframe> +<iframe id="subIframe2" onload="parent.parent.startTest()"></iframe> +</body> +</html> diff --git a/testing/web-platform/tests/page-visibility/resources/iframe.html b/testing/web-platform/tests/page-visibility/resources/iframe.html new file mode 100644 index 0000000000..e08acb827a --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/iframe.html @@ -0,0 +1,12 @@ +<!doctype html> +<html> +<head><title>Document</title></head> +<body> +<h1>Document</h1> +<script> +onload = function() { + parent.startTest(); +} +</script> +</body> +</html> diff --git a/testing/web-platform/tests/page-visibility/resources/pagevistestharness.js b/testing/web-platform/tests/page-visibility/resources/pagevistestharness.js new file mode 100644 index 0000000000..d164d4603b --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/pagevistestharness.js @@ -0,0 +1,112 @@ +// +// Helper functions for Page Visibility tests +// + +var VISIBILITY_STATES = +{ + HIDDEN: "hidden", + VISIBLE: "visible" +}; + +var feature_check = false; + +// +// All test() functions in the WebPerf PageVis test suite should use pv_test() instead. +// +// pv_test() validates the document.hidden and document.visibilityState attributes +// exist prior to running tests and immediately shows a failure if they do not. +// + +function pv_test(func, msg, doc) +{ + if (!doc) + { + doc = document; + } + + // only run the feature check once, unless func == null, in which case, + // this call is intended as a feature check + if (!feature_check) + { + feature_check = true; + + var hiddenVal = doc.hidden; + var visStateVal = doc.visibilityState; + + // show a single error that the Page Visibility feature is undefined + test(function() + { + assert_true(hiddenVal !== undefined && hiddenVal != null, + "document.hidden is defined and not null.");}, + "document.hidden is defined and not null."); + + test(function() + { + assert_true(visStateVal !== undefined && hiddenVal != null, + "document.visibilityState is defined and not null.");}, + "document.visibilityState is defined and not null."); + + } + + if (func) + { + test(func, msg); + } +} + + +function test_feature_exists(doc, msg) +{ + if (!msg) + { + msg = ""; + } + var hiddenMsg = "document.hidden is defined" + msg + "."; + var stateMsg = "document.visibilityState is defined" + msg + "."; + pv_test(function(){assert_not_equals(document.hidden, undefined, hiddenMsg);}, hiddenMsg, doc); + pv_test(function(){assert_not_equals(document.visibilityState, undefined, stateMsg);}, stateMsg, doc); +} + +// +// Common helper functions +// + +function test_true(value, msg) +{ + pv_test(function() { assert_true(value, msg); }, msg); +} + +function test_equals(value, equals, msg) +{ + pv_test(function() { assert_equals(value, equals, msg); }, msg); +} + +// +// asynchronous test helper functions +// + +function add_async_result(test_obj, pass_state) +{ + // add assertion to manual test for the pass state + test_obj.step(function() { assert_true(pass_state) }); + + // end manual test + test_obj.done(); +} + +function add_async_result_assert(test_obj, func) +{ + // add assertion to manual test for the pass state + test_obj.step(func); + + // end manual test + test_obj.done(); +} + +var open_link; +function TabSwitch() +{ + //var open_link = window.open("http://www.bing.com"); + open_link = window.open('', '_blank'); + step_timeout(function() { open_link.close(); }, 2000); +} diff --git a/testing/web-platform/tests/page-visibility/resources/unload-bubbles.html b/testing/web-platform/tests/page-visibility/resources/unload-bubbles.html new file mode 100644 index 0000000000..cc9e14f787 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/unload-bubbles.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> +<head><title>Document</title></head> +<body> +<h1>Document</h1> +<script> +window.addEventListener("load", function() { + window.addEventListener("visibilitychange", event => { + opener.postMessage({ + target: event.target.nodeName, + state: document.visibilityState, + bubbles: event.bubbles + }, "*"); + }); + opener.postMessage("close", "*"); +}); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/page-visibility/resources/unload.html b/testing/web-platform/tests/page-visibility/resources/unload.html new file mode 100644 index 0000000000..b548518784 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/unload.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> +<head><title>Document</title></head> +<body> +<h1>Document</h1> +<script> +onload = function() { + document.addEventListener("visibilitychange", onVisibilityChange, false); + opener.postMessage("close", "*"); +} + +function onVisibilityChange() { + opener.postMessage(document.visibilityState, "*"); +} +</script> +</body> +</html> diff --git a/testing/web-platform/tests/page-visibility/resources/window_state_context.js b/testing/web-platform/tests/page-visibility/resources/window_state_context.js new file mode 100644 index 0000000000..40f10a5644 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/resources/window_state_context.js @@ -0,0 +1,19 @@ +function window_state_context(t) { + let rect = null; + let state = "restored"; + t.add_cleanup(async () => { + if (state === "minimized") + await restore(); + }); + async function restore() { + state = "restored"; + await test_driver.set_window_rect(rect); + } + + async function minimize() { + state = "minimized"; + rect = await test_driver.minimize_window(); + } + + return {minimize, restore}; +} diff --git a/testing/web-platform/tests/page-visibility/test_attributes_exist.html b/testing/web-platform/tests/page-visibility/test_attributes_exist.html new file mode 100644 index 0000000000..748161fdf8 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/test_attributes_exist.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Page Visibility API Definition</title> + + <script type="text/javascript" src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script type="text/javascript" src="resources/pagevistestharness.js"></script> + </head> + <body> + <h1>Description</h1> + <p>This test validates that all of the attributes associated with the Page Visibility feature exist + (but does not validate that their values are correct).</p> + + <div id="log"></div> + + <script type="text/javascript" > + test_feature_exists(); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/test_child_document.html b/testing/web-platform/tests/page-visibility/test_child_document.html new file mode 100644 index 0000000000..77ec8f8fd2 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/test_child_document.html @@ -0,0 +1,94 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Page Visibility API Child Document Test</title> + + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script type="text/javascript" src="resources/pagevistestharness.js"></script> + + <style type="text/css"> + iframe + { + width:250px; + height:250px; + margin-left:5px; + } + + div.docs + { + position:relative; + float:left; + text-align:center; + margin:10px; + border:solid 1px black; + padding:3px; + } + </style> + + <script type="text/javascript" > + setup({explicit_done: true}); + + function onload_test() + { + pv_test(); + + var frames = document.getElementsByTagName("iframe"); + var doc, doc_name; + + for (var i = 0; i < frames.length; i++) + { + doc = frames[i].contentDocument; + doc_name = "IFrame with " + frames[i].id; + + pv_test(function() + { + test_feature_exists(doc, " for frame with " + frames[i].id); + }); + + test_equals(doc.visibilityState, VISIBILITY_STATES.VISIBLE, + "document.visibilityState for frame with " + + frames[i].id + " == " + + VISIBILITY_STATES.VISIBLE); + } + + done(); + } + </script> + </head> + <body onload="onload_test()"> + <h1>Description</h1> + <p>This test validates that, within child documents, all of the Page Visibility API attributes exist, + are read-only, and match the value of the attributes within the parent document.</p> + + <div id="log"></div> + + <br/> + + <div class="docs"> + IFrame with no style attribute + <br/> + <iframe id="no style attribute" src="resources/blank_page_green.html"> + iframes unsupported + </iframe> + </div> + + <div class="docs"> + IFrame with "display:none" style<br/> + <iframe id="'display:none' style" style="display:none" + src="resources/blank_page_green.html"> + iframes unsupported + </iframe> + </div> + + <div class="docs"> + IFrame with "visibility:hidden" style + <br/> + <iframe id="'visibility:hidden' style" style="visibility:hidden" + src="resources/blank_page_green.html"> + iframes unsupported + </iframe> + </div> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/test_default_view.html b/testing/web-platform/tests/page-visibility/test_default_view.html new file mode 100644 index 0000000000..6e2f97084f --- /dev/null +++ b/testing/web-platform/tests/page-visibility/test_default_view.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Page Visibility Null Default View Test</title> + <link rel="author" title="Microsoft" href="http://www.microsoft.com/" /> + + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script type="text/javascript" src="resources/pagevistestharness.js"></script> + + <script type="text/javascript" > + setup({explicit_done: true}); + + function onload_test() + { + // inject a windowless subdocument as a child of the root document <html> element + var subDoc = document.implementation.createDocument('resources/blank_page_green.html', 'html', null); + + // Test precondition: ensure subdocument has a null default view + test_true(subDoc.defaultView == null, "windowless subdocument generated for test has a null default view"); + + // check that feature exists within subdocument + test_feature_exists(subDoc, 'windowless subdocument'); + + // check that the subdocument has a hidden visibility state + test_true(subDoc.hidden, + "hidden == true for windowless subdocuments with a null default view"); + test_equals(subDoc.visibilityState, VISIBILITY_STATES.HIDDEN, + "visibilityState == " + VISIBILITY_STATES.HIDDEN + + " for windowless subdocuments with a null default view"); + + done(); + } + </script> + </head> + <body onload="onload_test()"> + <h1>Description</h1> + <p>This test validates that document.hidden == false and + document.visibilityState == "visible" for windowless subdocuments.</p> + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/test_minimize-manual.html b/testing/web-platform/tests/page-visibility/test_minimize-manual.html new file mode 100644 index 0000000000..27fd0d7cef --- /dev/null +++ b/testing/web-platform/tests/page-visibility/test_minimize-manual.html @@ -0,0 +1,189 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Page Visibility API Operation While Minimizing Browser Window</title> + <meta name="flags" content="interact" /> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript" src="resources/pagevistestharness.js"></script> + + </head> + <body> + <h1>Description</h1> + <p>This test validates that the page properly becomes hidden and visible due to minimizing, maximizing, and + restoring the browser window.</p> + + <h1>Manual Test Steps:</h1> + <p> + <ol> + <li> Ensure this page is the foreground and click the "Start Test"</li> + <li> Minimize the browser</li> + <li> Restore or maximize the browser</li> + </ol> + Note: This test will automatically timeout and fail if not completed within 60 seconds. + </p> + + <button onclick="start_test();">Start Test</button> + + <div id="log"></div> + + <br /> + IFrame with default style: + <br /> + <iframe id="childDocShown" src="resources/blank_page_green.html"> + iframes unsupported + </iframe> + <hr /> + IFrame with "display:none" style: + <br /> + <iframe id="childDocHidden" src="resources/blank_page_green.html" style="display:none"> + iframes unsupported + </iframe> + + <script type="text/javascript" > + var child_doc_shown = null; + var child_doc_hidden = null; + var transition_mode; + var manual_test = null; + + var expected_notification_count = 2; + var notification_count = new Array(); + var page_docs = new Array(); + var notification_handlers = new Array(); + var two_notifications = false; + + var PAGE_HIDDEN_VAL = "hidden"; + var PAGE_VISIBLE_VAL = "visible"; + + setup({ explicit_done: true }); + + function test_transition_init() + { + child_doc_shown = document.getElementById("childDocShown").contentDocument; + child_doc_hidden = document.getElementById("childDocHidden").contentDocument; + + // fill in data for page documents + page_docs.push([document, "document"]); + page_docs.push([child_doc_shown, "document.getElementById(\"childDocShown\").contentDocument"]); + page_docs.push([child_doc_hidden, "document.getElementById(\"childDocHidden\").contentDocument"]); + + notification_handlers[0] = function(){ VerifyNotification(0); }; + notification_handlers[1] = function(){ VerifyNotification(1); }; + notification_handlers[2] = function(){ VerifyNotification(2); }; + + for (var i in page_docs) + { + notification_count[i] = 0; + page_docs[i][0].addEventListener("visibilitychange", notification_handlers[i]); + } + + test_true(!document.hidden, "Page is visible on load."); + test_true((!child_doc_shown.hidden) && (!child_doc_hidden.hidden), + "All IFrame child documents are visible on load."); + + document.addEventListener("visibilitychange", notification_handlers[0]); + document.addEventListener("visibilitychange", VerifyTwoNotifications); + + manual_test = AddManual("Browser minimization has occurred."); + } + + function VerifyNotification(doc_index) + { + doc = page_docs[doc_index][0]; + docName = page_docs[doc_index][1]; + + notification_count[doc_index]++; + switch (notification_count[doc_index]) + { + case 1: + // First step, check page visibility after tab deselection / minimization. + // hidden should change to true; visibilityState should change to "hidden" + test_true(doc.hidden, docName + ".hidden == true (after browser frame minimization)"); + test_true(doc.visibilityState == PAGE_HIDDEN_VAL, + docName + ".visibilityState == \"hidden\" (after browser frame minimization)"); + + break; + + case 2: + //Second step, check page visibility after tab reselection / maximization / restoration. + // hidden should change to false; visibilityState should change to "visible" + test_true(!doc.hidden, + docName + ".hidden == false (after browser frame maximization / restoration)"); + test_true(doc.visibilityState == PAGE_VISIBLE_VAL, + docName + ".visibilityState == \"visible\" (after browser frame maximization / " + + "restoration)"); + + // perform tests specific to the main document + if (doc == document) + { + //Verify that a second registration to a different callback also occurred + test_true(two_notifications, "Two registrations (different callbacks) occurred."); + + //Verify that a second registration to the same callback did not occur + test_equals(notification_count[doc_index], + expected_notification_count, + "Two registrations (same callback) did not occur."); + + // pass the manual item associated with these tests + AddManualResult(manual_test, true); + + document.removeEventListener("visibilitychange", VerifyTwoNotifications); + + // schedule the rollup + setTimeout(VerifyAllNotifications, 200); + } + + //Remove all event listeners and verify that the event does not fire + doc.removeEventListener("visibilitychange", notification_handlers[doc_index]); + break; + case 3: + //This step should not have occurred since the event handlers were cleared + test_true(false, "Event did not fire when event listener is removed."); + + //On final step, schedule the rollup + setTimeout(done, 2000); + break; + + default: + break; + } + } + + function VerifyAllNotifications() + { + //On final step, schedule the rollup + setTimeout(done, 1000); + } + + function VerifyTwoNotifications() + { + //This is a duplicate registration on visibilitychange and + //should never get fired. Check that duplicate_notification + //is false to verify that this never occurred. + two_notifications = true; + } + + // Manual Test helper functions + function AddManual(test) + { + // add asynchronous test for manual tests + return async_test(test); + } + + function AddManualResult(oManualTest, passState) + { + // add assertion to manual test for the pass state + oManualTest.step(function() {assert_true(passState)}); + + // end manual test + oManualTest.done(); + } + + function start_test() + { + test_transition_init(); + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/test_read_only.html b/testing/web-platform/tests/page-visibility/test_read_only.html new file mode 100644 index 0000000000..6d3702292d --- /dev/null +++ b/testing/web-platform/tests/page-visibility/test_read_only.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Page Visibility API is Read Only</title> + + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script type="text/javascript" src="resources/pagevistestharness.js"></script> + + <script type="text/javascript"> + setup({ explicit_done: true }); + function onload_test() + { + //check for feature definition first before attempting to overwrite + pv_test(); + + //Check document.hidden + document.hidden = "new value"; + test_true(document.hidden !== "new value", 'document.hidden is read only.'); + + //Check document.visibilityState + document.visibilityState = "new value"; + test_true(document.visibilityState !== "new value", + "document.visibilityState is read only."); + + done(); + } + </script> + </head> + <body onload="onload_test();"> + <h1>Description</h1> + <p>This test validates that the Page Visibility attributes are read only.</p> + + <div id="log"></div> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/test_tab_state_change-manual.html b/testing/web-platform/tests/page-visibility/test_tab_state_change-manual.html new file mode 100644 index 0000000000..75d1da6e93 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/test_tab_state_change-manual.html @@ -0,0 +1,187 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <title>Page Visibility API Operation While Changing Tabs</title> + <meta name="flags" content="interact" /> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript" src="resources/pagevistestharness.js"></script> + + </head> + <body> + <h1>Description</h1> + <p>This test validates that the page properly becomes hidden and visible due to switching tabs.</p> + + <h1>Manual Test Steps:</h1> + <p> + <ol> + <li> Ensure this page is the foreground and click the "Start Test"</li> + <li> Switch to another tab</li> + <li> Return to the current tab containing this test page</li> + </ol> + Note: This test will automatically timeout and fail if not completed within 60 seconds. + </p> + + <button onclick="start_test();">Start Test</button> + + <div id="log"></div> + + <br /> + IFrame with default style: + <br /> + <iframe id="childDocShown" src="resources/blank_page_green.html"> + iframes unsupported + </iframe> + <hr /> + IFrame with "display:none" style: + <br /> + <iframe id="childDocHidden" src="resources/blank_page_green.html" style="display:none"> + iframes unsupported + </iframe> + + <script type="text/javascript" > + var child_doc_shown = null; + var child_doc_hidden = null; + var transition_mode; + var manual_test = null; + + var expected_notification_count = 2; + var notification_count = new Array(); + var page_docs = new Array(); + var notification_handlers = new Array(); + var two_notifications = false; + + var PAGE_HIDDEN_VAL = "hidden"; + var PAGE_VISIBLE_VAL = "visible"; + + setup({ explicit_done: true }); + + function test_transition_init() + { + child_doc_shown = document.getElementById("childDocShown").contentDocument; + child_doc_hidden = document.getElementById("childDocHidden").contentDocument; + + // fill in data for page documents + page_docs.push([document, "document"]); + page_docs.push([child_doc_shown, "document.getElementById(\"childDocShown\").contentDocument"]); + page_docs.push([child_doc_hidden, "document.getElementById(\"childDocHidden\").contentDocument"]); + + notification_handlers[0] = function(){ VerifyNotification(0); }; + notification_handlers[1] = function(){ VerifyNotification(1); }; + notification_handlers[2] = function(){ VerifyNotification(2); }; + + for (var i in page_docs) + { + notification_count[i] = 0; + page_docs[i][0].addEventListener("visibilitychange", notification_handlers[i]); + } + + test_true(!document.hidden, "Page is visible on load."); + test_true((!child_doc_shown.hidden) && (!child_doc_hidden.hidden), + "All IFrame child documents are visible on load."); + + document.addEventListener("visibilitychange", notification_handlers[0]); + document.addEventListener("visibilitychange", VerifyTwoNotifications); + + manual_test = AddManual("Browser tab switch has occurred."); + } + + function VerifyNotification(doc_index) + { + doc = page_docs[doc_index][0]; + docName = page_docs[doc_index][1]; + + notification_count[doc_index]++; + switch (notification_count[doc_index]) + { + case 1: + // First step, check page visibility after tab deselection / minimization. + // hidden should change to true; visibilityState should change to "hidden" + test_true(doc.hidden, docName + ".hidden == true (after tab switch)"); + test_true(doc.visibilityState == PAGE_HIDDEN_VAL, + docName + ".visibilityState == \"hidden\" (after tab switch)"); + + break; + + case 2: + //Second step, check page visibility after tab reselection / maximization / restoration. + // hidden should change to false; visibilityState should change to "visible" + test_true(!doc.hidden, + docName + ".hidden == false (after return to original tab)"); + test_true(doc.visibilityState == PAGE_VISIBLE_VAL, + docName + ".visibilityState == \"visible\" (after return to original tab)"); + + // perform tests specific to the main document + if (doc == document) + { + //Verify that a second registration to a different callback also occurred + test_true(two_notifications, "Two registrations (different callbacks) occurred."); + + //Verify that a second registration to the same callback did not occur + test_equals(notification_count[doc_index], + expected_notification_count, + "Two registrations (same callback) did not occur."); + + // pass the manual item associated with these tests + AddManualResult(manual_test, true); + + document.removeEventListener("visibilitychange", VerifyTwoNotifications); + + // schedule the rollup + setTimeout(VerifyAllNotifications, 200); + } + + //Remove all event listeners and verify that the event does not fire + doc.removeEventListener("visibilitychange", notification_handlers[doc_index]); + break; + case 3: + //This step should not have occurred since the event handlers were cleared + test_true(false, "Event did not fire when event listener is removed."); + + //On final step, schedule the rollup + setTimeout(done, 2000); + break; + + default: + break; + } + } + + function VerifyAllNotifications() + { + //On final step, schedule the rollup + setTimeout(done, 1000); + } + + function VerifyTwoNotifications() + { + //This is a duplicate registration on visibilitychange and + //should never get fired. Check that duplicate_notification + //is false to verify that this never occurred. + two_notifications = true; + } + + // Manual Test helper functions + function AddManual(test) + { + // add asynchronous test for manual tests + return async_test(test); + } + + function AddManualResult(oManualTest, passState) + { + // add assertion to manual test for the pass state + oManualTest.step(function() {assert_true(passState)}); + + // end manual test + oManualTest.done(); + } + + function start_test() + { + test_transition_init(); + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/page-visibility/unload-bubbles.html b/testing/web-platform/tests/page-visibility/unload-bubbles.html new file mode 100644 index 0000000000..19b169c5e6 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/unload-bubbles.html @@ -0,0 +1,22 @@ +<!doctype html> +<title>visibilitychange event bubbles when fired on unload</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(function(t) { + var w = window.open("resources/unload-bubbles.html"); + window.onmessage = t.step_func(function(event) { + if (event.data === "close") { + w.close(); + return; + } + + const {state, target, bubbles} = event.data + assert_equals(state, "hidden"); + assert_equals(target, "#document"); + assert_equals(bubbles, true); + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/page-visibility/unload.html b/testing/web-platform/tests/page-visibility/unload.html new file mode 100644 index 0000000000..9b7dcb8c66 --- /dev/null +++ b/testing/web-platform/tests/page-visibility/unload.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>visibilitychange fires on unload</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(function(t) { + var w = window.open("resources/unload.html"); + window.onmessage = t.step_func(function(event) { + if (event.data === "close") { + w.close(); + return; + } + assert_equals(event.data, "hidden"); + t.done(); + }); +}); +</script> diff --git a/testing/web-platform/tests/page-visibility/visibility-state-entry.tentative.html b/testing/web-platform/tests/page-visibility/visibility-state-entry.tentative.html new file mode 100644 index 0000000000..c62b6c583f --- /dev/null +++ b/testing/web-platform/tests/page-visibility/visibility-state-entry.tentative.html @@ -0,0 +1,82 @@ +<!DOCTYPE HTML> +<title>Test VisibleStateEntry</title> +<link rel="author" title="Noam Rosenthal" href="mailto:noam@chromium.org"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#page-visibility"> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/window_state_context.js"></script> +<script> + +setup(() => { + assert_implements(window.VisibilityStateEntry, 'VisibilityStateEntry is not supported.'); +}); + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + let entries = performance.getEntriesByType("visibility-state"); + assert_equals(entries.length, 1); + assert_equals(entries[0].name, "visible"); + assert_equals(entries[0].startTime, 0); + assert_equals(entries[0].duration, 0); + await minimize(); + entries = performance.getEntriesByType("visibility-state"); + assert_equals(entries.length, 2); + assert_equals(entries[1].name, "hidden"); + assert_equals(entries[1].duration, 0); + await restore(); + assert_equals(entries.length, 3); + assert_equals(entries[2].name, "visible"); + assert_equals(entries[2].duration, 0); +}, "Hiding/showing the page should create visibility-state entries"); + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + await minimize(); + const popup = window.open("resources/blank_page_green.html"); + t.add_cleanup(() => popup.close()); + await restore(); + let entries = popup.performance.getEntriesByType("visibility-state"); + assert_equals(entries.length, 2); + assert_equals(entries[0].name, "hidden"); + assert_equals(entries[0].startTime, 0); + assert_equals(entries[1].name, "visible"); + assert_greater_than(entries[1].startTime, 0); + +}, "If a page starts as hidden, the first visibility-state entry should be hidden"); + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + await minimize(); + const observed = new Promise(resolve => new PerformanceObserver(list => { + const entries = list.getEntries(); + assert_equals(entries.length, 1); + assert_equals(entries[0].name, "visible"); + assert_greater_than(entries[0].startTime, 0); + assert_equals(entries[0].duration, 0); + resolve(); + }).observe({entryTypes: ['visibility-state'], buffered: true})); + await restore(); + await observed; +}, "Visibility state entries should be queued to performance observers"); + +promise_test(async t => { + const {minimize, restore} = window_state_context(t); + await minimize(); + await restore(); + await new Promise(resolve => new PerformanceObserver(list => { + const entries = list.getEntries(); + assert_equals(entries.length, 3); + assert_equals(entries[0].name, "visible"); + assert_equals(entries[0].startTime, 0); + assert_equals(entries[0].duration, 0); + assert_equals(entries[1].name, "hidden"); + assert_equals(entries[1].duration, 0); + assert_equals(entries[2].name, "visible"); + assert_equals(entries[2].duration, 0); + resolve(); + }).observe({entryTypes: ['visibility-state'], buffered: true})); +}, "Visibility state entries should respect the buffered flag"); +</script> |