1"use strict";(globalThis.webpackChunkserenity_users_guide=globalThis.webpackChunkserenity_users_guide||[]).push([[7394],{3112(e,a,n){n.r(a),n.d(a,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"screenplay/screenplay_webdriver","title":"Pruebas Web con Serenity Screenplay","description":"Introduccion","source":"@site/i18n/es/docusaurus-plugin-content-docs/current/screenplay/screenplay-webdriver.md","sourceDirName":"screenplay","slug":"/screenplay/screenplay_webdriver","permalink":"/es/docs/screenplay/screenplay_webdriver","draft":false,"unlisted":false,"editUrl":"https://github.com/serenity-bdd/serenity-bdd.github.io/blob/master/docs/screenplay/screenplay-webdriver.md","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"id":"screenplay_webdriver","sidebar_position":2},"sidebar":"tutorialSidebar","previous":{"title":"Fundamentos de Screenplay","permalink":"/es/docs/screenplay/screenplay_fundamentals"},"next":{"title":"Pruebas Web con Serenity Screenplay y Playwright","permalink":"/es/docs/screenplay/screenplay_playwright"}}');var o=n(4848),l=n(8453);const i={id:"screenplay_webdriver",sidebar_position:2},r="Pruebas Web con Serenity Screenplay",d={},c=[{value:"Introduccion",id:"introduccion",level:2},{value:"Abriendo una URL",id:"abriendo-una-url",level:2},{value:"Abriendo una URL directamente",id:"abriendo-una-url-directamente",level:3},{value:"Abriendo la URL de un Page Object",id:"abriendo-la-url-de-un-page-object",level:3},{value:"Usando paginas con nombre",id:"usando-paginas-con-nombre",level:3},{value:"Localizando elementos en una pagina",id:"localizando-elementos-en-una-pagina",level:2},{value:"CSS y XPath",id:"css-y-xpath",level:3},{value:"Usando localizadores de Selenium",id:"usando-localizadores-de-selenium",level:3},{value:"Usando la clase Target",id:"usando-la-clase-target",level:3},{value:"Usando Target dinamicos",id:"usando-target-dinamicos",level:3},{value:"Usando Page Element",id:"usando-page-element",level:3},{value:"Interactuando con elementos",id:"interactuando-con-elementos",level:2},{value:"Clases de Interaction de Screenplay",id:"clases-de-interaction-de-screenplay",level:3},{value:"Clear",id:"clear",level:3},{value:"Click",id:"click",level:3},{value:"DoubleClick",id:"doubleclick",level:3},{value:"Enter y SendKeys",id:"enter-y-sendkeys",level:3},{value:"Evaluar una expresion Javascript",id:"evaluar-una-expresion-javascript",level:3},{value:"Presionar una tecla particular",id:"presionar-una-tecla-particular",level:3},{value:"Trabajando con checkbox",id:"trabajando-con-checkbox",level:3},{value:"JavaScriptClick",id:"javascriptclick",level:3},{value:"Moviendo el mouse",id:"moviendo-el-mouse",level:3}
1,{value:"Realizando acciones en colecciones de elementos",id:"realizando-acciones-en-colecciones-de-elementos",level:3},{value:"RightClick",id:"rightclick",level:3},{value:"Desplazando elementos a la vista",id:"desplazando-elementos-a-la-vista",level:3},{value:"Seleccionando de dropdowns",id:"seleccionando-de-dropdowns",level:3},{value:"Cambiando a otra ventana o frame",id:"cambiando-a-otra-ventana-o-frame",level:3},{value:"Tratando con dialogos de Alerta",id:"tratando-con-dialogos-de-alerta",level:3},{value:"Upload",id:"upload",level:3},{value:"Trabajando con Chrome DevTools",id:"trabajando-con-chrome-devtools",level:2},{value:"Consultando la pagina web",id:"consultando-la-pagina-web",level:2},{value:"Question de WebDriver incluidas",id:"question-de-webdriver-incluidas",level:2},{value:"Absence",id:"absence",level:3},{value:"Attribute",id:"attribute",level:3},{value:"CheckboxValue",id:"checkboxvalue",level:3},{value:"CSSValue",id:"cssvalue",level:3},{value:"CurrentlyEnabled",id:"currentlyenabled",level:3},{value:"CurrentVisibility",id:"currentvisibility",level:3},{value:"Disabled",id:"disabled",level:3},{value:"Displayed",id:"displayed",level:3},{value:"Enabled",id:"enabled",level:3},{value:"Presence",id:"presence",level:3},{value:"SelectedStatus",id:"selectedstatus",level:3},{value:"TextContent",id:"textcontent",level:3},{value:"TheCoordinates",id:"thecoordinates",level:3},{value:"TheLocation",id:"thelocation",level:3},{value:"TheSize",id:"thesize",level:3},{value:"Value",id:"value",level:3},{value:"Visibility",id:"visibility",level:3},{value:"Trabajando con Dropdown",id:"trabajando-con-dropdown",level:3},{value:"Manejando Esperas",id:"manejando-esperas",level:2},{value:"Usando la clase WaitUntil",id:"usando-la-clase-waituntil",level:3},{value:"Esperando una condicion de WebDriver",id:"esperando-una-condicion-de-webdriver",level:3},{value:"Esperando con Target",id:"esperando-con-target",level:3}];function t(e){const a={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.header,{children:(0,o.jsx)(a.h1,{id:"pruebas-web-con-serenity-screenplay",children:"Pruebas Web con Serenity Screenplay"})}),"\n",(0,o.jsx)(a.h2,{id:"introduccion",children:"Introduccion"}),"\n",(0,o.jsx)(a.p,{children:"Las pruebas web son un caso de uso comun para los Scenario de Screenplay, donde tratamos de modelar el comportamiento e interacciones del usuario con el sistema. En esta seccion, aprenderemos como interactuar con una aplicacion web usando la integracion de Screenplay con WebDriver."}),"\n",(0,o.jsx)(a.h2,{id:"abriendo-una-url",children:"Abriendo una URL"}),"\n",(0,o.jsx)(a.h3,{id:"abriendo-una-url-directamente",children:"Abriendo una URL directamente"}),"\n",(0,o.jsxs)(a.p,{children:["En Screenplay, abres una nueva pagina usando la clase de Interaction ",(0,o.jsx)(a.code,{children:"Open"}),". Esto puede funcionar con una URL, por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'toby.attemptsTo(Open.url("https://todomvc.com/examples/angularjs/#/"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"abriendo-la-url-de-un-page-object",children:"Abriendo la URL de un Page Object"}),"\n",(0,o.jsxs)(a.p,{children:["Si has definido un Page Object con una url por defecto, puedes abrir un Page Object refiriendote a la clase del Page Object. Supongamos que hemos definido el siguiente Page Object de Serenity, y establecimos el valor ",(0,o.jsx)(a.code,{children:"@DefaultUrl"})," a la URL de la aplicacion TodoMVC:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'@DefaultUrl("https://todomvc.com/examples/angularjs/#/")\npublic class TodoMvcPage extends PageObject {}\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Ahora podemos abrir esta pagina usando el metodo ",(0,o.jsx)(a.code,{children:"Open.browserOn()"}),", asi:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"toby.attemptsTo(Open.browserOn().the(TodoMvcPage.class));\n"})}),"\n",(0,o.jsx)(a.h3,{id:"usando-paginas-con-nombre",children:"Usando paginas con nombre"}),"\n",(0,o.jsxs)(a.p,{children:["A veces puede ser conveniente almacenar las URLs para diferentes entornos o servidores en el archivo ",(0,o.jsx)(a.code,{children:"serenity.conf"}),", y referirse a ellas por el nombre de la propiedad en nuestro codigo de test."]}),"\n",(0,o.jsxs)(a.p,{children:["Por ejemplo, imagina que quieremos ejecutar nuestros tests contra las implementaciones de Angular, React y Polymer de la aplicacion TodoMVC. Cada aplicacion tiene una URL diferente, que podriamos almacenar en el archivo ",(0,o.jsx)(a.code,{children:"serenity.conf"})," asi:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-json",children:'pages {\n angular = "https://todomvc.com/examples/angularjs/#/"\n react = "https://todomvc.com/examples/react/#/"\n polymer = "https://todomvc.com/examples/polymer/index.html"\n}\n'})}),"\n",(0,o.jsxs)(a.p,{children:["A continuacion, podemos referirnos a estas propiedades en nuestro codigo usando el metodo ",(0,o.jsx)(a.code,{children:"thePageNamed()"}),", asi:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'toby.attemptsTo(Open.browserOn().thePageNamed("pages.react"));\n'})}),"\n",(0,o.jsx)(a.h2,{id:"localizando-elementos-en-una-pagina",children:"Localizando elementos en una pagina"}),"\n",(0,o.jsx)(a.p,{children:"En Screenplay, puedes usar varias estrategias diferentes para localizar los elementos con los que necesitas interactuar."}),"\n",(0,o.jsx)(a.h3,{id:"css-y-xpath",children:"CSS y XPath"}),"\n",(0,o.jsx)(a.p,{children:"La forma mas simple de localizar un elemento es usar una expresion CSS o XPath, como se muestra aqui:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'toby.attemptsTo(\n Click.on("#login-button")\n);\n'})}),"\n",(0,o.jsx)(a.p,{children:"O"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"toby.attemptsTo(\n Click.on(\"//input[@id='login-button']\")\n);\n"})}),"\n",(0,o.jsx)(a.p,{children:'Serenity interpretara la cadena para determinar si es una expresion XPath o CSS. En algunos casos puede haber alguna ambiguedad, y Serenity usara XPath por defecto. Si esto no es lo esperado, puedes usar los prefijos "xpath:" o "css:" para especificar que tipo de localizador quieres:'}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'toby.attemptsTo(\n Click.on("css:input[name=login-button]")\n);\n'})}),"\n",(0,o.jsx)(a.h3,{id:"usando-localizadores-de-selenium",children:"Usando localizadores de Selenium"}),"\n",(0,o.jsxs)(a.p,{children:["Tambien puedes usar cualquiera de las clases localizadoras estandar de Selenium (",(0,o.jsx)(a.code,{children:"org.openqa.selenium.By"}),"), como se muestra aqui:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'toby.attemptsTo(\n Click.on(By.id("login-button"))\n);\n'})}),"\n",(0,o.jsx)(a.h3,{id:"usando-la-clase-target",children:"Usando la clase Target"}),"\n",(0,o.jsxs)(a.p,{children:["Usar localizadores de texto o ",(0,o.jsx)(a.code,{children:"By"})," tiene la ventaja de ser conciso, pero puede llevar a reportes de prueba poco legibles, especialmente cuando se usan localizadores XPath o CSS complejos o sin significado. En Screenplay, la clase ",(0,o.jsx)(a.code,{children:"Target"})," nos permite dar un nombre mas significativo a una estrategia de localizacion. Por ejemplo, c
1onsidera el siguiente codigo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"toby.attemptsTo(Click.on(\"//button[.='Add']\"));\n"})}),"\n",(0,o.jsx)(a.p,{children:"En los reportes de Serenity, este paso se reportara como \"Toby clicks on //button[.='Add']\", lo cual no es muy legible."}),"\n",(0,o.jsxs)(a.p,{children:["Si representamos este boton usando la clase ",(0,o.jsx)(a.code,{children:"Target"}),', podemos asociar una etiqueta como "Add to cart button", asi:']}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'Target ADD_TO_CART = Target.the("Add to cart button").located(By.cssSelector("//button[.=\'Add\']"));\n\ntoby.attemptsTo(Click.on(ADD_TO_CART));\n'})}),"\n",(0,o.jsx)(a.p,{children:'En los reportes, este paso ahora aparecera como "Toby clicks on Add to cart button".'}),"\n",(0,o.jsx)(a.h3,{id:"usando-target-dinamicos",children:"Usando Target dinamicos"}),"\n",(0,o.jsxs)(a.p,{children:["Tambien puedes incluir variables en un localizador ",(0,o.jsx)(a.code,{children:"Target"}),', para hacer tus localizadores dinamicos. Puedes incluir parametros numerados usando "',0,'", "',1,'", etc., y luego usar el metodo ',(0,o.jsx)(a.code,{children:"of()"})," para instanciar el ",(0,o.jsx)(a.code,{children:"Target"})," con el valor que te interesa. Por ejemplo, podriamos crear un localizador generico para un boton que contiene un texto dado asi:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"Target BUTTON_WITH_LABEL = Target.the(\"{0} button\").located(By.cssSelector(\"//button[.='{0}']\"));\n\ntoby.attemptsTo(Click.on(BUTTON_WITH_LABEL.of('Add')));\n"})}),"\n",(0,o.jsx)(a.p,{children:"Incluso podriamos usar este Target dinamico para definir otros Target con valores especificos, asi:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"Target BUTTON_WITH_LABEL = Target.the(\"{0} button\").located(By.cssSelector(\"//button[.='{0}']\"));\nTarget ADD_BUTTON = BUTTON_WITH_LABEL.of('Add');\n\ntoby.attemptsTo(Click.on(ADD_BUTTON));\n"})}),"\n",(0,o.jsx)(a.h3,{id:"usando-page-element",children:"Usando Page Element"}),"\n",(0,o.jsxs)(a.p,{children:["Los ",(0,o.jsx)(a.a,{href:"../../docs/guide/page_elements",children:"Page Element"})," de Serenity proporcionan una forma mas intuitiva y legible de localizar elementos en una pagina, a menudo sin necesidad de usar XPath o CSS. Con Page Element, puedes identificar elementos usando expresiones como las siguientes"]}),"\n",(0,o.jsxs)(a.ul,{children:["\n",(0,o.jsx)(a.li,{children:(0,o.jsx)(a.code,{children:'Click.on(Button.withText("Add to cart"))'})}),"\n",(0,o.jsx)(a.li,{children:(0,o.jsx)(a.code,{children:'Enter.theValue(").into(InputField.withPlaceholder("Enter the customer name"))'})}),"\n",(0,o.jsx)(a.li,{children:(0,o.jsx)(a.code,{children:'Click.on(PageElement.locatedBy(".item").containingText("Bananas"))'})}),"\n"]}),"\n",(0,o.jsxs)(a.p,{children:["Puedes aprender mas sobre Page Element ",(0,o.jsx)(a.a,{href:"../../docs/guide/page_elements",children:"aqui"}),"."]}),"\n",(0,o.jsx)(a.h2,{id:"interactuando-con-elementos",children:"Interactuando con elementos"}),"\n",(0,o.jsx)(a.p,{children:"En esta seccion veremos como interactuar con elementos en una pagina web usando Selenium WebDriver con Serenity Screenplay."}),"\n",(0,o.jsx)(a.h3,{id:"clases-de-interaction-de-screenplay",children:"Clases de Interaction de Screenplay"}),"\n",(0,o.jsxs)(a.p,{children:["Puedes encontrar las clases de Interaction estandar de Serenity en el paquete ",(0,o.jsx)(a.code,{children:"net.serenitybdd.screenplay.actions"}),"."]}),"\n",(0,o.jsxs)(a.table,{children:[(0,o.jsx)(a.thead,{children:(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.th,{children:"Interaction"}),(0,o.jsx)(a.th,{children:"Proposito"}),(0,o.jsx)(a.th,{children:"Ejemplo"})]})}),(0,o.jsxs)(a.tbody,{children:[(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Clear"}),(0,o.jsx)(a.td,{children:"Limpiar un campo de entrada"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Clear.field("#firstname"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Click"}),(0,o.jsx)(a.td,{children:"Hacer clic en un elemento"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Click.on("#add-to-cart"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"DoubleClick"}),(0,o.jsx)(a.td,{children:"Doble clic en un elemento usando una Action de Selenium"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(DoubleClick.on("#add-to-cart"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Enter"}),(0,o.jsx)(a.td,{children:"Escribir un valor en un campo de entrada"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Enter.theValue("scott").into("#username"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Evaluate"}),(0,o.jsx)(a.td,{children:"Evaluar una expresion Javascript"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Evaluate.javascript("window.localStorage.clear();")'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Hit"}),(0,o.jsx)(a.td,{children:"Presionar una tecla"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Hit.the(Keys.ENTER).into("#searchterms"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"JavaScriptClick"}),(0,o.jsx)(a.td,{children:"Hacer clic en un elemento usando Javascript en lugar de Selenium"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(JavaScriptClick.on("#add-to-cart"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"MoveMouse"}),(0,o.jsx)(a.td,{children:"Mover el mouse sobre un elemento especificado"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(MoveMouse.to("#main-menu"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Open"}),(0,o.jsx)(a.td,{children:"Abrir una URL o pagina especifica"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Open.url("https://www.google.com"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"PerformOn"}),(0,o.jsx)(a.td,{children:"Realizar una o mas acciones en varios elementos"}),(0,o.jsx)(a.td,{children:"Ver abajo"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"RightClick"}),(0,o.jsx)(a.td,{children:"Clic derecho en un elemento dado"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(RightClick.on("#menu"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Scroll"}),(0,o.jsx)(a.td,{children:"Desplazar hasta un elemento usando Javascript"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Scroll.to("#terms-and-conditions"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"SelectFromOptions"}),(0,o.jsx)(a.td,{children:"Seleccionar un valor en un dropdown HTML"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(SelectFromOptions.byVisibleText("Red").from("#color"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"SendKeys"}),(0,o.jsx)(a.td,{children:"Introducir un valor en un campo usando el metodo sendKeys() de Selenium"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(SendKeys.of("scott").into("#username"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"SetCheckbox"}),(0,o.jsx)(a.td,{children:"Marcar un campo checkbox"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(SetCheckbox.of("#subscribe-to-newsletter").toTrue())'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Switch"}),(0,o.jsx)(a.td,{children:"Cambiar a otra ventana o pestana"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:"actor.attemptsTo(Switch.toNewWindow())"})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Upload"}),(0,o.jsx)(a.td,{children:"Subir un archivo usando un campo de carga HTML"}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:'actor.attemptsTo(Upload.theFile(pathToFile)).to("#uploaded-file"))'})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"WithDevTools"}),(0,o.jsx)(a.td,{children:"Realizar una accion con Chrome DevTools"}),(0,o.jsx)(a.td,{children:"Ver abajo"})]})]})]}),"\n",(0,o.jsx)(a.p,{children:"Las Interaction mas importantes se describen con mas detalle en las siguientes secciones."}),"\n",(0,o.jsx)(a.h3,{id:"clear",children:"Clear"}),"\n",(0,o.jsxs)(a.p,{children:["La Interaction ",(0,o.jsx)(a.code,{children:"Clear"})," restablece el valor de un elemento de formulario HTML."]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Clear.field(By.id("first-name")));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"click",children:"Click"}),"\n",(0,o.jsx)(a.p,{children:"Hacer clic en un boton o elemento."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Click.on("#some-button"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["A veces un elemento no esta en un estado interactuable cuando intentamos hacer clic en el por primera vez. Por ejemplo, puede estar deshabilitado, o aun no visible en la pagina. En estos casos, podemos pedir a Serenity que espere a que el elemento este habilitado usando el metodo ",(0,o.jsx)(a.code,{children:"afterWaitingUntilEnabled()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Click.on("#some-button").afterWaitingUntilEnabled());\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Si el elemento aun no se ha renderizado, podemos usar el metodo ",(0,o.jsx)(a.code,{children:"afterWaitingUntilPresent()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Click.on("#some-button").afterWaitingUntilPresent());\n'})}),"\n",(0,o.jsxs)(a.p,{children:["En ambos casos, Serenity esperara hasta 5 segundos por defecto para que el elemento este presente o disponible. Puedes configurar este tiempo de espera usando la propiedad del sistema ",(0,o.jsx)(a.code,{children:"webdriver.wait.for.timeout"})," (definida en milisegundos)."]}),"\n",(0,o.jsx)(a.h3,{id:"doubleclick",children:"DoubleClick"}),"\n",(0,o.jsx)(a.p,{children:"Doble clic en un boton o elemento, usando Selenium Actions."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(DoubleClick.on("#some-button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"enter-y-sendkeys",children:"Enter y SendKeys"}),"\n",(0,o.jsx)(a.p,{children:"Hay dos formas de introducir un valor en un campo."}),"\n",(0,o.jsxs)(a.p,{children:[(0,o.jsx)(a.code,{children:"Enter"})," introducira un valor en un campo, primero esperando hasta que el campo este habilitado, y luego limpiando el campo de cualquier valor actual, antes de introducir el valor especificado."]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Enter.theValue("Sarah-Jane").into("#firstName"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:[(0,o.jsx)(a.code,{children:"SendKeys"})," realizara el equivalente del ",(0,o.jsx)(a.code,{children:"sendKeys()"})," de Selenium, puedes usar ",(0,o.jsx)(a.code,{children:"Enter.keyValue()"})," en lugar de ",(0,o.jsx)(a.code,{children:"Enter.theValue()"})]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(SendKeys.of("Sarah-Jane").into("#firstName"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"evaluar-una-expresion-javascript",children:"Evaluar una expresion Javascript"}),"\n",(0,o.jsxs)(a.p,{children:["El Task ",(0,o.jsx)(a.code,{children:"Evaluate"})," ejecuta un comando JavaScript en el contexto del frame o ventana actualmente seleccionad
1a. Por ejemplo, el siguiente codigo limpiara el almacenamiento local en el navegador de Dina:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'dina.attemptsTo(Evaluate.javascript("window.localStorage.clear()"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Si el script tiene un valor de retorno (es decir, si el script contiene una declaracion return), tambien puedes recuperar el valor devuelto por una expresion Javascript. Puedes hacer esto de dos formas. La primera es usar el metodo ",(0,o.jsx)(a.code,{children:"result()"})," para convertir la accion ",(0,o.jsx)(a.code,{children:"Evaluate"})," en una Question. Puedes ver un ejemplo aqui:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' Long result = (Long) dina.asksFor(Evaluate.javascript("return 1 + 1").result());\n assertThat(result).isEqualTo(2);\n'})}),"\n",(0,o.jsx)(a.p,{children:"El tipo de objeto devuelto por WebDriver es el siguiente:"}),"\n",(0,o.jsxs)(a.ul,{children:["\n",(0,o.jsxs)(a.li,{children:["Para un elemento HTML, este metodo devuelve un ",(0,o.jsx)(a.code,{children:"WebElement"})]}),"\n",(0,o.jsxs)(a.li,{children:["Para un decimal, se devuelve un ",(0,o.jsx)(a.code,{children:"Double"})]}),"\n",(0,o.jsxs)(a.li,{children:["Para un numero no decimal, se devuelve un ",(0,o.jsx)(a.code,{children:"Long"})]}),"\n",(0,o.jsxs)(a.li,{children:["Para un booleano, se devuelve un ",(0,o.jsx)(a.code,{children:"Boolean"})]}),"\n",(0,o.jsxs)(a.li,{children:["Para todos los demas casos, se devuelve un ",(0,o.jsx)(a.code,{children:"String"}),"."]}),"\n",(0,o.jsxs)(a.li,{children:["Para un array, devuelve una ",(0,o.jsx)(a.code,{children:"List<Object>"})," con cada objeto siguiendo las reglas anteriores. Soportamos listas anidadas."]}),"\n",(0,o.jsxs)(a.li,{children:["Para un map, devuelve un ",(0,o.jsx)(a.code,{children:"Map<String, Object>"})," con valores siguiendo las reglas anteriores."]}),"\n"]}),"\n",(0,o.jsx)(a.h3,{id:"presionar-una-tecla-particular",children:"Presionar una tecla particular"}),"\n",(0,o.jsxs)(a.p,{children:["Puedes introducir cualquier tecla o combinacion de teclas de Selenium usando el Task ",(0,o.jsx)(a.code,{children:"Enter"}),". Tambien puedes querer usar el Task ",(0,o.jsx)(a.code,{children:"Hit"})," para mayor legibilidad. La clase de Interaction ",(0,o.jsx)(a.code,{children:"Hit"})," es similar a la clase ",(0,o.jsx)(a.code,{children:"Enter"}),", pero toma una lista de uno o mas valores ",(0,o.jsx)(a.code,{children:"Keys"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Enter.theValue("Sarah-Jane").into(By.id("firstName")));\n dina.attemptsTo(Hit.the(Keys.TAB).into(By.id("firstName")));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"trabajando-con-checkbox",children:"Trabajando con checkbox"}),"\n",(0,o.jsxs)(a.p,{children:["Puedes marcar o desmarcar un elemento checkbox haciendo clic en el usando la Interaction ",(0,o.jsx)(a.code,{children:"Click"}),". Si quieres estar seguro de que el elemento esta marcado o desmarcado, tambien puedes usar la clase ",(0,o.jsx)(a.code,{children:"SetCheckbox"}),", para marcar o desmarcar el campo."]}),"\n",(0,o.jsx)(a.p,{children:"Por ejemplo, para marcar el checkbox de Terminos y Condiciones en un formulario, podrias usar lo siguiente:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(SetCheckbox.of("#terms-and-conditions").toTrue());\n'})}),"\n",(0,o.jsx)(a.p,{children:"Y para desmarcarlo, podrias hacer esto:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(SetCheckbox.of("#terms-and-conditions").toFalse());\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Dado que habilitar y deshabilitar checkbox implica hacer clic, tambien podemos usar los metodos ",(0,o.jsx)(a.code,{children:"afterWaitingUntilEnabled()"})," y ",(0,o.jsx)(a.code,{children:"afterWaitingUntilPresent()"})," disponibles con la clase de Interaction ",(0,o.jsx)(a.code,{children:"Click"}),", por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(\n SetCheckbox.of("#terms-and-conditions").toFalse()\n .afterWaitingUntilEnabled());\n'})}),"\n",(0,o.jsx)(a.h3,{id:"javascriptclick",children:"JavaScriptClick"}),"\n",(0,o.jsxs)(a.p,{children:["A veces es util poder saltarse Selenium y realizar un click() directamente con JavaScript. Podemos hacer esto con la clase ",(0,o.jsx)(a.code,{children:"JavaScriptClick"}),". La clase tiene la misma API que la clase ",(0,o.jsx)(a.code,{children:"Click"}),", por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(JavaScriptClick.on("#button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"moviendo-el-mouse",children:"Moviendo el mouse"}),"\n",(0,o.jsxs)(a.p,{children:["Podemos mover el mouse a un elemento en la pagina usando ",(0,o.jsx)(a.code,{children:"MoveMouse"}),", por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(MoveMouse.to("#button"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Si necesitamos realizar una o mas acciones en el elemento una vez que hemos movido el cursor sobre el, podemos hacerlo usando el metodo ",(0,o.jsx)(a.code,{children:"andThen()"})," con una expresion Lambda, a la que se le pasa el objeto Actions. Por ejemplo, para hacer clic en el boton despues de mover el cursor hacia el, podriamos hacer lo siguiente:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" dina.attemptsTo(MoveMouse.to(BUTTON).andThen(actions -> actions.click()));\n"})}),"\n",(0,o.jsx)(a.h3,{id:"realizando-acciones-en-colecciones-de-elementos",children:"Realizando acciones en cole
1cciones de elementos"}),"\n",(0,o.jsx)(a.p,{children:"Tambien podemos realizar acciones en una coleccion de elementos. Supongamos que tenemos una pagina HTML que contiene una lista de checkbox como esta:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-html",children:' <div>\n <label>Condiments:</label>\n Salt <input type="checkbox" id="salt" class="condiment" name="salt">\n Pepper <input type="checkbox" id="pepper" class="condiment" name="pepper">\n Sauce <input type="checkbox" id="sause" class="condiment" name="sauce">\n </div>\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Podriamos marcar cada uno de estos checkbox de una vez usando el metodo ",(0,o.jsx)(a.code,{children:"PerformOn.eachMatching()"}),". Este toma dos parametros:"]}),"\n",(0,o.jsxs)(a.ul,{children:["\n",(0,o.jsxs)(a.li,{children:["Un localizador (un Target, localizador ",(0,o.jsx)(a.code,{children:"By"}),", o expresion CSS o XPath)"]}),"\n",(0,o.jsxs)(a.li,{children:["Una expresion lambda que acepta un ",(0,o.jsx)(a.code,{children:"WebElementFacade"})]}),"\n"]}),"\n",(0,o.jsx)(a.p,{children:"Si quisieramos hacer clic en cada uno de estos checkbox, podriamos hacer lo siguiente:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(\n PerformOn.eachMatching(".condiment", WebElementFacade::click)\n );\n'})}),"\n",(0,o.jsx)(a.p,{children:"Tambien puedes usar Performable de Screenplay, como se muestra en este ejemplo:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(\n PerformOn.eachMatching(".condiment",\n checkbox -> dina.attemptsTo(SetCheckbox.of(checkbox).toTrue()))\n );\n'})}),"\n",(0,o.jsx)(a.h3,{id:"rightclick",children:"RightClick"}),"\n",(0,o.jsxs)(a.p,{children:["Puedes hacer clic derecho en un elemento usando la clase ",(0,o.jsx)(a.code,{children:"RightClick"}),". Esto usara el metodo de accion ",(0,o.jsx)(a.code,{children:"contextClick()"})," de Selenium:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(RightClick.on("#button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"desplazando-elementos-a-la-vista",children:"Desplazando elementos a la vista"}),"\n",(0,o.jsxs)(a.p,{children:["A veces puede ser util desplazarse hasta un elemento especifico en la pagina. Puedes hacer esto con la clase ",(0,o.jsx)(a.code,{children:"Scroll"}),", asi, que usa Javascript para desplazar el elemento a la vista."]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Scroll.to(By.id("#button")));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Esta clase usa el metodo Javascript ",(0,o.jsx)(a.code,{children:"scrollIntoView()"}),", que por defecto desplazara la pantalla para que la parte superior del elemento este alineada con la parte superior del area visible del ancestro desplazable. Tambien puedes alinear la parte inferior del elemento con la parte inferior del area visible del ancestro desplazable, usando el metodo ",(0,o.jsx)(a.code,{children:"andAlignToBottom()"}),", por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(Scroll.to(By.id("#button")).andAlignToBottom());\n'})}),"\n",(0,o.jsx)(a.h3,{id:"seleccionando-de-dropdowns",children:"Seleccionando de dropdowns"}),"\n",(0,o.jsxs)(a.p,{children:["Podemos seleccionar un valor de un dropdown usando la clase ",(0,o.jsx)(a.code,{children:"SelectFromOptions"}),". Supongamos que tenemos el siguiente codigo HTML:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-html",children:' <select id="color">\n <option value="red">Red</option>\n <option value="green">Green</option>\n <option value="blue">Blue</option>\n </select>\n'})}),"\n",(0,o.jsx)(a.p,{children:"Podemos seleccionar la segunda de estas opciones de cualquiera de las siguientes formas:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(SelectFromOptions.byVisibleText("Green").from("#color"));\n dina.attemptsTo(SelectFromOptions.byValue("green").from("#color"));\n dina.attemptsTo(SelectFromOptions.byIndex(1).from("#color"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Podemos recuperar el valor actual de una lista desplegable usando la clase Question ",(0,o.jsx)(a.code,{children:"SelectedValue"}),", por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' String selectedValue = dina.asksFor(SelectedValue.of(COLOR_"#color")));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"cambiando-a-otra-ventana-o-frame",children:"Cambiando a otra ventana o frame"}),"\n",(0,o.jsxs)(a.p,{children:["Podemos cambiar a una nueva ventana o pestana usando la clase ",(0,o.jsx)(a.code,{children:"Switch"}),". Por ejemplo, el siguiente codigo abre un enlace en una nueva pestana y camb
1ia el control a esta pestana:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(\n Click.on("#link-that-opens-a-new-tab"),\n Switch.toNewWindow()\n );\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Si solo hay dos ventanas o pestanas abiertas, podemos volver a la ventana original usando el metodo ",(0,o.jsx)(a.code,{children:"Switch.toTheOtherWindow()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" dina.attemptsTo(\n Switch.toTheOtherWindow()\n );\n"})}),"\n",(0,o.jsxs)(a.p,{children:["Otra opcion es usar el nombre o handle de la ventana a la que quieres cambiar, usando ",(0,o.jsx)(a.code,{children:"Switch.toWindow()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" dina.attemptsTo(\n Switch.toWindow(originalWindowHandle)\n );\n"})}),"\n",(0,o.jsxs)(a.p,{children:["Alternativamente, si conoces el titulo de la ventana o pestana, puedes usar el metodo ",(0,o.jsx)(a.code,{children:"Switch.toWindowTitled()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(\n Switch.toWindowTitled("The other window")\n );\n'})}),"\n",(0,o.jsx)(a.p,{children:"Aunque los frames HTML se consideran obsoletos para aplicaciones modernas, todavia existen en algunas aplicaciones antiguas. Puedes interactuar con frames usando los siguientes metodos:"}),"\n",(0,o.jsx)(a.p,{children:"Otras funciones de switch de Selenium se manejan con los siguientes metodos:"}),"\n",(0,o.jsxs)(a.table,{children:[(0,o.jsx)(a.thead,{children:(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.th,{children:"Interaction"}),(0,o.jsx)(a.th,{children:"Proposito"}),(0,o.jsx)(a.th,{children:"Equivalente en Selenium"})]})}),(0,o.jsxs)(a.tbody,{children:[(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Switch.toFrame(index)"}),(0,o.jsx)(a.td,{children:'Seleccionar un frame por su indice (basado en cero). Seleccionar un frame por indice es equivalente a la expresion JS window.frames[index] donde "window" es la ventana DOM representada por el contexto actual. Una vez que el frame ha sido seleccionado, todas las llamadas subsiguientes a la interfaz WebDriver se hacen a ese frame.'}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:"driver.switch().toFrame(index)"})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Switch.toFrame(nameOrId)"}),(0,o.jsx)(a.td,{children:"Seleccionar un frame por su nombre o ID. Los frames localizados por atributos de nombre coincidentes siempre tienen prioridad sobre los que coinciden por ID."}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:"driver.switch().toFrame(nameOrId)"})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Switch.toParentFrame()"}),(0,o.jsx)(a.td,{children:"Cambiar el foco al contexto padre. Si el contexto actual es el contexto de navegacion de nivel superior, el contexto permanece sin cambios."}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:"driver.switchTo().parentFrame()"})})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Switch.toDefaultContext()"}),(0,o.jsx)(a.td,{children:"Selecciona el primer frame en la pagina, o el documento principal cuando una pagina contiene iframes."}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:"driver.switch().toDefaultContext()"})})]})]})]}),"\n",(0,o.jsx)(a.p,{children:"Otras funciones de switch de Selenium se manejan con los siguientes metodos:"}),"\n",(0,o.jsxs)(a.table,{children:[(0,o.jsx)(a.thead,{children:(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.th,{children:"Interaction"}),(0,o.jsx)(a.th,{children:"Proposito"}),(0,o.jsx)(a.th,{children:"Equivalente en Selenium"})]})}),(0,o.jsx)(a.tbody,{children:(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"Switch.toActiveElement()"}),(0,o.jsx)(a.td,{children:'Cambia al elemento que actualmente tiene el foco dentro del documento actualmente "switched to", o al elemento body si esto no puede detectarse. Esto coincide con la semantica de llamar "document.activeElement" en Javascript.'}),(0,o.jsx)(a.td,{children:(0,o.jsx)(a.code,{children:"driver.switchTo().activeElement()"})})]})})]}),"\n",(0,o.jsx)(a.h3,{id:"tratando-con-dialogos-de-alerta",children:"Tratando con dialogos de Alerta"}),"\n",(0,o.jsxs)(a.p,{children:["Podemos trabajar con dialogos de Alerta HTML usando el metodo ",(0,o.jsx)(a.code,{children:"Switch.toAlert()"}),". Por ejemplo, el siguiente codigo cambiara la ventana actual al dialogo de alerta actual:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" dina.attemptsTo(\n Switch.toAlert()\n );\n"})}),"\n",(0,o.jsxs)(a.p,{children:["Podemos consultar el texto de la alerta usando la clase Question ",(0,o.jsx)(a.code,{children:"HtmlAlert.text()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' dina.attemptsTo(\n Switch.toAlert()\n );\n assertThat(dina.asksFor(HtmlAlert.text())).isEqualTo("Are you sure?");\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Tambien podemos aceptar o descartar el mensaje de alerta usando los metodos ",(0,o.jsx)(a.code,{children:"Switch.toAlert().andAccept()"})," y ",(0,o.jsx)(a.code,{children:"Switch.toAlert().andDismiss()"})," respectivamente:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" dina.attemptsTo(\n Switch.toAlert().andAccept()\n );\n"})}),"\n",(0,o.jsx)(a.h3,{id:"upload",children:"Upload"}),"\n",(0,o.jsxs)(a.p,{children:["La forma mas simple de subir un archivo a un campo de carga HTML (uno que tiene un tipo de 'file') es usar el Task ",(0,o.jsx)(a.code,{children:"Upload"}),". Supongamos que tenemos el siguiente campo de formulario HTML:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-html",children:' <input type="file" id="upload-file" name="filename">\n'})}),"\n",(0,o.jsx)(a.p,{children:"Podemos subir un archivo a este campo como se muestra aqui:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' Path fileToUpload = ...\n dina.attemptsTo(Upload.theFile(fileToUpload).to("#upload-file"));\n'})}),"\n",(0,o.jsx)(a.p,{children:"Si estas ejecutando los tests en una maquina remota, puedes usar el Selenium Local File Detector. El Local File Detector permite la transferencia de archivos desde la maquina cliente al servidor remoto. Por ejemplo, si un test necesita subir un archivo a una aplicacion web, un WebDriver remoto puede transferir automaticamente el archivo desde la maquina local al servidor web remoto durante la ejecucion. Esto permite que el archivo sea subido desde la maquina remota que ejecuta el test."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' Path fileToUpload = ...\n dina.attemptsTo(Upload.theFile(fileToUpload).to("#upload-file").usingLocalFileDetector());\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Tambien puedes subir un archivo en los recursos del classpath usando el metodo ",(0,o.jsx)(a.code,{children:"Upload.theClasspathResource()"}),", como se muestra aqui:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' Path fileToUpload = ...\n dina.attemptsTo(Upload.theClasspathResource("some/resource/path.txt").to("#upload-file"));\n'})}),"\n",(0,o.jsx)(a.h2,{id:"trabajando-con-chrome-devtools",children:"Trabajando con Chrome DevTools"}),"\n",(0,o.jsx)(a.p,{children:'Muchos navegadores proporcionan "DevTools" - un conjunto de herramientas que estan integradas con el navegador que los de
1sarrolladores pueden usar para depurar aplicaciones web y explorar el rendimiento de sus paginas. Los DevTools de Google Chrome hacen uso de un protocolo llamado Chrome DevTools Protocol (o "CDP" para abreviar). Como sugiere el nombre, esto no esta disenado para pruebas, ni para tener una API estable, por lo que la funcionalidad depende en gran medida de la version del navegador.'}),"\n",(0,o.jsxs)(a.p,{children:["En Serenity Screenplay, podemos acceder a la biblioteca DevTools de Selenium 4 usando el metodo ",(0,o.jsx)(a.code,{children:"WithDevTools.perform()"}),". Por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" final List<Metric> metricList = new ArrayList<>();\n\n dina.attemptsTo(\n WithDevTools.perform(\n devTools -> {\n devTools.createSession();\n devTools.send(Performance.enable(Optional.empty()));\n metricList.addAll(devTools.send(Performance.getMetrics()));\n }\n )\n );\n"})}),"\n",(0,o.jsxs)(a.p,{children:["Si queremos usar DevTools para recuperar un valor especifico, podemos usar la clase ",(0,o.jsx)(a.code,{children:"DevToolsQuery"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:" List<Metric> metrics = dina.asksFor(\n DevToolsQuery.ask().about(devTools -> {\n devTools.createSession();\n devTools.send(Performance.enable(Optional.empty()));\n return devTools.send(Performance.getMetrics());\n })\n );\n"})}),"\n",(0,o.jsx)(a.h2,{id:"consultando-la-pagina-web",children:"Consultando la pagina web"}),"\n",(0,o.jsx)(a.p,{children:"Serenity Screenplay tambien te da un gran numero de opciones cuando se trata de consultar una interfaz web. La mayoria involucra tipos especiales de clases Question."}),"\n",(0,o.jsx)(a.p,{children:'En los tests web de Screenplay, simplemente puedes implementar una Question que devuelva el tipo de objeto que te interesa, y luego consultar la interfaz de usuario de manera convencional con Webdriver. Por ejemplo, supongamos que queremos leer el nombre de usuario en una pagina, que puede localizarse con el selector CSS ".user-name".'}),"\n",(0,o.jsx)(a.p,{children:"Una asercion de Screenplay para verificar el nombre de usuario podria verse asi:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:' sam.should(seeThat(TheUserName.value(), equalTo("sam")));\n'})}),"\n",(0,o.jsx)(a.p,{children:"Podriamos crear una clase Question TheUserName para consultar este campo de la siguiente manera:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'@Subject("the displayed username")\npublic class TheUserName implements Question<String> {\n @Override\n public String answeredBy(Actor actor) {\n return BrowseTheWeb.as(actor).findBy(".user-name").getText();\n }\n\n public static Question<String> value() { return new TheUserName(); }\n}\n'})}),"\n",(0,o.jsx)(a.p,{children:"Aqui usamos BrowseTheWeb.as(actor) para obtener la API de Serenity WebDriver para la instancia de webdriver del Actor, lo que da acceso a toda la gama de metodos de Page Object de Serenity."}),"\n",(0,o.jsx)(a.p,{children:"Tambien podriamos usar un Target para localizar el nombre de usuario, que podriamos almacenar en una clase Page Component separada:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'public static Target USER_NAME = Target.the("User name").locatedBy(".user-name");\n'})}),"\n",(0,o.jsx)(a.p,{children:"Luego podemos usar el metodo resolveFor() para encontrar el elemento que coincide con ese Target en el navegador del Actor:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'@Subject("the displayed username")\npublic class TheUserName implements Question<String> {\n\n @Override\n public String answeredBy(Actor actor) {\n return USER_NAME.resolveFor(actor).getText();\n }\n\n public static Question<String> value() { return new TheUserName(); }\n}\n'})}),"\n",(0,o.jsx)(a.p,{children:"Alternativamente, podriamos escribir esta clase como una factoria, y usar una expresion lambda en lugar de una clase Question completa:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"public class TheUserName {\n\n public static Question<String> value() {\n return actor -> USER_NAME.resolveFor(actor).getText();\n }\n}\n"})}),"\n",(0,o.jsxs)(a.p,{children:["En este caso, la anotacion ",(0,o.jsx)(a.code,{children:"@Subject"})," no tendra efecto, por lo que necesitamos pasar el nombre del objeto que estamos verificando en la asercion de Screenplay:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'sam.should(seeThat("the displayed username", TheUserName.value(), equalTo("sam")));\n'})}),"\n",(0,o.jsx)(a.p,{children:"Hasta ahora has visto como funcionan las Question de Screenplay en detalle. Esto te ayudara a implementar las tuyas propias si lo necesitas. Sin embargo, Serenity tambien proporciona una serie de atajos relacionados con la consulta de paginas web, que encontraras en el paquete net.serenitybdd.screenplay.questions, que te permiten escribir codigo de automatizacion mucho mas conciso."}),"\n",(0,o.jsx)(a.h2,{id:"question-de-webdriver-incluidas",children:"Question de WebDriver incluidas"}),"\n",(0,o.jsxs)(a.p,{children:["Serenity proporciona muchas clases Question incluidas en el paquete ",(0,o.jsx)(a.code,{children:"net.serenitybdd.screenplay.questions"})," que son una forma abreviada de consultar una pagina web. Por ejemplo, la clase ",(0,o.jsx)(a.code,{children:"Text"})," te permite recuperar el contenido de texto de un elemento, asi:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'String name = sam.asksFor(Text.of("#name"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Si hay muchas entradas coincidentes, podemos recuperarlas todas usando el metodo ",(0,o.jsx)(a.code,{children:"ofEach()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'Collection<String> names = sam.asksFor(Text.ofEach(".name"));\n'})}),"\n",(0,o.jsx)(a.p,{children:"La lista completa de clases Web Question se proporciona aqui."}),"\n",(0,o.jsx)(a.h3,{id:"absence",children:"Absence"}),"\n",(0,o.jsxs)(a.p,{children:["Determinar si un elemento ",(0,o.jsx)(a.em,{children:"no"})," esta presente o visible en la pagina. Un campo que esta presente en el DOM pero no se renderiza se considerara ausente."]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean isNotPresent = sam.asksFor(Absence.of("#no-such-field"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"attribute",children:"Attribute"}),"\n",(0,o.jsx)(a.p,{children:"Verificar el valor de un atributo HTML de un elemento especificado."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'String placeholderText = sam.asksFor(Attribute.of(".new-todo").named("placeholder"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"checkboxvalue",children:"CheckboxValue"}),"\n",(0,o.jsx)(a.p,{children:"Determinar si un checkbox ha sido marcado o no."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean termsAndConditionsApproved = sam.asksFor(CheckboxValue.of("#tnc"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"cssvalue",children:"CSSValue"}),"\n",(0,o.jsx)(a.p,{children:"Recuperar el valor de un atributo CSS especifico de un elemento."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'String font = sam.asksFor(CSSValue.of(target).named("font"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"currentlyenabled",children:"CurrentlyEnabled"}),"\n",(0,o.jsx)(a.p,{children:"Verificar si un elemento esta actualmente habilitado, sin esperar."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean isCurrentlyEnabled = sam.asksFor(CurrentlyEnabled.of("#some-button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"currentvisibility",children:"CurrentVisibility"}),"\n",(0,o.jsx)(a.p,{children:"Verificar si un elemento es actualmente visible, sin esperar."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean isCurrentlyVisible = sam.asksFor(CurrentVisibility.of("#some-button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"disabled",children:"Disabled"}),"\n",(0,o.jsx)(a.p,{children:"Verificar si un elemento esta deshabilitado."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean isDisabled = sam.asksFor(Disabled.of("#a-disabled-button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"displayed",children:"Displayed"}),"\n",(0,o.jsx)(a.p,{children:"Verificar si un elemento se muestra. Si el elemento no se muestra actualmente, el test esperara un breve retraso para darle tiempo a mostrarse."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean isDisplayed = sam.asksFor(Displayed.of("#some-button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"enabled",children:"Enabled"}),"\n",(0,o.jsx)(a.p,{children:"Verificar si un elemento esta habilitado. Si el elemento no esta actualmente habilitado, el test esperara un breve retraso para darle tiempo a habilitarse."}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean isEnabled = sam.asksFor(Enabled.of("#some-button"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"presence",children:"Presence"}),"\n",(0,o.jsx)(a.p,{children:"Verificar si un elemento esta presente en el DOM. Un elemento invisible u oculto todavia puede estar presente en el DOM."}),"\n",(0,o.jsx)(a.h3,{id:"selectedstatus",children:"SelectedStatus"}),"\n",(0,o.jsxs)(a.p,{children:["Alternativa a ",(0,o.jsx)(a.code,{children:"CheckboxValue"})]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'boolean termsAndConditionsApproved = sam.asksFor(SelectedStatus.of("#tnc"));\n'})}),"\n",(0,o.jsx)(a.h1,{id:"text",children:"Text"}),"\n",(0,o.jsxs)(a.p,{children:["Para obtener el valor de texto de un elemento, podemos usar la clase ",(0,o.jsx)(a.code,{children:"Text"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'String introductionText = sam.asksFor(Text.of("#introduction"));\n'})}),"\n",(0,o.jsx)(a.h3,{id:"textcontent",children:"TextContent"}),"\n",(0,o.jsxs)(a.p,{children:["En algunos casos, podemos necesitar leer la propiedad HTML ",(0,o.jsx)(a.code,{children:"textContent"})," para obtener el texto que necesitamos. Para hacer esto, podemos usar la clase ",(0,o.jsx)(a.code,{children:"TextContent"})," en lugar de ",(0,o.jsx)(a.code,{children:"Text"}),". Esto devuelve el contenido de texto del elemento especificado, y todos sus descendientes."]}),"\n",(0,o.jsx)(a.h3,{id:"thecoordinates",children:"TheCoordinates"}),"\n",(0,o.jsx)(a.p,{children:"Devolver las coordenadas de un elemento especificado."}),"\n",(0,o.jsx)(a.h3,{id:"thelocation",children:"TheLocation"}),"\n",(0,o.jsx)(a.p,{children:"Devolver donde en la pagina esta la esquina superior izquierda del elemento renderizado."}),"\n",(0,o.jsx)(a.h3,{id:"thesize",children:"TheSize"}),"\n",(0,o.jsx)(a.p,{children:"Cual es el ancho y alto del elemento renderizado?"}),"\n",(0,o.jsx)(a.h3,{id:"value",children:"Value"}),"\n",(0,o.jsxs)(a.p,{children:["Devolver el atributo HTML ",(0,o.jsx)(a.code,{children:"value"})," de un elemento especificado."]}),"\n",(0,o.jsx)(a.h3,{id:"visibility",children:"Visibility"}),"\n",(0,o.jsx)(a.p,{children:"Determinar si este elemento web esta presente y visible en la pantalla"}),"\n",(0,o.jsx)(a.h3,{id:"trabajando-con-dropdown",children:"Trabajando con Dropdown"}),"\n",(0,o.jsxs)(a.p,{children:["Podemos consultar el valor o valores seleccionados actualmente de un elemento HTML ",(0,o.jsx)(a.code,{children:"<SELECT>"})," usando las clases Question ",(0,o.jsx)(a.code,{children:"SelectedValue"}),", ",(0,o.jsx)(a.code,{children:"SelectedValues"}),", ",(0,o.jsx)(a.code,{children:"SelectedVisibleTextValue"})," y ",(0,o.jsx)(a.code,{children:"SelectedVisibleTextValue"}),"."]}),"\n",(0,o.jsx)(a.p,{children:"Por ejemplo, para encontrar el valor seleccionado actual de una lista desplegable HTML, podriamos usar el siguiente codigo:"}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'String selectedColorValue = dina.asksFor(SelectedValue.of("#color-dropdown"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Para obtener el texto visible del elemento seleccionado, usariamos ",(0,o.jsx)(a.code,{children:"SelectedVisibleTextValue"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'String selectedColor = dina.asksFor(SelectedVisibleTextValue.of("#color-dropdown"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Para multi-selects, podemos usar ",(0,o.jsx)(a.code,{children:"SelectedValues"})," y ",(0,o.jsx)(a.code,{children:"SelectedVisibleTextValues"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'List<String> selectedColors = dina.asksFor(SelectedValues.of("#color-dropdown"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Podemos recuperar la lista actual de opciones usando ",(0,o.jsx)(a.code,{children:"SelectOptions"}),", que devuelve la lista de textos visibles para cada opcion:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'List<String> selectedColors = dina.asksFor(SelectOptions.of("#color-dropdown"));\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Si necesitamos el atributo ",(0,o.jsx)(a.code,{children:"value"}
1)," de cada opcion del dropdown, podemos usar ",(0,o.jsx)(a.code,{children:"SelectOptionValues"}),", por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'List<String> selectedColors = dina.asksFor(SelectOptionValues.of("#color-dropdown"));\n'})}),"\n",(0,o.jsx)(a.h2,{id:"manejando-esperas",children:"Manejando Esperas"}),"\n",(0,o.jsx)(a.h3,{id:"usando-la-clase-waituntil",children:"Usando la clase WaitUntil"}),"\n",(0,o.jsxs)(a.p,{children:["Si necesitas esperar a que un elemento aparezca con Serenity Screenplay, hay algunas opciones disponibles. Por defecto, Serenity esperara un breve retraso si intentas interactuar con un elemento que no esta en la pagina. Sin embargo, puedes asegurarte de que esta espera sea suficiente usando la clase ",(0,o.jsx)(a.code,{children:"WaitUntil"}),", como se muestra aqui:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'private final static Target DELAYED_BUTTON = PageElement.locatedBy("#delayed-button");\n\ndina.attemptsTo(\n WaitUntil.the(DELAYED_BUTTON, WebElementStateMatchers.isVisible()),\n Click.on(DELAYED_BUTTON)\n);\n'})}),"\n",(0,o.jsxs)(a.p,{children:["Este codigo esperara hasta que el elemento sea visible antes de proceder a la accion Click. El tiempo de espera puede configurarse (en milisegundos) usando la propiedad ",(0,o.jsx)(a.code,{children:"webdriver.timeouts.implicitlywait"}),", que es 5 segundos por defecto."]}),"\n",(0,o.jsxs)(a.p,{children:["Si necesitas tener un control mas fino sobre la duracion del tiempo de espera para situaciones especificas, puedes especificarlo agregando el metodo ",(0,o.jsx)(a.code,{children:"forNoMoreThan()"}),", que te permite especificar un tiempo de espera explicito:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"dina.attemptsTo(\n WaitUntil.the(DELAYED_BUTTON, isVisible()).forNoMoreThan(10).seconds()\n);\n"})}),"\n",(0,o.jsxs)(a.p,{children:["Tambien puedes esperar otras condiciones. Por ejemplo, para esperar hasta que un elemento desaparezca, puedes usar el matcher ",(0,o.jsx)(a.code,{children:"isNotVisible()"}),":"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:"dina.attemptsTo(\n WaitUntil.the(DISAPPEARING_BUTTON, isNotVisible())\n);\n"})}),"\n",(0,o.jsxs)(a.p,{children:["Los siguientes matcher estan disponibles en la clase ",(0,o.jsx)(a.code,{children:"WebElementStateMatchers"}),". Ten en cuenta que todos los siguientes metodos tambien tienen un equivalente negativo (",(0,o.jsx)(a.code,{children:"isNotVisible()"}),", ",(0,o.jsx)(a.code,{children:"isNotEmpty()"})," etc.)."]}),"\n",(0,o.jsxs)(a.table,{children:[(0,o.jsx)(a.thead,{children:(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.th,{children:"Matcher"}),(0,o.jsx)(a.th,{children:"Proposito"})]})}),(0,o.jsxs)(a.tbody,{children:[(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"containsText(...)"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento contiene un valor de texto especifico"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"containsOnlyText(...)"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento contiene exactamente un valor de texto especifico"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"containsSelectOption(...)"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento dropdown contiene un valor de texto especifico como opcion"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"isClickable"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento es visible y esta habilitado"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"isEmpty"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento no es visible o contiene una cadena vacia"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"isEnabled"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento esta habilitado"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"isPresent"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento esta presente en la pagina"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"isSelected"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento esta seleccionado"})]}),(0,o.jsxs)(a.tr,{children:[(0,o.jsx)(a.td,{children:"isVisible"}),(0,o.jsx)(a.td,{children:"Verificar que un elemento es visible"})]})]})]}),"\n",(0,o.jsx)(a.h3,{id:"esperando-una-condicion-de-webdriver",children:"Esperando una condicion de WebDriver"}),"\n",(0,o.jsxs)(a.p,{children:["Otra opcion es esperar una condicion de WebDriver (que puede encontrarse en la clase ",(0,o.jsx)(a.code,{children:"org.openqa.selenium.supp
1ort.ui.ExpectedConditions"}),"), por ejemplo:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'dina.attemptsTo(\n WaitUntil.the(\n invisibilityOfElementLocated(By.id("disappearing-button")))\n);\n'})}),"\n",(0,o.jsx)(a.h3,{id:"esperando-con-target",children:"Esperando con Target"}),"\n",(0,o.jsxs)(a.p,{children:["Tambien puedes colocar una condicion de espera especifica en un objeto ",(0,o.jsx)(a.code,{children:"Target"}),". Puedes hacer esto ya sea cuando defines la variable ",(0,o.jsx)(a.code,{children:"Target"})," (si debe aplicarse cada vez que interactuas con este elemento), o solo cuando interactuas con el elemento, como se muestra a continuacion:"]}),"\n",(0,o.jsx)(a.pre,{children:(0,o.jsx)(a.code,{className:"language-java",children:'private final static Target INVISIBLE_BUTTON\n = PageElement.locatedBy("#invisible-button");\n\ndina.attemptsTo(\n Click.on(INVISIBLE_BUTTON.waitingForNoMoreThan(Duration.ofSeconds(3)))\n);\n'})})]})}function u(e={}){const{wrapper:a}={...(0,l.R)(),...e.components};return a?(0,o.jsx)(a,{...e,children:(0,o.jsx)(t,{...e})}):t(e)}},8453(e,a,n){n.d(a,{R:()=>i,x:()=>r});var s=n(6540);const o={},l=s.createContext(o);function i(e){const a=s.useContext(l);return s.useMemo(function(){return"function"==typeof e?e(a):{...a,...e}},[a,e])}function r(e){let a;return a=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),s.createElement(l.Provider,{value:a},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.