feat: contain mobile Device Setup focus (Closes #1134)
This commit is contained in:
1 parent
f3c9e89920
commit
4b3e53f4d0
3 files changed
+142
-4
No files matched your search
@@ -148,12 +148,24 @@ def test_release_artifact_bootstraps_mobile_home_and_returns_from_insights(
|
||||
expect(page.locator("#device-setup-sheet")).to_be_visible()
|
||||
expect(page.locator("#device-storage-heading")).to_have_text("Private device storage")
|
||||
expect(page.locator("#device-storage-detail")).to_contain_text("private work records")
|
||||
expect(page.locator("body > header")).to_have_attribute("inert", "")
|
||||
expect(page.locator("main")).to_have_attribute("inert", "")
|
||||
expect(dock).to_have_attribute("inert", "")
|
||||
expect(page.locator("#close-device-setup")).to_be_focused()
|
||||
page.keyboard.press("Shift+Tab")
|
||||
expect(page.locator("#clear-private-device-data")).to_be_focused()
|
||||
page.keyboard.press("Tab")
|
||||
expect(page.locator("#close-device-setup")).to_be_focused()
|
||||
for selector in ("#clear-device-caches", "#clear-private-device-data"):
|
||||
bounds = page.locator(selector).bounding_box()
|
||||
assert bounds and bounds["height"] >= 44
|
||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||
page.locator("#close-device-setup").click()
|
||||
page.go_back()
|
||||
expect(page.locator("#device-setup-sheet")).to_be_hidden()
|
||||
expect(page.locator("#open-device-setup")).to_be_focused()
|
||||
expect(page.locator("body > header")).not_to_have_attribute("inert", "")
|
||||
expect(page.locator("main")).not_to_have_attribute("inert", "")
|
||||
expect(dock).not_to_have_attribute("inert", "")
|
||||
|
||||
page.locator("#active-devices").click()
|
||||
expect(page.locator("#active-devices-sheet")).to_be_visible()
|
||||
|
||||
@@ -10,7 +10,7 @@ def run_scenario(script: str) -> dict:
|
||||
harness = r"""
|
||||
const createMobileDeviceSetup = require(__MODULE__);
|
||||
class FakeTarget {
|
||||
constructor() { this.listeners = {}; this.hidden = false; this.disabled = false; this.textContent = ''; }
|
||||
constructor() { this.listeners = {}; this.hidden = false; this.disabled = false; this.textContent = ''; this.inert = false; }
|
||||
addEventListener(name, callback) { (this.listeners[name] ||= []).push(callback); }
|
||||
async dispatch(name, event = {}) { for (const callback of this.listeners[name] || []) await callback(event); }
|
||||
focus() { state.focused = this; }
|
||||
@@ -39,6 +39,15 @@ const promptSummary = new FakeTarget();
|
||||
const promptLauncher = new FakeTarget();
|
||||
const promptDismiss = new FakeTarget();
|
||||
const returnButton = new FakeTarget();
|
||||
const backgroundHeader = new FakeTarget();
|
||||
const backgroundMain = new FakeTarget(); backgroundMain.inert = true;
|
||||
sheet.querySelectorAll = () => [closeButton, installButton, offlineButton, returnButton];
|
||||
const historyTarget = new FakeTarget();
|
||||
const history = {
|
||||
state:{section:'home'},
|
||||
pushState(state) { this.state = state; },
|
||||
back() { this.state = {section:'home'}; historyTarget.dispatch('popstate', {state:this.state}); },
|
||||
};
|
||||
let now = 1000;
|
||||
const promptStorage = {
|
||||
values:{},
|
||||
@@ -57,6 +66,8 @@ const setup = createMobileDeviceSetup({
|
||||
installStatus, offlineStatus, protectionStatus, pushStatus, deadlineStatus, readyStatus, escapeTarget,
|
||||
promptCard, promptSummary, promptLauncher, promptDismiss,
|
||||
returnButton, isMobile:() => true,
|
||||
backgroundElements:[backgroundHeader, backgroundMain],
|
||||
history, historyTarget,
|
||||
timerView:{
|
||||
beginDetour:reason => { state.events.push('pause'); state.beginCalls.push(reason); return {reason}; },
|
||||
finishDetour:() => { state.events.push('resume'); state.finishCalls += 1; },
|
||||
@@ -206,6 +217,60 @@ process.stdout.write(JSON.stringify({
|
||||
assert result == {"hidden": True, "launcherFocused": True}
|
||||
|
||||
|
||||
def test_open_setup_contains_focus_and_restores_background_inert_state():
|
||||
result = run_scenario("""
|
||||
await launcher.dispatch('click', {currentTarget:launcher});
|
||||
state.focused = returnButton;
|
||||
let preventedForward = false;
|
||||
await escapeTarget.dispatch('keydown', {key:'Tab', target:returnButton, preventDefault(){preventedForward=true;}});
|
||||
const forwardFocus = state.focused === closeButton;
|
||||
state.focused = closeButton;
|
||||
let preventedReverse = false;
|
||||
await escapeTarget.dispatch('keydown', {key:'Tab', shiftKey:true, target:closeButton, preventDefault(){preventedReverse=true;}});
|
||||
const reverseFocus = state.focused === returnButton;
|
||||
const inertWhileOpen = [backgroundHeader.inert, backgroundMain.inert];
|
||||
await closeButton.dispatch('click');
|
||||
process.stdout.write(JSON.stringify({
|
||||
preventedForward, forwardFocus, preventedReverse, reverseFocus,
|
||||
inertWhileOpen,
|
||||
inertAfterClose:[backgroundHeader.inert, backgroundMain.inert],
|
||||
launcherFocused:state.focused === launcher,
|
||||
}));
|
||||
""")
|
||||
|
||||
assert result == {
|
||||
"preventedForward": True,
|
||||
"forwardFocus": True,
|
||||
"preventedReverse": True,
|
||||
"reverseFocus": True,
|
||||
"inertWhileOpen": [True, True],
|
||||
"inertAfterClose": [False, True],
|
||||
"launcherFocused": True,
|
||||
}
|
||||
|
||||
|
||||
def test_browser_back_closes_setup_and_restores_launcher_focus():
|
||||
result = run_scenario("""
|
||||
await launcher.dispatch('click', {currentTarget:launcher});
|
||||
const marked = history.state.deviceSetup === true;
|
||||
history.back();
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
process.stdout.write(JSON.stringify({
|
||||
marked,
|
||||
hidden:sheet.hidden,
|
||||
backgroundReleased:backgroundHeader.inert === false,
|
||||
launcherFocused:state.focused === launcher,
|
||||
}));
|
||||
""")
|
||||
|
||||
assert result == {
|
||||
"marked": True,
|
||||
"hidden": True,
|
||||
"backgroundReleased": True,
|
||||
"launcherFocused": True,
|
||||
}
|
||||
|
||||
|
||||
def test_mobile_setup_pauses_before_readiness_and_each_exit_resumes_once():
|
||||
result = run_scenario("""
|
||||
state.events = [];
|
||||
|
||||
Reference in new issue
Block a user