From e9c57a51d55aa8207b69189ca56dc8eb173be224 Mon Sep 17 00:00:00 2001 From: Artem Eroshenko Date: Wed, 23 Jan 2013 13:14:05 +0400 Subject: [PATCH] #8: nested classes (not static) are supported now --- .../loader/HtmlElementLoader.java | 30 ++++----- .../loader/decorator/HtmlElementFactory.java | 28 ++++---- .../htmlelements/utils/ReflectionUtils.java | 26 ++++++++ .../qatools/htmlelements/NestedClassTest.java | 65 +++++++++++++++++++ 4 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/utils/ReflectionUtils.java create mode 100644 htmlelements-java/src/test/java/ru/yandex/qatools/htmlelements/NestedClassTest.java diff --git a/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/HtmlElementLoader.java b/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/HtmlElementLoader.java index 6cacd0e5..9eb667a1 100644 --- a/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/HtmlElementLoader.java +++ b/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/HtmlElementLoader.java @@ -32,11 +32,11 @@ public class HtmlElementLoader { * @see #createPageObject(Class, org.openqa.selenium.WebDriver) */ public static T create(Class clazz, WebDriver driver) { - return create(clazz, new HtmlElementLocatorFactory(driver)); - } + return create(clazz, new HtmlElementLocatorFactory(driver)); + } - @SuppressWarnings("unchecked") - public static T create(Class clazz, CustomElementLocatorFactory locatorFactory) { + @SuppressWarnings("unchecked") + public static T create(Class clazz, CustomElementLocatorFactory locatorFactory) { if (isHtmlElement(clazz)) { Class htmlElementClass = (Class) clazz; return (T) createHtmlElement(htmlElementClass, locatorFactory); @@ -44,7 +44,7 @@ public static T create(Class clazz, CustomElementLocatorFactory locatorFa // Otherwise consider class as a page object class return createPageObject(clazz, locatorFactory); } - } + } /** * Initializes {@code instance} as a block of elements it is instance of {@link HtmlElement} @@ -90,13 +90,13 @@ public static void populate(T instance, WebDriver driver) { * @return Initialized instance of the specified class. */ public static T createHtmlElement(Class clazz, WebDriver driver) { - return createHtmlElement(clazz, new HtmlElementLocatorFactory(driver)); + return createHtmlElement(clazz, new HtmlElementLocatorFactory(driver)); } public static T createHtmlElement(Class clazz, CustomElementLocatorFactory locatorFactory) { T htmlElementInstance = HtmlElementFactory.createHtmlElementInstance(clazz); populateHtmlElement(htmlElementInstance, locatorFactory); - return htmlElementInstance; + return htmlElementInstance; } /** @@ -123,12 +123,12 @@ public static T createHtmlElement(Class clazz, Custom public static T createPageObject(Class clazz, WebDriver driver) { return createPageObject(clazz, new HtmlElementLocatorFactory(driver)); } - + public static T createPageObject(Class clazz, CustomElementLocatorFactory locatorFactory) { - T page = HtmlElementFactory.createPageObjectInstance(clazz, locatorFactory); + T page = HtmlElementFactory.createPageObjectInstance(clazz); populatePageObject(page, locatorFactory); return page; - } + } /** * Initializes fields of the given block of elements with lazy proxies. @@ -153,9 +153,9 @@ public static T createPageObject(Class clazz, CustomElementLocatorFactory * @param driver The {@code WebDriver} instance that will be used to look up the elements. */ public static void populateHtmlElement(HtmlElement htmlElement, WebDriver driver) { - populateHtmlElement(htmlElement, new HtmlElementLocatorFactory(driver)); + populateHtmlElement(htmlElement, new HtmlElementLocatorFactory(driver)); } - + public static void populateHtmlElement(HtmlElement htmlElement, CustomElementLocatorFactory locatorFactory) { @SuppressWarnings("unchecked") Class htmlElementClass = (Class) htmlElement.getClass(); @@ -168,7 +168,7 @@ public static void populateHtmlElement(HtmlElement htmlElement, CustomElementLoc String elementName = getElementName(htmlElementClass); htmlElement.setName(elementName); // Initialize elements of the block - PageFactory.initElements(new HtmlElementDecorator(elementToWrap), htmlElement); + PageFactory.initElements(new HtmlElementDecorator(elementToWrap), htmlElement); } /** @@ -194,8 +194,8 @@ public static void populateHtmlElement(HtmlElement htmlElement, CustomElementLoc public static void populatePageObject(Object page, WebDriver driver) { populatePageObject(page, new HtmlElementLocatorFactory(driver)); } - + public static void populatePageObject(Object page, CustomElementLocatorFactory locatorFactory) { - PageFactory.initElements(new HtmlElementDecorator(locatorFactory), page); + PageFactory.initElements(new HtmlElementDecorator(locatorFactory), page); } } diff --git a/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/decorator/HtmlElementFactory.java b/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/decorator/HtmlElementFactory.java index 73e216f2..b7636bc9 100644 --- a/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/decorator/HtmlElementFactory.java +++ b/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/loader/decorator/HtmlElementFactory.java @@ -1,16 +1,12 @@ package ru.yandex.qatools.htmlelements.loader.decorator; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Proxy; +import java.lang.reflect.*; import java.util.List; import org.openqa.selenium.WebElement; import org.openqa.selenium.internal.Locatable; import org.openqa.selenium.internal.WrapsElement; import org.openqa.selenium.support.pagefactory.ElementLocator; -import org.openqa.selenium.support.pagefactory.ElementLocatorFactory; import org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler; import ru.yandex.qatools.htmlelements.element.HtmlElement; @@ -21,6 +17,8 @@ import ru.yandex.qatools.htmlelements.loader.decorator.proxyhandlers.WebElementListNamedProxyHandler; import ru.yandex.qatools.htmlelements.loader.decorator.proxyhandlers.WebElementNamedProxyHandler; +import static ru.yandex.qatools.htmlelements.utils.ReflectionUtils.newInstance; + /** * Contains factory methods for creating instances of blocks, typified elements, page objects * and for creating lazy proxies. @@ -32,19 +30,22 @@ public class HtmlElementFactory { public static T createHtmlElementInstance(Class elementClass) { try { - return elementClass.newInstance(); + return newInstance(elementClass); + } catch (NoSuchMethodException e) { + throw new HtmlElementsException(e); } catch (InstantiationException e) { throw new HtmlElementsException(e); } catch (IllegalAccessException e) { throw new HtmlElementsException(e); + } catch (InvocationTargetException e) { + throw new HtmlElementsException(e); } } public static T createTypifiedElementInstance(Class elementClass, WebElement elementToWrap) { try { - Constructor constructor = elementClass.getConstructor(WebElement.class); - return constructor.newInstance(elementToWrap); + return newInstance(elementClass, elementToWrap); } catch (NoSuchMethodException e) { throw new HtmlElementsException(e); } catch (InstantiationException e) { @@ -56,14 +57,11 @@ public static T createTypifiedElementInstance(Class< } } - public static T createPageObjectInstance(Class pageObjectClass, ElementLocatorFactory locatorFactory) { + public static T createPageObjectInstance(Class pageObjectClass) { try { - try { - Constructor constructor = pageObjectClass.getConstructor(ElementLocatorFactory.class); - return constructor.newInstance(locatorFactory); - } catch (NoSuchMethodException e) { - return pageObjectClass.newInstance(); - } + return newInstance(pageObjectClass); + } catch (NoSuchMethodException e) { + throw new HtmlElementsException(e); } catch (InstantiationException e) { throw new HtmlElementsException(e); } catch (IllegalAccessException e) { diff --git a/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/utils/ReflectionUtils.java b/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/utils/ReflectionUtils.java new file mode 100644 index 00000000..d5da31a8 --- /dev/null +++ b/htmlelements-java/src/main/java/ru/yandex/qatools/htmlelements/utils/ReflectionUtils.java @@ -0,0 +1,26 @@ +package ru.yandex.qatools.htmlelements.utils; + +import com.google.common.collect.Lists; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import static org.apache.commons.lang3.reflect.ConstructorUtils.invokeConstructor; + +/** + * User: eroshenkoam + * Date: 1/22/13, 5:53 PM + */ +public class ReflectionUtils { + + public static T newInstance(Class clazz, Object... args) throws IllegalAccessException, + InstantiationException, NoSuchMethodException, InvocationTargetException { + if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) { + Class outerClass = clazz.getDeclaringClass(); + Object outerObject = outerClass.newInstance(); + return invokeConstructor(clazz, Lists.asList(outerObject, args).toArray()); + } else { + return invokeConstructor(clazz, args); + } + } +} diff --git a/htmlelements-java/src/test/java/ru/yandex/qatools/htmlelements/NestedClassTest.java b/htmlelements-java/src/test/java/ru/yandex/qatools/htmlelements/NestedClassTest.java new file mode 100644 index 00000000..7e34220e --- /dev/null +++ b/htmlelements-java/src/test/java/ru/yandex/qatools/htmlelements/NestedClassTest.java @@ -0,0 +1,65 @@ +package ru.yandex.qatools.htmlelements; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import ru.yandex.qatools.htmlelements.annotations.Block; +import ru.yandex.qatools.htmlelements.element.HtmlElement; +import ru.yandex.qatools.htmlelements.element.Link; +import ru.yandex.qatools.htmlelements.element.TypifiedElement; +import ru.yandex.qatools.htmlelements.loader.HtmlElementLoader; + +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * User: eroshenkoam + * Date: 1/22/13, 2:16 PM + */ +public class NestedClassTest { + + public WebDriver driver = mock(WebDriver.class); + WebElement arrow = mock(WebElement.class); + WebElement link = mock(WebElement.class); + + @Before + public void before() { + when(driver.findElement(By.className("arrow"))).thenReturn(arrow); + when(arrow.findElement(By.className("link"))).thenReturn(link); + } + + @Test + @Ignore + public void test() { + NestedPageObject pageObject = HtmlElementLoader.create(NestedPageObject.class, driver); + assertThat(pageObject, notNullValue()); + assertThat(pageObject.arrow.getName(), notNullValue()); + assertThat(pageObject.arrow.link.getWrappedElement(), notNullValue()); + } + + public class NestedPageObject { + @FindBy(className = "arrow") + public NestedHtmlElement arrow; + } + + public class NestedHtmlElement extends HtmlElement { + @FindBy(className = "link") + public NestedTypifiedElement link; + + } + + + public class NestedTypifiedElement extends TypifiedElement { + + public NestedTypifiedElement(WebElement wrappedElement) { + super(wrappedElement); + } + + } +}