c# selenium drop-down-menu selenium-webdriver pageobjects

¿Cómo inicializar SelectElements al usar PageFactory/FindsBy en Selenium C#?



drop-down-menu selenium-webdriver (1)

Primero, no hay una "espera integrada" en la implementación de .NET PageFactory . Puede especificar fácilmente uno en la llamada a InitElements (más sobre eso en un momento). En este momento, la mejor opción para usted sería su opción 3, aunque no expondría al miembro de IWebElement ; Lo haría private , ya que PageFactory puede enumerar a miembros privados con la misma facilidad que los públicos. Entonces su objeto de página se vería así:

[FindsBy(How = How.Id, Using = "MonthDropdown")] private IWebElement dropDown; public SelectElement MonthDropdownElement { get { return new SelectElement(dropdown); } }

¿Cómo se obtiene el IWebElement real cuando lo necesita? Como SelectElement implementa IWrappedElement , puede simplemente llamar a la propiedad WrappedElement si necesita acceder a los métodos y propiedades del elemento proporcionado por la interfaz IWebElement .

Las versiones recientes de los enlaces .NET han reestructurado el PageFactory para que sea más extensible. Para agregar la "espera integrada" que desee, puede hacer lo siguiente:

// Assumes you have a page object of type MyPage. // Note the default timeout for RetryingElementLocator is // 5 seconds, if unspecified. // The generic version of this code looks like this: // MyPage page = PageFactory.InitElements<MyPage>(new RetryingElementLocator(driver), TimeSpan.FromSeconds(10)); MyPage page = new MyPage(); PageFactory.InitElements(page, new RetryingElementLocator(driver, TimeSpan.FromSeconds(10)));

Además, si realmente necesita personalizar cómo funcionan las cosas, siempre puede implementar IPageObjectMemberDecorator , que le permite personalizar completamente cómo se enumeran los atributos y los valores establecidos en las propiedades o campos decorados con esos atributos. Una de las sobrecargas (no genéricas) de PageFactory.InitElements toma una instancia de un objeto que implementa IPageObjectMemberDecorator .

Dejaré de lado que las implementaciones adecuadas del Patrón de Objetos de Página como estrictamente definido no deben exponer ningún objeto WebDriver fuera de cada objeto de página. De lo contrario, todo lo que está implementando es un "envoltorio de página", que es un enfoque perfectamente válido, simplemente no lo que uno llamaría un "objeto de página".

Estoy construyendo un Modelo de Objetos de Página en Selenium WebDriver para C #, usando PageFactory.

Desafortunadamente, descubrí que FindsByAttribute no inicializará un SelectElement (HTML <select> etiqueta / menú desplegable). Me he encontrado con algunas ideas para solucionarlo hasta el momento, pero ninguna de ellas es ideal:

  1. PageFactory y FindsByAttribute están sealed , por lo que no puedo forzarlo simplemente heredando esos.
  2. La instanciación manual de un SelectElement de un IWebElement en cada método es bastante complicada y duplicativa. También ignora la espera aparente incorporada en PageFactory y arroja NoSuchElementException a menos que agregue una espera cada vez que hago esto, lo que requeriría repetir el localizador por todas partes, derrotando (parte de) el propósito del POM.
  3. Envolver cada propiedad IWebElement con una propiedad SelectElement es menos desordenado, pero aún tiene el mismo problema de espera que el anterior.

La mejor opción hasta ahora es # 3, y escribir un contenedor para SelectElement que simplemente agrega una espera a cada método. Si bien esta solución funcionará , aumentará mucho el código de cada página, ya que en lugar de este código (hipotético) bonito:

[FindsBy(How = How.Id, Using = "MonthDropdown")] public SelectElement MonthDropdown;

Estoy atascado con un contenedor (algo que preferiría evitar), y:

[FindsBy(How = How.Id, Using = "MonthDropdown")] private IWebElement _monthDropdown; public Selector MonthDropdown { get { return new Selector(MonthDropdown, Wait); } }

Con Selector como el contenedor SelectElement , que también tiene que aceptar IWait<IWebDriver> para que pueda esperar y crear instancias de un nuevo Selector cada vez que IWait<IWebDriver> a él.

¿Hay una mejor manera de hacer esto?

EDITAR: poner adormecidos los modificadores de acceso incorrectos. Fijo. Gracias, @JimEvans.