#42967·Playwright

[Bug]: methods fill()/press()/type() doesn't wait element to be focusable, when element inside inert container

Author: msgoloborodovCreated Sep 28, 2026Updated Sep 28, 2026

Version

1.60.0

Steps to reproduce

 import { expect, test } from '@playwright/test';                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                     
  test.describe('locator.fill() silently does nothing inside [inert] container', () => {                                                                                                                                                                                                                                                                             
    test.beforeEach(async ({ page }) => {                                                                                                                                                                                                                                                                                                                            
      await page.setContent(`                                                                                                                                                                                                                                                                                                                                        
        <div inert id="locker">                                                                                                                                                                                                                                                                                                                                      
          <input id="target">                                                                                                                                                                                                                                                                                                                                        
        </div>                                                                                                                                                                                                                                                                                                                                                       
        <input id="outside">                                                                                                                                                                                                                                                                                                                                         
      `);                                                                                                                                                                                                                                                                                                                                                            
    });                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                     
    test('fill() resolves successfully but the input stays empty', async ({ page }) => {                                                                                                                                                                                                                                                                             
      const target = page.locator('#target');                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                     
      // All fill() actionability checks pass although the element is inert:                                                                                                                                                                                                                                                                                         
      // visible / enabled / editable do not consider the inert attribute                                                                                                                                                                                                                                                                                            
      // (aria-disabled="true" on the container would make "enabled" fail).                                                                                                                                                                                                                                                                                          
      await expect(target).toBeVisible();                                                                                                                                                                                                                                                                                                                            
      await expect(target).toBeEnabled();                                                                                                                                                                                                                                                                                                                            
      await expect(target).toBeEditable();                                                                                                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                                                                                                     
      // This resolves WITHOUT any error...                                                                                                                                                                                                                                                                                                                          
      await target.fill('hello');                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                     
      // ...but the value is silently dropped: injected fill does                                                                                                                                                                                                                                                                                                    
      // input.focus() (silently fails inside inert subtree), then                                                                                                                                                                                                                                                                                                   
      // Input.insertText goes to the actual focused element (<body>),                                                                                                                                                                                                                                                                                               
      // and dom.ts returns 'done' without verifying element.value.                                                                                                                                                                                                                                                                                                  
      await expect(target).toHaveValue('');                                                                                                                                                                                                                                                                                                                          
    });                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                     
    test('contrast: click() on the same element waits and times out', async ({ page }) => {                                                                                                                                                                                                                                                                          
      const target = page.locator('#target');                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                     
      // click() is properly blocked: the browser hit-testing skips inert                                                                                                                                                                                                                                                                                            
      // subtrees, so the hit-target check keeps failing.                                                                                                                                                                                                                                                                                                            
      await expect(target.click({ timeout: 3_000 })).rejects.toThrow(/timeout/i);                                                                                                                                                                                                                                                                                    
    });                                                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                     
    test('contrast: press() sends keystrokes to an unrelated focused element', async ({ page }) => {                                                                                                                                                                                                                                                                 
      const target = page.locator('#target');                                                                                                                                                                                                                                                                                                                        
      const outside = page.locator('#outside');                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                     
      await outside.focus();                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                     
      // press() = actionability checks + focus() + key press.                                                                                                                                                                                                                                                                                                       
      // The focus() call silently fails (inert), so the keystroke                                                                                                                                                                                                                                                                                                   
      // lands in whatever was focused before — a field outside the locker.                                                                                                                                                                                                                                                                                          
      await target.press('a');                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                     
      await expect(target).toHaveValue('');                                                                                                                                                                                                                                                                                                                          
      await expect(outside).toHaveValue('a');                                                                                                                                                                                                                                                                                                                        
    });

    test('contrast: the same input inside [aria-disabled] container is properly waited on', async ({ page }) => {                                                                                                                                                                                                                                                    
      await page.setContent(`                                                                                                                                                                                                                                                                                                                                        
        <div aria-disabled="true" id="locker">