• No results found

Integration with existing Frameworks

In document }w!"#$%&'()+,-./012345<ya (Page 52-58)

4.3 Implementing the Component Model

4.3.2 Integration with existing Frameworks

It is always a good practice to not to reinvent a wheel by implementing the whole functionality from the beginning. When creating a new project, utilize already implemented functionality from other frameworks. What frameworks, and how the created component model utilizes them, is described in this section.

WebDriver

WebDriver automation tool is already mentioned in the section 3.2. In the created abstract model, it will be the main automation tool, in other words, it will be used to make interactions with the browser.

Currently, Arquillian Graphene is used to obtain an instance of WebDriver, which is subsequently injected into the test object.

To instruct WebDriver what web page element we want to com- municate with, it uses already seen mechanism of WebElement. For example line 4 at Listing 4.3 declares such a WebElement by specifying the XPath of the particular element which is in that example string //input[@type=’submit’].

XPath is a way of navigation in an XML document, and the structure of all web pages is also connected with their Document Object Model (DOM) which is a tree model of all web page elements, constructed in an XML syntax. This particular string locates a submit button. There are also other ways of locating web elements, such as CSS selectors.

WebDriver root mechanism What is particularly utilized, is the

way of locating nested elements of the particular web element. Listing 4.8 shows demonstration of the nested elements.

A HTML code of two components can be seen, particularly RichFaces calendars. Note that the HTML structure of that two components is the same, only values of attribute id are unique.

The value of id is, however, generated randomly, and differentiates from one rendering to another. That is the reason why can not rely only on locating according to id value, but there has to be employed locating according to other characteristics, for example CSS class, or the position in the DOM tree.

termines the particular component unambiguously is its root element (lines 1 and 12).

We can reference from this root other component’s parts. It is possible because of WebDriver root mechanism which is shown in Figure 4.6. It shows two approaches of locating WebElement, firstly when locating from WebDriver object elements with class nice, two elements are found (blue marked). When locating the first Root 2 element, and from it elements which have class nice, only one element is found (red marked).

Figure 4.6: WebDriver way of locating elements.

When taking into consideration the listings 4.8 again, referencing an img element with class rf-cal-btn from its root element <span id="j_idt6:calendar1"> (line 1), the image (line 5) from the first calendar will be selected, not the second one (line 16), even though it has the same class.

This is used in component model to access different parts of the components. For example the above mentioned image is a trigger which has to be clicked on in order to show a calendar in a pop-up panel.

Hence each component needs to have set root, before any action can be taken with it. Each component’s interface therefore needs to extend defined Component interface, which contains method setRoot, and therefore forces a user to implement that method.

1 <span i d=" j _ i d t 6 : c a l e n d a r 1 ">

2 <span i d=" j _ i d t 6 : j _ i d t 9 P o p u p " s t y l e=" white−s p a c e :

nowrap ; ">

3 <i n p u t c l a s s=" r f −c a l −i n p " i d=" j _ i d t 6 : j _ i d t 9 I n p u t D a t e "

name=" j _ i d t 6 : j _ i d t 9 I n p u t D a t e "

4 r e a d o n l y=" r e a d o n l y " s t y l e=" v e r t i c a l −a l i g n : m i d d l e ; "

t y p e=" t e x t " /> 5 <img a l t=" " c l a s s=" r f −c a l −btn " i d=" j _ i d t 6 : j _ i d t 9 P o p u p B u t t o n " 6 s r c=" path / toImage / c a l e n d a r I c o n . png " 7 s t y l e=" v e r t i c a l −a l i g n : m i d d l e " /> 8 . 9 . 10 . 11 . 12<span i d=" j _ i d t 6 : c a l e n d a r 2 ">

13 <span i d=" j _ i d t 6 : j _ i d t 1 0 P o p u p " s t y l e=" white−s p a c e :

nowrap ; ">

14 <i n p u t c l a s s=" r f −c a l −i n p " i d=" j _ i d t 6 : j _ i d t 1 0 I n p u t D a t e "

name=" j _ i d t 6 : j _ i d t 1 0 I n p u t D a t e "

15 r e a d o n l y=" r e a d o n l y " s t y l e=" v e r t i c a l −a l i g n : m i d d l e ; "

t y p e=" t e x t " /> 16 <img a l t=" " c l a s s=" r f −c a l −btn " i d=" j _ i d t 6 : j _ i d t 1 0 P o p u p B u t t o n " 17 s r c=" path / toImage / c a l e n d a r I c o n . png " 18 s t y l e=" v e r t i c a l −a l i g n : m i d d l e " /> 19 . 20 . 21 . 22 .

Listing 4.8: Web page fragment demonstrating two components - calendars - at one page.

Arquillian Drone

After the creating a prototype for the first selected component, calendar (its implementation in Listing 4.9), the usage of this component in the

test looked like Listing 4.10.

The Calendar component from listing has two fields, one annotated with Root annotation, which represented the field for later setting of the actual root, and the second annotated with annotation FindBy with

value according to which the element was inferred from component’s root. To use the component in the test, the tester had to initialise the component first with created Factory class, and secondly set the actual root, when the page was loaded, because only then the actual root can be located.

Initialisation of components The problem was to initialize com-

ponent properly. The components fields annotated with annotation FindBy needed to recognize the actual root by which they were inferred. This made an obligation to at first locate the actual root and to in- ject WebDriver and the root to the Factory class, which can properly initialise particular annotated fields with use of Java Reflection.

We wanted to avoid this obligation. It was resolved with use of Java Dynamic Proxies (see section 4.3.1). So when initialising the component, instead of injecting the real instances of WebElements, Dynamic Proxies objects are inserted, which invocation handlers forward all method invocations to the real WebDriver object.

More comprehensive will be probably the study of the Factory class, and its methods. Appendix B shows the fragments of the Factory class, the most important method, initializeComponent. This method is generic (see section 4.3.1), and can initialise any class which extends AbstractComponent class, it is a constraint to avoid initialising classes which are not components.

With the use of method instantiateComponent, whose internal implementation is using Java Reflection (see section 4.3.1), the given component is instantiated, in other words a new object is created from the given class.

In next the steps, all declared fields and subsequently all annotations of given field are retrieved with the use of Java Reflection, and iterated over to initialise root element and other fields with Java Dynamic Proxy objects. The initialisation of root element begins on line 17, we are creating new Proxy, and assigning to it invocation handler class. This method invoke will be called every time when any method will be called on the root element. In that method we retrieve the actual root, which should have already been set to the rootReference by the time that the method is invoked.

annotation17, with the difference that it finds the actual WebElement from the root.

1 public c l a s s C a l e n d a r I m p l { 2

3 @Root

4 private WebElement r o o t ; 5

6 @FindBy ( c s s = " img : nth−o f −t y p e ( 1 ) ") 7 private WebElement showCalendarButton ; 8

9 public void showCalendar ( ) { 10 showCalendarButton . c l i c k ( ) ;

11 }

12 }

Listing 4.9: First Calendar component prototype of the implementation.

1 public c l a s s TestPageWithCalendar { 2 3 private C a l e n d a r I m p l c a l e n d a r ; 4 5 @ B e f o r e C l a s s 6 public void i n i t C a l e n d a r ( ) { 7 c a l e n d a r = F a c t o r y . i n i t i a l i z e C o m p o n e n t ( C a l e n d a r I m p l .c l a s s) ; 8 } 9 10 @BeforeMethod 11 public void l o a d T e s t P a g e ( ) { 12 13 webDriver 14 . g e t (" h t t p : / / l o c a l h o s t : 8 0 8 0 / myTestApp/ c a l e n d a r . j s f ") ; 15 16 c a l e n d a r R o o t = webDriver 17 . f i n d E l e m e n t ( By . xpath (" // td [ @ c l a s s =’ e c o l 1 ’ ] ") ) ; 18 c a l e n d a r . s e t R o o t ( c a l e n d a r R o o t ) ; 19 }

17. Note that it is standard annotation of WebDriver, so it will be good recognized by community.

20 21 @Test 22 public void t e s t C a l e n d a r S e r v i c e ( ) { 23 c a l e n d a r . showCalendar ( ) ; 24 } 25 26 }

Listing 4.10: Usage of first calendar implementation.

The next problem was that demonstrated using of calendar compo- nent is clumsy, because the initialisation and the setting of the root will be repeated for every component, it is worth to automate it, to enhance created framework usability.

Therefore we decided to utilize again FindBy annotation, so that the calendar component will be annotated by FindBy annotation, which will provide information about the position of the root element on the tested page.

We needed to discover a mechanism which will perform this auto- matic discovery of FindBy annotations.

Drone SPI Arquillian provides a way to manage this by providing

SPI (see section 4.3.1) for enriching the test, which is a way to inject various dependencies into the test object during runtime.

I just needed to provide an implementation for that SPI. Appendix C.1 shows some important fragments of this implementation. With the use of reflection it initialises at first fields annotated with FindBy annotation, it can be either components, then also the root is set to that component, or it can be other elements which we need to interact with. Secondly, the fields with Page annotation are initialised, it is support for Page Objects pattern (see section 4.2.1), so you can use various pages in the test. These pages can contain other components, and the page object and its parts are properly initialised by Drone extension.

Arquillian Drone was also used in functional tests for the created component model.

In document }w!"#$%&'()+,-./012345<ya (Page 52-58)

Related documents