Code Monkey home page Code Monkey logo

fluentlenium / fluentlenium Goto Github PK

View Code? Open in Web Editor NEW
864.0 53.0 211.0 19.12 MB

FluentLenium is a web & mobile automation framework which extends Selenium to write reliable and resilient UI functional tests. This framework is React ready. Written and maintained by people who are automating browser-based tests on a daily basis.

Home Page: https://fluentlenium.io

License: Other

Java 85.92% HTML 7.12% JavaScript 0.01% Gherkin 0.16% Groovy 1.52% Shell 0.02% Kotlin 5.24%
java selenium junit testng spock spring assertj fluentlenium html javascript

fluentlenium's Introduction

What is FluentLenium ?

FluentLenium CI pipeline Coveralls javadoc Maven Central Website

FluentLenium helps you writing readable, reusable, reliable and resilient UI functional tests for the browser and mobile app.

FluentLenium provides a Java fluent interface to Selenium, and brings some extra features to avoid common issues faced by Selenium users.

FluentLenium is shipped with adapters for JUnit4, JUnit5 , TestNG, Spock , Kotest , Spring TestNG and Cucumber, but it can also be used standalone.

FluentLenium best integrates with AssertJ, but you can also choose to use the assertion framework you want.

FluentLenium can be used to make your mobile Appium tests fluent and easier to maintain.

FluentLenium gives you multiple methods which help you write tests quicker. All those methods are tested daily by commercial regression test suites maintained by project developers.

Quickstart

Quickstart steps are described in deail in our separate documentation section.

Example

public class DuckDuckGoTest extends FluentTest {
    @Test
    public void titleOfDuckDuckGoShouldContainSearchQueryName() {
        goTo("https://duckduckgo.com");
        $("#search_form_input_homepage").fill().with("FluentLenium");
        $("#search_button_homepage").submit();
        assertThat(window().title()).contains("FluentLenium");
    }
}

More detailed FluentLenium examples are available in examples section. Examples include headless Chrome and Firefox, Spring-based framework supporting multiple browsers and much more.

Documentation

Detailed documentation is available on fluentlenium.io.

Javadoc

Javadoc is available on fluentlenium.io/javadoc.

Modules summary

To help you navigate through FluentLenium, here's a short summary about its modules and what support they provide.

  • fluentlenium-core: Contains core functionality of FluentLenium, including webdriver configuration, page object support and injection logic.
  • fluentlenium-junit: Provides support for integration with JUnit 4.
  • fluentlenium-junit-jupiter: Provides support for integration with JUnit 5.
  • fluentlenium-testng: Provides support for integration with TestNG.
  • fluentlenium-spock: Provides support for integration with Spock.
  • fluentlenium-spring-testng: Provides support for integration with Spring Test NG
  • fluentlenium-kotest: Provides support for integration with Kotest
  • fluentlenium-kotest-assertions: Provides custom Kotest matchers
  • fluentlenium-cucumber: Provides support for integration with Cucumber. This may be combined with any of the modules above that are also supported by Cucumber.
  • fluentlenium-assertj: Provides AssertJ assertions for FluentLenium specific objects like FluentWebElement, FluentList and FluentPage.
  • fluentlenium-integration-tests: Integration tests for validating the correctness of FluentLenium features internally.
  • fluentlenium-coverage-report: Creates jacoco test coverage report.
  • fluentlenium-ide-support: Though not an actual Maven module, it contains resources to make working with FluentLenium in the IDE easier.

Contact Us

If you have any comment, remark or issue, please open an issue on FluentLenium Issue Tracker

fluentlenium's People

Contributors

abendt avatar benmccann avatar brantb avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dgageot avatar filipcynarski avatar framiere avatar jarlehansen avatar jcsirot avatar jeanlaurent avatar jetoile avatar johanrydstrom avatar jroper avatar julien-lafont avatar koryl avatar kristo avatar mathildelemee avatar michaelbitard avatar nozomiito avatar nurkiewicz avatar pascalschumacher avatar pierreleresteux avatar romainlouvet avatar slawekradzyminski avatar tmurakam avatar toilal avatar twillouer avatar yannmoisan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fluentlenium's Issues

Selectors and filters for classes?

I don't see anywhere the documentation how to find an element with more than one class.

There doesn't seem to be a "withClass" selector to do the following:

browser.findFirst(".modal", withClass("in"));

Nor does the standard cascading CSS notation work:

browser.findFirst(".modal .in");

Finally, I don't know how to inspect an element which is found to retrieve all the classes.

In my case, I can add an id and do the following:

browser.find(".in", withId("myModal"));

But I find it really awkward and can't believe there isn't a way to get examine classes.

Guidance appreciated,
thanks!

takeScreenShot() causes ClassCastException

I wrote a simple Play example system to illustrate Fluentlenium for my students:

https://github.com/philipmjohnson/play-example-fluentlenium

When I included a call to takeSnapShot, I got the following exception:

java.lang.ClassCastException: org.openqa.selenium.htmlunit.HtmlUnitDriver cannot be cast to org.openqa.selenium.TakesScreenshot

The call to takeScreenShot is here:

https://github.com/philipmjohnson/play-example-fluentlenium/blob/master/test/IntegrationTest.java

Am I doing something wrong?

Thanks,
Philip

Group of page

In case of a statefull application, provide a way to create a path of page (Page 1 => Page 2 => Page 3) that can be used in others tests, in order to avoir to have Page 1 => Page 2 => Page 3 hard coded for each test after page 3.

Generic return type for FluentList

in the class fr.javafreelance.fluentlenium.core.Fluent

have the methods

public FluentList find(String name, final Filter... filters)
public FluentList $(String name, final Filter... filters)

return a generic FluentList<?>

without the generic a simple for loop does not work without casting

for (FluentWebElement vraag : (FluentList<?>) $("input")) 

Improve fest-assert assertions

hasClass
hasAttribute
containsAttribute(String attr).withValue(String value) (or other name)
hasId
hasText
isPresent

(see the wait API and copy).

go To Until Is At

Hi,

That would be nice to have a method like that :

public static void goToUntilIsAt(FluentPage page, long millis) {
  // 1) go to the target page
  // ... goto(page)

  // 2) wait until isAt()...
  // ...
}

I understood that the isAt() method verifies that the browser is at the page.

Here, i guest that the page#isAt() method should retour a boolean intead than a void...

goTo() method should retain page type passed as argument

Currently, the goTo() method is defined as:

public FluentPage goTo(FluentPage page) {
    if (page == null) {
        throw new IllegalArgumentException("Page is mandatory");
    }
    page.go();
    return page;
}

This interrupts the fluent API because the specific page type is being erased.

Hence, the following is not possible (without a cast):

LoginPage loginPage = goTo(createPage(LoginPage.class));

This can be fixed by carrying the argument type over to the return type:

public <P extends FluentPage> P goTo(P page) {
    if (page == null) {
        throw new IllegalArgumentException("Page is mandatory");
    }
    page.go();
    return page;
}

Now the sample code above will work.

Improve API asynchronous call

Equal (eq), Not Equal(ne), Less than (lt), Less than or equal(le), greater than (gt),greater than or equal(ge)
Example : await().atMost(5, TimeUnit.SECONDS).until(".small").hasSize().ne(3);

Simplify await

  • put a default timing (5 secondes) :
    await().until("xxx").isPresent() => wait for 5 seconds

Add isDisplayed() for await

Sometimes it is needed to wait for an element to be visible even if this element is already present but hidden in the DOM.

TestNg default firefox browser not closing

public class AppsLongTest extends FluentTestNg {

@Test
public void when_basic_test_then_browser_not_closing(){
   goTo("http://google.com");
   assertThat($(".product")).hasSize(12);
}

}

Getting java.lang.NoClassDefFoundError: org/apache/http/entity/ContentType

Followed the instruction to setup Maven. Was getting a java.lang.NoClassDefFoundError: org/apache/http/entity/ContentType that would not allow it to connect to the browser driver.

Had to explicitly add a dependency to httpcore to get it to work. Is this expected, or should these dependencies be rolled in automatically by fluentLenium?

Firefox versions beyond 12 hangs with no errors

When I try to run fluentlenium against any version of Firefox beyond version 12, Fluent Lenium just hangs indefinitely. I don't get any output nor any debug messages. Fluent Lenium fails to open a browser and then nothing else happens, the jvm just hangs.

Documentation : provide page's method returning another page

The documentation is not clear on how I should return a page object after the call to a page method.
For example, my a.html page redirects to b.html after I click on the button "next".

It seems it's not possible to use @page directly in a page variable as in a test. So should I use PageFactory.initElements ?

fill Select is not fluent yet?

We may miss something but to fill a select we use :

Select selectDayType = new Select(findFirst("#dayType").getElement());
selectDayType.selectByValue(dayTypeValue);

Would you be interesting in a fluent version (if it doesn't exist yet) ?

fillSelect("#dayType").withValue(dayTypeValue);

We have a PR if it is something interesting.

Provide a waitForHTTP method

The behavior in FluentLenium for .click() methods on elements which submit a form while clicking (like in RichFaces a:commandButton or other) which leads to a page changement is not always the same.
Sometimes my test passes OK (when I debug the code step by step), sometimes, the code don't wait the HTTP page changement to run on, and my next asserts fail because it should be on a next page.

It could be could to have a waitForHTTP method like in Graphene.
A usage is showed here

FluentWaitBuilder#hasAttribute uses hardcoded attribute name

The attribute parameter in hasAttribute(final String attribute, final String value) is ignored. Instead, always the String constant attribute is used.

hasAttribute("my-name", "my value") works fine when using <elem attribute="my value"> in the HTML, but fails when using the expected <elem my-name="my value">.

The current code:

public void hasAttribute(final String attribute, final String value) {
    Predicate isPresent = new com.google.common.base.Predicate<WebDriver>() {
        public boolean apply(@Nullable WebDriver webDriver) {
            if (filter.size() > 0) {
                return search.find(selector, (Filter[]) filter.toArray(new Filter[filter.size()])).getAttributes("attribute").contains(value);
            } else {
                return search.find(selector).getAttributes("attribute").contains(value);
            }
        }
    };
    wait.until(isPresent);
}

I assume this should read attribute rather than "attribute":

if (filter.size() > 0) {
    return search.find(selector, (Filter[]) filter.toArray(new Filter[filter.size()])).getAttributes(attribute).contains(value);
} else {
    return search.find(selector).getAttributes(attribute).contains(value);
}

As a workaround, one can simply use with(...).equalTo(...):

await().atMost(10, TimeUnit.SECONDS).until("elem")
    .with("my-name").equalTo("my value").isPresent();

FluentWebElements in super classes of page objects are not initialized

If I have a hierarchy of Page objects like the one defined below, FluentWebElement fields in super classes (GenericPage$search in this case) are not initialized during tests.

public abstract class GenericPage extends FluentPage {
    // Search box appearing on all pages in the site
    public FluentWebElement search; 
    public void searchFor(String text) {
        fill(search).with(text);
        submit(search);
    }
}
public class HomePage extends GenericPage {
}

public class SearchTests extends FluentTest {
    @Page HomePage homePage;
    @Test public void canSearchFromHomePage() {
        // Fails because homePage.search is null.
        homePage.searchFor("foo");
    }
}

Creating a page from another page isn't as easy as it should, and page injection is broken

This is a followup to the issue #55.

Suppose we have a master page (list) and a detail page. It seems desirable to be able to do something like

public DetailPage clickDetail(String detailName) {
    ...
}

in the master page, and to do

public MasterPage clickBackToMaster() {
    ...
}

in the detail page.

However, implementing that is not as simple as it should, for the following reasons:

  • the createPage() method is in FluentAdapter, which FluentPage doesn't extend. So we have to create a page using the following code

    return new FluentAdapter(getDriver()).createPage(clazz);
    

it would be helpful to have the createPage() in Fluent directly, instead of having it in FluentAdapter

  • The suggested solution of the issue #55 doesn't work, because it causes a StackOverflowError: the master page needs a detail page to be injected, and the detail page needs a master page to be injected. So either circular dependencies between pages should be forbidden (which would not be natural at all, given that web pages naturally constitute a cyclic graph), or the injection should be fixed in order to create only one instance of every page and inject the same page instance in every test or page needing it.

Allow @Page type to change during navigation

Given a page object ListPage (extends FluentPage) for list.html and a page object DetailPage (extends FluentPage) for detail.html.
When I test these 2 html pages, I still want 2 page objects. So on a.html when I click on 'view detail' button I want to use the DetailPage page object.

To do so I copy the private fields 'search' and 'driver' to my page using reflexion. It would be nice to have this built in FluentLenium.

public class EvolvedFluentPage extends FluentPage {

    public <T extends FluentPage> T toPage(Class<T> classOfPage) throws Exception {
        T newPage = (new FluentAdapter()).createPage(classOfPage);

        copyPrivateField("search", newPage);
        copyPrivateField("driver", newPage);

        return newPage;
    }

    private <T extends FluentPage> void copyPrivateField(String fieldName, T otherPage) throws NoSuchFieldException, IllegalAccessException {
        Field f = Fluent.class.getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(otherPage, f.get(this));
    }

}

An even better way to call this behaviour might be to have a click(DetailPage.class) that returns the new page but seems harder to implement.

I hope my explanation is clear enought.

Search#select() should report cssSelector if WebDriver throws exception resolving it

Currently, when a CSS selector that has a syntax error is encountered, WebDriver does not give any indication as to which CSS selector is invalid. It only says:

org.openqa.selenium.WebDriverException: An invalid or illegal string was specified

FluentLenium should rethrow the WebDriverException with additional information about the CSS selector (until this is fixed in WebDriver).

Unfortunately, there's no way to know that problem is with the selector, but we do know that the request was to find an element, so reporting the selector is reasonable.

Here's an example that reproduces this issue:

fill("username]").with("user1");

Impossible d'effectuer un assertEquals de texte.

Bonjour,

J'ai rencontré un problème assez obscur à propos de tests sur des textes.

Scénario 1 : Je devais tester le texte "Paiement sécurisé" de la balise 'b'. Lors de la récupération de cette chaîne, elle était correcte pour un affichage dans un SySout() mais devenait vide lors de tests avec AssertEquals() et AssertThat().isEqualsTo.

J'ai été obligé de récupérer dans une String ma donnée pour ensuite la tester dans un 'if' avec mes constantes en faisant un "AssertThat(true)" dans le cas où c'était correct.

J'utilise toujours les AssertsEquals() prévus pour mes autres tests. Il n'y a que pour ces quelques cinq cas du même bloc "

Bing Vs Google

Bonjour,

Je crée un test en m'inspirant des exemples.

J'ai ma page Bing

public class BingPage extends FluentPage {
    public String getUrl() {
        return "http://www.bing.com";
    }

    public void isAt() {
        assertThat(title()).isEqualTo("bing");
    }

    public void search(String keywords) {
        fill("#sb_form_q").with(keywords);
        submit("#sb_form_go");

    }
}

Et mon test.

public class BingTest extends FluentTest {
    @Page
    private BingPage bingPage;

    @Test
    public void testRecherche() {
        // Arrange
        String keyword = "wikipedia";

        // Act
        goTo(bingPage);
        bingPage.search(keyword);

        try {
            for (int i = 0; i < 10; i++) {
                System.out.println(title());
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Assert
        assertThat(title()).containsIgnoringCase(keyword);
    }
}

J'ai mis un sleep pour bien voir ce qui se passe, car tout à l'air bon dans la fenêtre de Firefox qui s'ouvre :

Bing
Bing
Bing
Bing
Bing
Bing
Bing
Bing
Bing
Bing

Je peux faire varier la durée du sleep, ça ne change rien. Pourtant la page est déjà chargée comme il faut, avec les bons résultats.

Je fais le même test avec Google.

public class GooglePage extends FluentPage {

    public String getUrl() {
        return "http://www.google.fr";
    }

    public void isAt() {
        assertThat(title()).isEqualTo("Google");
    }

    public void search(String keywords) {
        // Remplir le champ de recherche
        fill("#gbqfq").with(keywords);
        // Clic sur le bouton
        submit("#gbqfba");

    }

}

Pour Google, j'utilise un sleep de 100ms seulement et j'ai :
Google
Google
Google
Google
Google
Google
Google
Google
Google
wikipedia - Recherche Google
wikipedia - Recherche Google

Donc ça marche avec Google, mais pas avec Bing ?...

Fix page injector

The suggested solution of the issue #55 doesn't work, because it causes a StackOverflowError: the master page needs a detail page to be injected, and the detail page needs a master page to be injected. So either circular dependencies between pages should be forbidden (which would not be natural at all, given that web pages naturally constitute a cyclic graph), or the injection should be fixed in order to create only one instance of every page and inject the same page instance in every test or page needing it.

Scénario avec une page de login

Bonjour,

Que conseillez-vous dans le cadre de l'écriture d'un scénario, faisant franchir plusieurs pages ?

Voici un exemple :

  1. Goto home ;
  2. Clic sur menu "Fibonacci" (pour arriver sur une page de calcul de cette suite)
  3. Saisir une valeur et submit. Puis vérif que la réponse est ok.

Je pensais naturellement avoir HomePage et FibonacciPage, mais comment les enchaîner ? Quelles sont vos recommandations ?

Si en plus l'application est protégée, on peut imaginer que l'étape (1) va d'abord passer par un login, ou non selon qu'on est déjà connecté ou pas.

Provide examples for options

Hi,

given the following html

<select id="form:isEnabled" name="form:isEnabled" size="1">
    <option value="">Any</option>
    <option value="true">Yes</option>
    <option value="false">No</option>
</select>
<select id="form:homeAddress" name="form:homeAddress" size="1"> 
    <option value="-1">-- Select One</option>
    <option value="1">Avenue des champs Elysées/Paris</option>
    <option value="2" selected>Park avenue/New-York</option>
    <option value="3">Tochomae/Tokyo</option>
    <option value="4">California Street/San Francisco</option>
</select>

Would you mind providing the following examples:

  • click on "form:isEnabled" using the "Yes" text
  • click on "form:isEnabled" using the "false" value
  • verify that in "form:homeAddress" the text "Park avenue/New-York" is selected
  • verify that in "form:homeAddress" the value "2" is selected

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.