Skip to content

Commit

Permalink
Merge pull request #228 from FluentLenium/feature/element-as-component
Browse files Browse the repository at this point in the history
Add as(Component.class) method in FluentWebElement
  • Loading branch information
Toilal committed Mar 31, 2016
2 parents 1643d6a + 2426fae commit 9fb83e0
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 1 deletion.
31 changes: 30 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,6 @@ public class LoginPage extends FluentPage {
}
```


If you need to wait for an element to be present, especially when waiting for an ajax call to complete, you can use the @AjaxElement annotation on the fields:

```java
Expand All @@ -547,6 +546,36 @@ public class LoginPage extends FluentPage {
You can set the timeout in seconds for the page to throw an error if not found with `@AjaxElement(timeountOnSeconds=3)` if you want to wait 3 seconds.
By default, the timeout is set to one second.

## Extend FluentWebElement to model components

You can implement reusable components by extending FluentWebElement. Doing so will improve readability of both Page Objects and Tests.

```java
public class SelectComponent extends FluentWebElement {
public FluentWebElement(WebElement element) { // This constructor MUST exist !
super(element);
}

public void doSelect(String selection) {
// Implement selection provided by this component.
}

public String getSelection() {
// Return the selected value as text.
}
}
```

These kind of component can be created automatically by `FluentPage`,
or programmatically by calling `as` method of FluentWebElement or FluentList.

```java
SelectComponent comp = findFirst("#some-select").as(SelectComponent.class);

comp.doSelect("Value to select");
assertThat(comp.getSelection()).isEquals("Value to select");
```


## Wait for an Ajax Call

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import org.fluentlenium.core.action.FluentDefaultActions;
import org.fluentlenium.core.filter.Filter;
import org.fluentlenium.core.search.SearchActions;
import org.openqa.selenium.WebElement;

import java.lang.reflect.Constructor;
import java.util.List;

/**
Expand Down Expand Up @@ -188,6 +190,13 @@ public interface FluentList<E extends FluentWebElement> extends List<E>, FluentD
*/
FluentList<E> clearAll();

/**
* Wrap all elements in a component extending FluentWebElement.
*
* @return elements as components.
*/
public <T extends FluentWebElement> FluentList<T> as(Class<T> componentClass);

/**
* Clear all elements on the list
* Only the visible elements are filled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,5 +343,16 @@ public E findFirst(String name, Filter... filters) {
public E findFirst(Filter... filters) {
return find(0, filters);
}

@Override
public <T extends FluentWebElement> FluentList<T> as(Class<T> componentClass) {
List<T> elements = new ArrayList<>();

for (E e : this) {
elements.add(e.as(componentClass));
}

return new FluentListImpl<>(elements);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
* WebElementCustom include a Selenium WebElement. It provides a lot of shortcuts to make selenium more fluent
*/
Expand Down Expand Up @@ -47,6 +50,20 @@ public Axes axes() {
return this.axes;
}

/**
* Wrap this element in a component extending FluentWebElement.
*
* @return element as a component.
*/
public <T extends FluentWebElement> T as(Class<T> componentClass) {
try {
Constructor<T> constructor = componentClass.getConstructor(WebElement.class);
return constructor.newInstance(getElement());
} catch (Exception e) {
throw new IllegalArgumentException(componentClass.getName() + " is not a valid component class. It should have a single WebElement parameter constructor.", e);
}
}

/**
* Double Click on the element
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.fluentlenium.integration;

import org.fluentlenium.core.domain.FluentList;
import org.fluentlenium.core.domain.FluentWebElement;
import org.fluentlenium.integration.localtest.LocalFluentCase;
import org.junit.Test;
import org.openqa.selenium.WebElement;

import static org.assertj.core.api.Assertions.assertThat;

public class ElementAsTest extends LocalFluentCase {

public static class Component extends FluentWebElement {

public Component(WebElement webElement) {
super(webElement);
}

}

public static class NotAComponent extends FluentWebElement {
public NotAComponent(String invalidConstructorParam) {
super(null);
}
}

@Test
public void testAsComponent() {
goTo(DEFAULT_URL);
Component span = findFirst("span").as(Component.class);
assertThat(span).isNotNull();

FluentList<Component> spans = find("span").as(Component.class);
assertThat(spans).isNotEmpty();
}

@Test(expected = IllegalArgumentException.class)
public void testAsNotAComponent() {
goTo(DEFAULT_URL);
findFirst("span").as(NotAComponent.class);
}

}

0 comments on commit 9fb83e0

Please sign in to comment.