2026-10-25 19:39:06 +00:00
""" SO globales: recorrido HTTP real y Playwright MCP en instalación desechable. """
import json
import base64
import hashlib
import time
import uuid
def verify ( context , fixture , admin_password ) :
api , tool , capture = context [ ' api ' ] , context [ ' tool ' ] , context [ ' capture ' ]
origin , directory = context [ ' origin ' ] , context [ ' directory ' ]
checks , screenshots , measurements = [ ] , [ ] , [ ]
base = ' /catalogs/global-operating-systems '
def code ( client , source ) :
print ( ' SO MCP: ' + source [ : 90 ] , flush = True )
try :
return tool ( client , ' browser_run_code_unsafe ' , { ' code ' : ' async(page)=> { ' + source + ' } ' } )
except RuntimeError :
shot ( client , ' failure ' )
diagnostic = context [ ' result_json ' ] ( tool ( client , ' browser_run_code_unsafe ' , { ' code ' : " async(page)=>( { alerts:await page.locator( ' [role=alert] ' ).allTextContents(),dialogs:await page.getByRole( ' dialog ' ).allTextContents(),buttons:await page.getByRole( ' button ' ).evaluateAll(items=>items.filter(x=>x.getBoundingClientRect().width).map(x=>( { text:x.innerText,disabled:x.disabled})))}) " } ) )
measurements . append ( { ' failure ' : diagnostic } )
raise
def login ( client , email , password ) :
tool ( client , ' browser_navigate ' , { ' url ' : origin + ' /login ' } )
code ( client , " await page.getByRole( ' button ' , { name: ' Entrar ' ,exact:true}).waitFor(); " )
tool ( client , ' browser_fill_form ' , { ' fields ' : [
{ ' name ' : ' Correo electrónico ' , ' type ' : ' textbox ' , ' target ' : ' input[type=email] ' , ' value ' : email } ,
{ ' name ' : ' Contraseña ' , ' type ' : ' textbox ' , ' target ' : ' input[type=password] ' , ' value ' : password } ] } )
tool ( client , ' browser_click ' , { ' target ' : ' button[type=submit] ' } )
code ( client , " await page.locator( ' [data-slot=workspace] ' ).waitFor( {timeout:30000} ); " )
def shot ( client , name ) :
screenshots . append ( capture ( client , directory , ' global-os- ' + name ) )
2026-10-26 10:22:23 +00:00
def text_contrast ( client , selector ) :
return context [ ' result_json ' ] ( code ( client , """ return await page.evaluate(selector=> {
const canvas = document . createElement ( ' canvas ' ) ; canvas . width = canvas . height = 1 ; const ctx = canvas . getContext ( ' 2d ' , { willReadFrequently : true } ) ;
const rgba = color = > { ctx . clearRect ( 0 , 0 , 1 , 1 ) ; ctx . fillStyle = color ; ctx . fillRect ( 0 , 0 , 1 , 1 ) ; return [ . . . ctx . getImageData ( 0 , 0 , 1 , 1 ) . data ] . map ( ( v , i ) = > i == = 3 ? v / 255 : v ) } ;
const over = ( a , b ) = > { const alpha = a [ 3 ] + b [ 3 ] * ( 1 - a [ 3 ] ) ; return [ . . . a . slice ( 0 , 3 ) . map ( ( v , i ) = > ( v * a [ 3 ] + b [ i ] * b [ 3 ] * ( 1 - a [ 3 ] ) ) / alpha ) , alpha ] } ;
const bg = e = > e ? over ( rgba ( getComputedStyle ( e ) . backgroundColor ) , bg ( e . parentElement ) ) : [ 255 , 255 , 255 , 1 ] ;
const lum = c = > c . slice ( 0 , 3 ) . map ( v = > v / 255 ) . map ( v = > v < = .04045 ? v / 12.92 : ( ( v + .055 ) / 1.055 ) * * 2.4 ) . reduce ( ( sum , v , i ) = > sum + v * [ .2126 , .7152 , .0722 ] [ i ] , 0 ) ;
return [ . . . document . querySelectorAll ( selector ) ] . filter ( e = > e . getBoundingClientRect ( ) . width & & e . innerText . trim ( ) ) . map ( e = > { const a = lum ( over ( rgba ( getComputedStyle ( e ) . color ) , bg ( e ) ) ) , b = lum ( bg ( e ) ) ; return { text : e . innerText . slice ( 0 , 80 ) , ratio : ( Math . max ( a , b ) + .05 ) / ( Math . min ( a , b ) + .05 ) } } ) ;
} , """ + json.dumps(selector) + " ); " ))
2026-10-25 19:39:06 +00:00
def report ( ) :
data = { ' checks ' : checks , ' screenshots ' : screenshots , ' measurements ' : measurements , ' database ' : ' metis_desk_test ' , ' companies ' : 15 ,
' principal ' : { ' people ' : 50 , ' assetsAtLeast ' : 50 , ' resourcesAtLeast ' : 50 , ' profiles ' : 50 , ' workstations ' : 50 } ,
' mcp ' : ' Docker stdio de .codex/config.toml ' , ' productionEnabled ' : False }
( directory / ' global-operating-systems-report.json ' ) . write_text ( json . dumps ( data , ensure_ascii = False , indent = 2 ) + ' \n ' )
with context [ ' browser ' ] ( context [ ' config ' ] ) as client :
try :
login ( client , ' setup@audit.example.test ' , admin_password )
tool ( client , ' browser_resize ' , { ' width ' : 1280 , ' height ' : 1000 } )
tool ( client , ' browser_navigate ' , { ' url ' : origin + base } )
code ( client , " await page.getByText( ' Todavía no hay sistemas operativos globales. ' , { exact:false}).waitFor(); " )
checks . append ( ' empty-catalog ' )
shot ( client , ' empty ' )
code ( client , " await page.getByRole( ' button ' , { name: ' Nuevo sistema operativo global ' ,exact:true}).click(); await page.getByRole( ' dialog ' ).getByRole( ' textbox ' , { name: ' Nombre ' ,exact:true}).fill( ' Windows 11 Pro ' ); await page.getByRole( ' textbox ' , { name: ' Fabricante / proveedor ' ,exact:true}).fill( ' Microsoft ' ); await page.getByRole( ' textbox ' , { name: ' Familia ' ,exact:true}).fill( ' Windows ' ); await page.getByRole( ' textbox ' , { name: ' Versión principal del producto ' ,exact:true}).fill( ' 11 ' ); await page.getByRole( ' combobox ' , { name: ' Estado de edición ' ,exact:true}).click(); await page.getByRole( ' option ' , { name: ' Edición conocida ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Edición ' ,exact:true}).fill( ' Pro ' ); " )
code ( client , " if(!await page.getByRole( ' button ' , { name: ' Guardar ' ,exact:true}).isDisabled())throw Error( ' Revisión obligatoria ' ); await page.getByRole( ' button ' , { name: ' Comprobar identidad en el catálogo ' ,exact:true}).click(); await page.getByText( ' No hay otra identidad equivalente en el catálogo. ' , { exact:false}).waitFor(); await page.getByRole( ' checkbox ' , { name: ' He revisado la identidad y el catálogo; este producto es distinto. ' ,exact:true}).check(); await page.getByRole( ' textbox ' , { name: ' Edición ' ,exact:true}).fill( ' Home ' ); if(!await page.getByRole( ' button ' , { name: ' Guardar ' ,exact:true}).isDisabled())throw Error( ' Revisión obsoleta ' ); await page.getByRole( ' textbox ' , { name: ' Edición ' ,exact:true}).fill( ' Pro ' ); " )
checks . extend ( [ ' identity-fields ' , ' known-edition ' , ' review-required ' , ' identity-review-invalidation ' ] )
shot ( client , ' create-review ' )
code ( client , " await page.getByRole( ' button ' , { name: ' Guardar ' ,exact:true}).click(); await page.getByRole( ' heading ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); await page.getByRole( ' heading ' , { name: ' Historial ' ,exact:true}).waitFor(); " )
product_url = context [ ' result_json ' ] ( code ( client , ' return page.url(); ' ) )
product_id = product_url . split ( ' / ' ) [ - 1 ]
checks . extend ( [ ' create-in-browser ' , ' history ' ] )
shot ( client , ' created-detail ' )
code ( client , " await page.getByRole( ' button ' , { name: ' Editar sistema operativo global ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Versión principal del producto ' ,exact:true}).fill( ' 10 ' ); await page.getByRole( ' textbox ' , { name: ' Nombre ' ,exact:true}).fill( ' Windows 10 Pro ' ); await page.getByRole( ' button ' , { name: ' Comprobar identidad en el catálogo ' ,exact:true}).click(); await page.getByRole( ' checkbox ' , { name: ' He revisado la identidad y el catálogo; este producto es distinto. ' ,exact:true}).check(); await page.getByRole( ' button ' , { name: ' Guardar ' ,exact:true}).click(); await page.getByText( ' Este producto ya se publicó. ' , { exact:false}).waitFor(); " )
checks . append ( ' server-rejects-product-transformation-form-preserved ' )
shot ( client , ' identity-error ' )
code ( client , " await page.getByRole( ' button ' , { name: ' Cancelar ' ,exact:true}).click(); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); if(!await page.getByRole( ' button ' , { name: ' Editar sistema operativo global ' ,exact:true}).evaluate(el=>el===document.activeElement))throw Error( ' Retorno de foco ' ); " )
checks . append ( ' dialog-focus-return ' )
api . request ( ' /auth/login ' , { ' email ' : ' setup@audit.example.test ' , ' password ' : admin_password } )
rc = api . request ( ' /resource-catalog/global ' ) [ ' items ' ]
ids = { item [ ' builtinKey ' ] : item [ ' id ' ] for item in rc if item . get ( ' builtinKey ' ) }
identity_keys = { ' provider ' : ' provider ' , ' family ' : ' os_family ' , ' productVersion ' : ' os_product_version ' , ' editionState ' : ' os_edition_state ' , ' edition ' : ' software_edition ' }
for index in range ( 50 ) :
identity = { ' provider ' : ' Microsoft ' , ' family ' : ' Windows ' , ' productVersion ' : str ( 100 + index ) , ' editionState ' : ' known ' , ' edition ' : ' Pro ' }
creation = str ( uuid . UUID ( int = ( int ( time . time ( ) * 1000 ) << 80 ) | ( 0x7 << 76 ) | ( 0x2 << 62 ) | ( uuid . uuid4 ( ) . int & ( ( 1 << 62 ) - 1 ) ) ) )
api . request ( ' /resource-global-operating-systems ' , { ' creationId ' : creation , ' reviewedIdentity ' : identity ,
' values ' : { ' name ' : f ' Windows { 100 + index } Pro — Producto sintético Álvarez ' , ' templateId ' : ids [ ' template:os ' ] , ' active ' : True , ' notes ' : ' ' , ' characteristics ' : { ids [ ' field: ' + identity_keys [ key ] ] : value for key , value in identity . items ( ) } } } , expected = 201 )
company = fixture [ ' company ' ]
local = api . request ( ' /resources/ ' + company , { ' values ' : { ' name ' : ' Windows 11 Pro ' , ' templateId ' : ids [ ' template:os ' ] , ' active ' : True , ' notes ' : ' ' , ' characteristics ' : { } } } , expected = 201 ) [ ' resource ' ]
for resource_id in [ product_id , local [ ' id ' ] ] :
api . request ( ' /software-installations/ ' + company , { ' values ' : { ' assetId ' : fixture [ ' softwareAssets ' ] [ 0 ] , ' resourceId ' : resource_id , ' licenseResourceId ' : None , ' version ' : ' 24H2 ' , ' state ' : ' configured ' , ' notes ' : ' ' } } , expected = 201 )
api . request ( ' /auth/logout ' , { } )
tool ( client , ' browser_navigate ' , { ' url ' : origin + base } )
code ( client , " await page.getByRole( ' link ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); await page.getByRole( ' button ' , { name: ' Siguiente ' ,exact:true}).click(); await page.getByRole( ' button ' , { name: ' Anterior ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Buscar por nombre o proveedor ' ,exact:true}).fill( ' SIN-COINCIDENCIAS-SO ' ); await page.getByText( ' No hay sistemas operativos que coincidan. ' , { exact:false}).waitFor(); " )
checks . extend ( [ ' 51-global-products ' , ' cursor-pagination ' , ' search-empty-recovery ' ] )
shot ( client , ' no-results ' )
code ( client , " await page.getByRole( ' textbox ' , { name: ' Buscar por nombre o proveedor ' ,exact:true}).fill( ' ' ); await page.getByRole( ' link ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); " )
for theme in [ ' light ' , ' dark ' ] :
code ( client , " await page.evaluate(theme=> { document.documentElement.classList.toggle( ' dark ' ,theme=== ' dark ' );}, " + json . dumps ( theme ) + " ); " )
for width in [ 320 , 390 , 768 , 1024 , 1280 , 1600 ] :
tool ( client , ' browser_resize ' , { ' width ' : width , ' height ' : 1000 if width > 768 else 844 } )
code ( client , " if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth+1))throw Error( ' Desbordamiento de página ' ); " )
shot ( client , f ' list- { theme } - { width } ' )
2026-10-26 10:22:23 +00:00
contrast = text_contrast ( client , ' main h1,main p,main table a,main th ' )
2026-10-25 19:39:06 +00:00
if not contrast or any ( item [ ' ratio ' ] < 4.5 for item in contrast ) :
raise RuntimeError ( ' Contraste de texto insuficiente en ' + theme + ' : ' + json . dumps ( contrast ) )
measurements . append ( { ' theme ' : theme , ' contrast ' : contrast } )
checks . append ( ' computed-text-contrast- ' + theme )
checks . append ( ' list- ' + theme + ' -320-390-768-1024-1280-1600 ' )
tool ( client , ' browser_resize ' , { ' width ' : 390 , ' height ' : 844 } )
code ( client , " await page.getByRole( ' button ' , { name: ' Nuevo sistema operativo global ' ,exact:true}).click(); await page.getByRole( ' dialog ' ).waitFor(); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth+1))throw Error( ' Desbordamiento de modal ' ); " )
shot ( client , ' mobile-form ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); " )
checks . append ( ' mobile-form-keyboard-close ' )
tool ( client , ' browser_resize ' , { ' width ' : 1280 , ' height ' : 1000 } )
code ( client , " page.osPattern= ' **/api/resource-global-operating-systems?* ' ; await page.route(page.osPattern,r=>r.fulfill( { status:500,contentType: ' application/json ' ,json: { code: ' INTERNAL_ERROR ' }})); await page.goto( " + json . dumps ( origin + base ) + " ); await page.getByText( ' No se han podido cargar los sistemas operativos. ' , { exact:true}).waitFor(); " )
shot ( client , ' list-error ' )
code ( client , " await page.unroute(page.osPattern); await page.getByRole( ' button ' , { name: ' Reintentar ' ,exact:true}).click(); await page.getByRole( ' link ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); " )
checks . append ( ' transport-error-retry ' )
# Una sola llamada conserva las barreras y sus callbacks en el mismo ámbito.
loading_capture = context [ ' result_json ' ] ( code ( client , """
const releases = [ ] , pending = [ ] ;
const pattern = ' **/api/resource-global-operating-systems?* ' ;
const hold = async route = > { const task = ( async ( ) = > { await new Promise ( resolve = > releases . push ( resolve ) ) ; await route . continue ( ) } ) ( ) ; pending . push ( task ) ; await task } ;
await page . route ( pattern , hold ) ;
let screenshot ;
try {
await page . goto ( """ + json.dumps(origin+base) + """ , { waitUntil : ' domcontentloaded ' } ) ;
await page . getByText ( ' Cargando sistemas operativos… ' , { exact : true } ) . waitFor ( ) ;
screenshot = ( await page . screenshot ( { fullPage : false } ) ) . toString ( ' base64 ' ) ;
} finally {
for ( const release of releases ) release ( ) ;
await Promise . all ( pending ) ;
await page . unroute ( pattern , hold ) ;
}
await page . getByRole ( ' link ' , { name : ' Windows 11 Pro ' , exact : true } ) . waitFor ( ) ;
return screenshot ;
""" ))
png = base64 . b64decode ( loading_capture , validate = True )
( directory / ' global-os-list-loading.png ' ) . write_bytes ( png )
screenshots . append ( { ' file ' : ' global-os-list-loading.png ' , ' sha256 ' : hashlib . sha256 ( png ) . hexdigest ( ) } )
checks . append ( ' initial-loading ' )
code ( client , " await page.getByRole( ' button ' , { name: ' Nuevo sistema operativo global ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Nombre ' ,exact:true}).fill( ' Borrador de SO ' ); await page.getByRole( ' checkbox ' , { name: ' Publicar como producto activo ' ,exact:true}).uncheck(); await page.getByRole( ' button ' , { name: ' Guardar ' ,exact:true}).click(); await page.getByRole( ' heading ' , { name: ' Borrador de SO ' ,exact:true}).waitFor(); " )
checks . append ( ' inactive-draft-in-browser ' )
code ( client , " await page.getByRole( ' button ' , { name: ' Editar sistema operativo global ' ,exact:true}).click(); await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); await page.getByLabel( ' Menú de usuario ' , { exact:true}).click(); await page.getByRole( ' combobox ' , { name: ' Idioma ' ,exact:true}).click(); await page.getByRole( ' option ' , { name: ' English ' ,exact:true}).click(); await page.getByRole( ' combobox ' , { name: ' Language ' ,exact:true}).waitFor(); await page.getByLabel( ' User menu ' , { exact:true}).click(); await page.getByRole( ' button ' , { name: ' Edit global operating system ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Major product version ' ,exact:true}).waitFor(); await page.getByRole( ' combobox ' , { name: ' Edition status ' ,exact:true}).click(); await page.getByRole( ' option ' , { name: ' Edition not applicable ' ,exact:true}).waitFor(); await page.keyboard.press( ' Escape ' ); " )
shot ( client , ' english-form ' )
checks . append ( ' english-form-labels-edition-options ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); " )
finally :
report ( )
with context [ ' browser ' ] ( context [ ' config ' ] ) as client :
try :
login ( client , fixture [ ' email ' ] , fixture [ ' password ' ] )
tool ( client , ' browser_resize ' , { ' width ' : 1280 , ' height ' : 1000 } )
tool ( client , ' browser_navigate ' , { ' url ' : product_url } )
code ( client , " await page.getByRole( ' heading ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); await page.getByText( ' Versión principal del producto ' , { exact:true}).waitFor(); if(await page.getByRole( ' button ' , { name: ' Editar sistema operativo global ' ,exact:true}).count())throw Error( ' Administración ordinaria ' ); " )
checks . append ( ' ordinary-public-projection ' )
shot ( client , ' ordinary-detail ' )
asset_url = origin + ' /companies/ ' + company + ' /assets/ ' + fixture [ ' softwareAssets ' ] [ 0 ]
station_url = origin + ' /companies/ ' + company + ' /workstations/ ' + fixture [ ' softwareWorkstations ' ] [ 0 ]
for view , url in [ ( ' asset ' , asset_url ) , ( ' workstation ' , station_url ) ] :
tool ( client , ' browser_navigate ' , { ' url ' : url } )
code ( client , " await page.locator( ' [data-current-operating-systems] ' ).getByRole( ' link ' , { name: ' Windows 11 Pro ' ,exact:true}).first().waitFor(); if(!await page.locator( ' [data-current-operating-systems] ' ).locator( ' a[href= \" " + base + ' / ' + product_id + " \" ] ' ).count())throw Error( ' Destino SO global ' ); " )
code ( client , " await page.locator( ' [data-current-operating-systems] ' ).locator( ' xpath=ancestor::section[1] ' ).scrollIntoViewIfNeeded(); " )
shot ( client , view + ' -current-os ' )
checks . append ( view + ' -global-os-navigation ' )
global_href = base + ' / ' + product_id
if view == ' asset ' :
code ( client , " const row=page.getByRole( ' row ' ).filter( { has:page.locator( ' a[href= \" " + global_href + " \" ] ' )}); await row.getByRole( ' button ' , { name: ' Acciones ' ,exact:true}).click(); await page.getByRole( ' menuitem ' , { name:/Historial/}).click(); await page.getByRole( ' dialog ' , { name:/Historial/}).locator( ' a[href= \" " + global_href + " \" ] ' ).waitFor(); " )
shot ( client , ' installation-history-global-link ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); " )
checks . append ( ' installation-panel-and-history-global-os-navigation ' )
else :
code ( client , " await page.locator( ' [data-workplace-software] a[href= \" " + global_href + " \" ] ' ).waitFor(); await page.locator( ' [data-workplace-map] ' ).scrollIntoViewIfNeeded(); " )
shot ( client , ' workplace-map-global-os ' )
code ( client , " await page.locator( ' [data-workplace-software] a[href= \" " + global_href + " \" ] ' ).click(); await page.getByRole( ' heading ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); if(new URL(page.url()).pathname!== " + json . dumps ( global_href ) + " )throw Error( ' Destino del mapa ' ); " )
checks . append ( ' map-click-opens-global-os-detail ' )
tool ( client , ' browser_navigate ' , { ' url ' : station_url } )
code ( client , " await page.locator( ' [data-workplace-equipment=principal] a ' ).click(); await page.getByRole( ' heading ' , { name: ' AUDIT-R23-PORT-01 ' ,exact:true}).waitFor(); " )
checks . append ( ' map-equipment-pointer-navigation ' )
tool ( client , ' browser_navigate ' , { ' url ' : asset_url } )
code ( client , " await page.getByRole( ' button ' , { name: ' Añadir instalación ' ,exact:true}).click(); await page.getByRole( ' dialog ' , { name: ' Añadir instalación ' ,exact:true}).getByRole( ' button ' , { name: ' Software ' ,exact:true}).click(); await page.getByRole( ' dialog ' , { name: ' Seleccionar software ' ,exact:true}).getByRole( ' textbox ' , { name: ' Buscar por nombre o proveedor ' ,exact:true}).fill( ' Windows 11 Pro ' ); await page.getByRole( ' dialog ' , { name: ' Seleccionar software ' ,exact:true}).getByRole( ' cell ' , { name: ' Windows 11 Pro ' ,exact:true}).first().waitFor(); if(await page.getByRole( ' dialog ' , { name: ' Seleccionar software ' ,exact:true}).getByRole( ' cell ' , { name: ' Windows 11 Pro ' ,exact:true}).count()!==2)throw Error( ' Coexistencia ' ); " )
shot ( client , ' mixed-picker ' )
checks . append ( ' mixed-picker-global-local-no-replacement ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.keyboard.press( ' Escape ' ); " )
2026-10-26 10:22:23 +00:00
# Revalida los consumidores y diálogos modificados después del cierre anterior.
for theme in [ ' light ' , ' dark ' ] :
for width in [ 320 , 390 , 768 , 1280 , 1600 ] :
tool ( client , ' browser_resize ' , { ' width ' : width , ' height ' : 1000 if width > 768 else 844 } )
tool ( client , ' browser_navigate ' , { ' url ' : asset_url } )
code ( client , " await page.locator( ' [data-current-operating-systems] ' ).getByRole( ' link ' , { name: ' Windows 11 Pro ' ,exact:true}).first().waitFor(); await page.evaluate(theme=>document.documentElement.classList.toggle( ' dark ' ,theme=== ' dark ' ), " + json . dumps ( theme ) + " ); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth+1))throw Error( ' Overflow activo ' ); " )
shot ( client , f ' consumer-asset- { theme } - { width } ' )
tool ( client , ' browser_navigate ' , { ' url ' : station_url } )
code ( client , " await page.locator( ' [data-workplace-software] a[href= \" " + global_href + " \" ] ' ).waitFor(); await page.evaluate(theme=>document.documentElement.classList.toggle( ' dark ' ,theme=== ' dark ' ), " + json . dumps ( theme ) + " ); await page.locator( ' [data-workplace-map] ' ).scrollIntoViewIfNeeded(); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth+1))throw Error( ' Overflow puesto ' ); " )
code ( client , " page.osNode=page.locator( ' [data-workplace-software] ' ).filter( { has:page.locator( ' a[href= \" " + global_href + " \" ] ' )}); await page.osNode.locator( ' [data-workplace-node-menu] ' ).focus(); await page.keyboard.press( ' Enter ' ); await page.getByRole( ' menu ' ).waitFor(); await page.keyboard.press( ' ArrowDown ' ); if(!await page.evaluate(()=>!!document.activeElement?.closest( ' [role=menu] ' )))throw Error( ' Teclado menú ' ); " )
shot ( client , f ' consumer-menu- { theme } - { width } ' )
contrast = text_contrast ( client , ' [role=menuitem] ' )
if not contrast or any ( item [ ' ratio ' ] < 4.5 for item in contrast ) :
raise RuntimeError ( ' Contraste del menú insuficiente: ' + json . dumps ( contrast ) )
focus = context [ ' result_json ' ] ( code ( client , " return await page.evaluate(()=> { const style=getComputedStyle(document.activeElement);return { outline:style.outlineWidth,shadow:style.boxShadow}}); " ) )
if focus [ ' outline ' ] == ' 0px ' and focus [ ' shadow ' ] == ' none ' :
raise RuntimeError ( ' Foco sin indicador visible ' )
measurements . append ( { ' consumerMenu ' : width , ' theme ' : theme , ' contrast ' : contrast , ' focus ' : focus } )
code ( client , " await page.getByRole( ' menuitem ' , { name: ' Historial de la instalación ' ,exact:true}).click(); await page.getByRole( ' dialog ' ).locator( ' a[href= \" " + global_href + " \" ] ' ).waitFor(); if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth+1))throw Error( ' Overflow historial ' ); " )
shot ( client , f ' consumer-history- { theme } - { width } ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); if(!await page.osNode.locator( ' [data-workplace-node-menu] ' ).evaluate(el=>el===document.activeElement))throw Error( ' Foco historial ' ); await page.keyboard.press( ' Enter ' ); await page.getByRole( ' menuitem ' , { name: ' Editar instalación ' ,exact:true}).click(); await page.getByRole( ' dialog ' ).getByRole( ' textbox ' , { name: ' Versión ' ,exact:true}).waitFor(); await page.keyboard.press( ' Tab ' ); if(!await page.evaluate(()=>!!document.activeElement?.closest( ' [role=dialog] ' )))throw Error( ' Tab diálogo ' ); " )
shot ( client , f ' consumer-editor- { theme } - { width } ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); if(!await page.osNode.locator( ' [data-workplace-node-menu] ' ).evaluate(el=>el===document.activeElement))throw Error( ' Foco edición ' ); " )
measurements . append ( { ' consumerViewport ' : width , ' theme ' : theme , ' overflow ' : False , ' keyboardMenu ' : True , ' dialogTab ' : True , ' focusReturn ' : True } )
checks . extend ( [ ' consumer-asset-workstation-light-dark-320-390-768-1280-1600 ' , ' map-global-os-menu-keyboard ' , ' map-installation-history-global-reference ' , ' map-installation-editor-tab-escape-focus ' ] )
tool ( client , ' browser_resize ' , { ' width ' : 1280 , ' height ' : 1000 } )
code ( client , " await page.osNode.locator( ' [data-workplace-node-menu] ' ).click(); await page.getByRole( ' menuitem ' , { name: ' Editar instalación ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Versión ' ,exact:true}).fill( ' 25H2 ' ); await page.getByRole( ' button ' , { name: ' Guardar ' ,exact:true}).click(); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); await page.locator( ' [data-current-operating-systems] ' ).getByText( ' Versión 25H2 ' , { exact:true}).waitFor(); " )
shot ( client , ' consumer-version-updated ' )
checks . append ( ' version-save-refreshes-workstation ' )
tool ( client , ' browser_navigate ' , { ' url ' : asset_url } )
code ( client , " await page.locator( ' [data-current-operating-systems] ' ).getByText( ' Versión 25H2 ' , { exact:true}).waitFor(); await page.locator( ' [data-current-operating-systems] ' ).locator( ' a[href= \" /companies/ " + company + " /resources/ " + local [ ' id ' ] + " \" ] ' ).click(); await page.getByRole( ' heading ' , { name: ' Windows 11 Pro ' ,exact:true}).waitFor(); " )
checks . append ( ' version-refreshes-asset-local-navigation-preserved ' )
tool ( client , ' browser_navigate ' , { ' url ' : station_url } )
code ( client , " await page.getByLabel( ' Menú de usuario ' , { exact:true}).click(); await page.getByRole( ' combobox ' , { name: ' Idioma ' ,exact:true}).click(); await page.getByRole( ' option ' , { name: ' English ' ,exact:true}).click(); await page.getByLabel( ' User menu ' , { exact:true}).click(); await page.locator( ' [data-workplace-software] ' ).filter( { has:page.locator( ' a[href= \" " + global_href + " \" ] ' )}).locator( ' [data-workplace-node-menu] ' ).click(); await page.getByRole( ' menuitem ' , { name: ' Edit installation ' ,exact:true}).click(); await page.getByRole( ' textbox ' , { name: ' Version ' ,exact:true}).waitFor(); " )
shot ( client , ' consumer-english-editor ' )
code ( client , " await page.keyboard.press( ' Escape ' ); await page.getByRole( ' dialog ' ).waitFor( { state: ' hidden ' }); " )
checks . append ( ' consumer-english-menu-editor ' )
2026-10-25 19:39:06 +00:00
finally :
report ( )
print ( ' SO global: recorrido MCP verificado. Evidencias: ' + str ( directory . relative_to ( context [ ' ROOT ' ] ) ) , flush = True )