¿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:
-
PageFactory
yFindsByAttribute
estánsealed
, por lo que no puedo forzarlo simplemente heredando esos. - La instanciación manual de un
SelectElement
de unIWebElement
en cada método es bastante complicada y duplicativa. También ignora la espera aparente incorporada enPageFactory
y arrojaNoSuchElementException
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. - Envolver cada propiedad
IWebElement
con una propiedadSelectElement
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.