Skip to content
Astera Technology

Keep controls reachable in a reduced viewport

Test actual focus and scrolling against the supplied visible area.

Download complete case notes and answer keys ↓

Set the decision and its input

The supplied viewing area is390×300. A fixed frame with overflow clip hides Calculate below that area. The corrected scrollable frame lets focus reach Calculate and return to the input. Both actions are needed; nominal document height does not establish reachability inside the frame.

Filled local test worksheet
CaseInput JSON
Base test{"height":300}
Download editable CSV ↓

Run the supplied comparison

Browser control rectangles are inspected after actual focus actions. The reduced viewport is supplied test geometry, not evidence that a real device keyboard was opened.

Faulty and required outputs
PathOutput JSON
Faulty path{"buttonReachable":false,"fieldRecoverable":true}
Required path{"buttonReachable":true,"fieldRecoverable":true}
Download editable CSV ↓
Node24.14.1 programme; Playwright1.63 Chromium required
import assert from 'node:assert/strict';
const smallWhole=(x,max)=>Number.isSafeInteger(x)&&x>=0&&x<=max;
import {createRequire} from 'node:module';
const htmlEscape=s=>String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
async function withPage(action,options={}){
  const require=createRequire(import.meta.url);const {chromium}=require('playwright');
  const browser=await chromium.launch({headless:true});
  try{const context=await browser.newContext(options);const page=await context.newPage();
    const requests=[];await page.route('**/*',route=>{requests.push(route.request().url());return route.abort();});
    return await action(page,context,requests);
  }finally{await browser.close();}
}

const run=async function run(i,corrected=true){
    if(!smallWhole(i.height,800)||i.height<200)return {held:true};
    return withPage(async page=>{await page.setContent('<style>body{margin:0;overflow:hidden}.frame{position:fixed;inset:0;overflow:'+(corrected?'auto':'clip')+'}.space{height:650px}</style><form class="frame"><label>Memo<input id="field"></label><div class="space"></div><button type="button" id="calculate">Calculate</button></form>');
      await page.focus('#calculate');const buttonReachable=await page.evaluate(()=>{const r=document.querySelector('#calculate').getBoundingClientRect();return r.top>=0&&r.bottom<=innerHeight;});
      await page.focus('#field');const fieldRecoverable=await page.evaluate(()=>{const r=document.querySelector('#field').getBoundingClientRect();return r.top>=0&&r.bottom<=innerHeight;});return {buttonReachable,fieldRecoverable};
    },{viewport:{width:390,height:i.height}});
  };
const cases=[{"input":{"height":300},"corrected":false,"expected":{"buttonReachable":false,"fieldRecoverable":true}},{"input":{"height":300},"corrected":true,"expected":{"buttonReachable":true,"fieldRecoverable":true}},{"input":{"height":240},"corrected":true,"expected":{"buttonReachable":true,"fieldRecoverable":true}},{"input":{"height":null},"corrected":true,"expected":{"held":true}}];
for(const test of cases){const actual=await run(test.input,test.corrected);assert.deepEqual(actual,test.expected);console.log(actual);}
Download runnable example ↓

Choose from the boundary evidence

A240-pixel-high boundary retains the same path. Missing visible height is held rather than guessed.

  1. Use the supplied visible area
  2. Focus the required action
  3. Return to the input

Obtain missing viewport observations before claiming mobile access.

Editable boundary inputs and outputs
ConditionInput JSONExpected output JSON
smaller supplied viewport{"height":240}{"buttonReachable":true,"fieldRecoverable":true}
visible viewport unknown{"height":null}{"held":true}
Download editable CSV ↓

What must the repaired base observation show?

Show the worked answer

Calculate becomes visible after focus, and the field is recoverable afterward. A clipped offscreen action does not satisfy the task.

Related resources