Skip to content

Commit

Permalink
#8: nested classes (not static) are supported now
Browse files Browse the repository at this point in the history
  • Loading branch information
Artem Eroshenko committed Jan 23, 2013
1 parent 161e157 commit e9c57a5
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ public class HtmlElementLoader {
* @see #createPageObject(Class, org.openqa.selenium.WebDriver)
*/
public static <T> T create(Class<T> clazz, WebDriver driver) {
return create(clazz, new HtmlElementLocatorFactory(driver));
}
return create(clazz, new HtmlElementLocatorFactory(driver));
}

@SuppressWarnings("unchecked")
public static <T> T create(Class<T> clazz, CustomElementLocatorFactory locatorFactory) {
@SuppressWarnings("unchecked")
public static <T> T create(Class<T> clazz, CustomElementLocatorFactory locatorFactory) {
if (isHtmlElement(clazz)) {
Class<HtmlElement> htmlElementClass = (Class<HtmlElement>) clazz;
return (T) createHtmlElement(htmlElementClass, locatorFactory);
} else {
// 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}
Expand Down Expand Up @@ -90,13 +90,13 @@ public static <T> void populate(T instance, WebDriver driver) {
* @return Initialized instance of the specified class.
*/
public static <T extends HtmlElement> T createHtmlElement(Class<T> clazz, WebDriver driver) {
return createHtmlElement(clazz, new HtmlElementLocatorFactory(driver));
return createHtmlElement(clazz, new HtmlElementLocatorFactory(driver));
}

public static <T extends HtmlElement> T createHtmlElement(Class<T> clazz, CustomElementLocatorFactory locatorFactory) {
T htmlElementInstance = HtmlElementFactory.createHtmlElementInstance(clazz);
populateHtmlElement(htmlElementInstance, locatorFactory);
return htmlElementInstance;
return htmlElementInstance;
}

/**
Expand All @@ -123,12 +123,12 @@ public static <T extends HtmlElement> T createHtmlElement(Class<T> clazz, Custom
public static <T> T createPageObject(Class<T> clazz, WebDriver driver) {
return createPageObject(clazz, new HtmlElementLocatorFactory(driver));
}

public static <T> T createPageObject(Class<T> 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.
Expand All @@ -153,9 +153,9 @@ public static <T> T createPageObject(Class<T> 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<HtmlElement> htmlElementClass = (Class<HtmlElement>) htmlElement.getClass();
Expand All @@ -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);
}

/**
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.
Expand All @@ -32,19 +30,22 @@ public class HtmlElementFactory {

public static <T extends HtmlElement> T createHtmlElementInstance(Class<T> 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 extends TypifiedElement> T createTypifiedElementInstance(Class<T> elementClass,
WebElement elementToWrap) {
try {
Constructor<T> constructor = elementClass.getConstructor(WebElement.class);
return constructor.newInstance(elementToWrap);
return newInstance(elementClass, elementToWrap);
} catch (NoSuchMethodException e) {
throw new HtmlElementsException(e);
} catch (InstantiationException e) {
Expand All @@ -56,14 +57,11 @@ public static <T extends TypifiedElement> T createTypifiedElementInstance(Class<
}
}

public static <T> T createPageObjectInstance(Class<T> pageObjectClass, ElementLocatorFactory locatorFactory) {
public static <T> T createPageObjectInstance(Class<T> pageObjectClass) {
try {
try {
Constructor<T> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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> T newInstance(Class<T> 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}

}
}

0 comments on commit e9c57a5

Please sign in to comment.