4 Replies Latest reply on Sep 3, 2013 2:30 AM by jhuska

    Graphene: proposal of API change of FindBy to achieve extensibility


      We currently use @FindBy annotation as a replacement for WebDriver's own @FindBy annotation.


      Those annotation allows to specify what location strategy to use, supporting variety of strategies from element identifiers, CSS selectors, XPath to some other bizzare ways.



      The purpose of own @FindBy annotation was to extend this set of location strategies by support for jQuery.




      The FindBy allows to specify element location in following ways:


      @FindBy(id = 'xyz')

      @FindBy(css = '.class')

      @FindBy(jquery = '.class:visible')




      @FindBy(how = CSS, using = '.class')




      However neither from those styles allows for extensibility.


      We can't introduce new properties to @FindBy(my_strategy=...) nor we can extend How with MY_STRATEGY because it's enum.




      The number of use cases where extending the location strategy would be useful are plethora, but most prominent is particular need of some web frameworks:





      Location by JSF IDs


      the server_id is a short version of long clientId, which can differ by the environment in which the component is used


      Location by AngularJS Model names


      AngularJS comes with its own expression language where expressions can be used in HTML markup.

      We could use model names to find elements on the page which is a similar what End-to-End tests for AngularJS use.



      Question is simple: how to allow for extensibility of FindBy?

        • 1. Re: Graphene: proposal of API change from FindBy to FindByJQuery to achieve extensibility

          I have two proposals:


          1. re-define @FindBy(how = How) where how should be Class<? extends How> instead of enum.


          @FindBy(how = JQuery.class, using=".class:visible") for jQuery

          @FindBy(how = JSF.class, using="component-id") for JSF


          locating <h:commandButton id="component-id" />


          @FindBy(how = NG.class, using="modelProperty") for AngularJS


          locating <input ng-model="modelProperty" />


          Additionally, one could change the default location strategy for whole project, so that one could use just:




          when arquillian.xml will specify <property name="defaultLocationStrategy">org.jboss.arquillian.graphene.by.ByJSF</property>




          @FindBy(how = JSF.class, using = "due")

          private Calendar dueDate;


          @FindBy(how = JSF.class, using = "edit")

          private Button editButton;


          @FindBy(how = JSF.class, using = "delete")

          private Button deleteButton;





          2. allow to extend a syntax with own annotations:








          @ElementLocationStrategy(resolver = ByJSF.class)

          public @interfaces FindByJSF {

              String value();



          private Calendar dueDate;


          private Button edit;


          private Button delete;

          • 2. Re: Graphene: proposal of API change of FindBy to achieve extensibility

            Another aspect of this API which is in question is re-definition of WebDriver's @FindBy.


            I don't really like there is a duplicity on classpath, since it makes a life with IDEs harder:


            you get two FindBy implementations in type search, so you need to mind the package name.

            • 3. Re: Graphene: proposal of API change of FindBy to achieve extensibility



              I really hate having own @FindBy annotation. Therefore, I'd definitely prefer having a bunch of @FindByXYZ annotations with some "SPI" that allows user to register their own annotation - e.g. all @FindByXYZ annotations are marked with a meta annotation.


              Something like: https://github.com/aerogear/aerogear-unifiedpush-server/blob/master/src/main/java/org/jboss/aerogear/unifiedpush/annotations/PATCH.java



              • 4. Re: Graphene: proposal of API change of FindBy to achieve extensibility

                I am voting for the second option as well. It gives us less verbose syntax, without need (but with possibility) to setup something on the global level.