| <!doctype html> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| |
| <button autofocus id="initialAutofocusTarget">Initial autofocus target</button> |
| |
| <script type="module"> |
| promise_setup(async () => { |
| // Get the overall autofocus processed flag to flip to true, so that |
| // we only test the app history-specific stuff. |
| await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))); |
| assert_equals(document.activeElement, initialAutofocusTarget, "Non-app history autofocus was processed"); |
| initialAutofocusTarget.remove(); |
| assert_equals(document.activeElement, document.body); |
| }); |
| |
| promise_test(async t => { |
| const decoy = createAndAppend(t); |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); |
| |
| await finished; |
| assert_equals(document.activeElement, autofocusTarget, "Focus moves to the autofocused button after the transition"); |
| }, "An element with autofocus, present before navigation, gets focused"); |
| |
| promise_test(async t => { |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| const decoy = createAndAppend(t, { autofocus: true }); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the initially-focused button during the transition"); |
| |
| await finished; |
| assert_equals(document.activeElement, autofocusTarget, "Focus moves to the first autofocused button after the transition"); |
| }, "Two elements with autofocus, present before navigation; the first gets focused"); |
| |
| promise_test(async t => { |
| const decoy = createAndAppend(t); |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); |
| |
| autofocusTarget.disabled = true; |
| |
| await finished; |
| assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); |
| }, "An element with autofocus, present before navigation but disabled before finished, does not get focused"); |
| |
| promise_test(async t => { |
| const decoy = createAndAppend(t); |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); |
| |
| autofocusTarget.autofocus = false; |
| |
| await finished; |
| assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); |
| }, "An element with autofocus, present before navigation but with its autofocus attribute removed before finished, does not get focused"); |
| |
| promise_test(async t => { |
| const decoy = createAndAppend(t, { autofocus: true }); |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the initially-focused button during the transition"); |
| |
| decoy.disabled = true; |
| assert_equals(document.activeElement, document.body, "Disabling the initially-focused button temporarily resets focus to the body"); |
| |
| await finished; |
| assert_equals(document.activeElement, autofocusTarget, "Focus moves to the second autofocused button after the transition"); |
| }, "Two elements with autofocus, present before navigation, but the first gets disabled; the second gets focused"); |
| |
| promise_test(async t => { |
| const decoy = createAndAppend(t); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); |
| |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| |
| await finished; |
| assert_equals(document.activeElement, autofocusTarget, "Focus moves to the autofocused button after the transition"); |
| }, "An element with autofocus, introduced between committed and finished, gets focused"); |
| |
| promise_test(async t => { |
| const decoy = createAndAppend(t); |
| |
| assert_equals(document.activeElement, document.body, "Start on body"); |
| decoy.focus(); |
| assert_equals(document.activeElement, decoy, "focus() worked"); |
| |
| navigation.addEventListener("navigate", e => { |
| e.transitionWhile(Promise.resolve()); |
| }, { once: true }); |
| |
| const { committed, finished } = navigation.navigate("#1"); |
| |
| await committed; |
| assert_equals(document.activeElement, decoy, "Focus stays on the non-autofocused button during the transition"); |
| |
| await finished; |
| assert_equals(document.activeElement, document.body, "Focus gets reset after the transition"); |
| |
| const autofocusTarget = createAndAppend(t, { autofocus: true }); |
| |
| await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r))); |
| assert_equals(document.activeElement, document.body, "Focus stays reset two animation frames after the transition"); |
| }, "An element with autofocus, introduced after finished, does not get focused"); |
| |
| function createAndAppend(t, props) { |
| const element = document.createElement("button"); |
| Object.assign(element, props); |
| |
| document.body.append(element); |
| t.add_cleanup(() => { element.remove(); }); |
| |
| return element; |
| } |
| </script> |