Showing posts with label PRACTICUM. Show all posts
Showing posts with label PRACTICUM. Show all posts

Friday, March 22, 2013

PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Advanced User Interactions


This is the next installment (in progress) of my PRACTICUM series. This particular grouping is going through David Burns' "Selenium 2 Testing Tools Beginner's Guide".

Note: PRACTICUM is a continuing series in what I refer to as a somewhat "Live Blog" format. Sections may vary in time to complete. Some may go fast. Some may take much more time to get through. Updates should be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom of the post, you will know that this entry is finished :).


Update: This project was put down back in April, with the intention to get back to it after I figured out why the examples weren't working. I didn't intend for the process to take 3 MONTHS to get back to, but I believe in finishing what I start, whenever I can. Therefore, all of the previous examples from earlier posts have been updated and re-examined. thanks for the patience and here's hoping you all continue the journey with me once again :).



Chapter 9: Advanced User Interactions


Much of what we have worked with thus far would be plenty if the web of yore were the one we were working with. Ahh yes, those days when things were simple. Three tiered architecture, some simple front end details, links, buttons, and a few CGI scripts. Just find the elements, click the buttons or links, and move to the next item. So simple... and so 1994!

The web doesn't really look like that any longer. Well, many places actually still do, but the places we most like to visit certainly don't. Today's Twitter and Facebook level web apps are a lot more dynamic. It's not just typing text and clicking buttons. Now we can move stuff, resize things, pull and stretch and add components whenever we feel like it, and who knows what will happen next.

For these types of environments, this next chapter focuses on how the user can leverage more advanced options in the API to have this level of interaction. These interactions require a more in depth coverage of not just keyboard combinations, but actual placement and movement of the mouse, and how to track it and implement the appropriate actions.

Creating an Action Chain

One of the things that we are ab;e to do with Selenium is create sequences of events that we can bind together. These sequences are referred to as "action chains" and they allow us to  make a variety of movements and treat them as one action. Below is the example code that David presents to show us how to drag and drop an element:


If we run the text, we should see two things happen. The first is we should see a screen like the first one below:



and then see a second screen that looks like this:



I say "should because, well, that's not what I'm seeing. Instead, my browser looks like this:

And my output for the test looks like this:



Now, if I have learned anything from these past several weeks, it's not to jump to conclusions that something isn't working. It's very possible that what may be the culprit is the version of Java JDK I'm using. My plan is to dig in and see if there's some thing I'm unaware of. For the Java pro's out there, if I'm doing something dumb, please, let me know so that I can fix it :).

Moving an Element by an Offset Value

So, the building option to allow us to move elements also allows us to move items by specific amounts (or so the book says). With this is n mind, I tried to create the example as described, using JUnit 4.1.1 format. Instead of dragging and dropping abox from one element to another, this time, it calls for moving by an index amount on the X-Y axes.



Seems straightforward enough, but I am still seeing the same issues with this example as with the last one.



Again, Java peoples out there, it is just me, or is there something not happening here that should be happening? An enquiring mind wants to know.

More to come. Stay tuned!

Michael Larsen, TESTHEAD

Friday, February 22, 2013

PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Selenium Grid


This is the next installment (completed) of my PRACTICUM series. This particular grouping is going through David Burns' "Selenium 2 Testing Tools Beginner's Guide".

Note: PRACTICUM is a continuing series in what I refer to as a somewhat "Live Blog" format. Sections may vary in time to complete. Some may go fast. Some may take much more time to get through. Updates will be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom of the post, you will know that this entry is finished :).


[Note for 2/19/2013: Compiler errors... no, that will not stand, man! I will get to the bottom of this... and I think I finally have. For those who are using Java 7 as your JDK, look towards the bottom, I discovered something that resolved our past compile problems, or at least, I think I have :). --MKL].

Chapter 8: Selenium Grid

One of the nice things I have noticed thus far with regards to the Selenium tests that I have seen is that they are relatively easy to change so that the tests can be run on multiple devices. The down side is that, so far, we have had to run them all one at a time, or switch things over to different servers, different bridges, and check them out one at a time. Also, tests are launched serially and run in order in the approaches we have taken so far. That's all cool, but is there some way that we could simplify things and just have one place we could focus our attention? The answer is "well, almost!"

Selenium Grid lets us set up a number of Selenium instances, with one central "hub" to send commands to. Selenium Grid routes the commands destined for a particular device or driver based on the configuration options and identification elements we create. While it's not an "all in one" solution, it's a nice way to go about gathering a lot of tests under one roof and varying the ability to test lots of different devices. First, though, we need to set up our environment to allow for a grid server.

Starting up Selenium Grid


Thankfully, this is an easy first step. We start up Selenium Server like we usually do, but we add a flag to it, like this:

java -jar selenium-server-standalone-2.29.0.jar -role hub

This will start up selenium server in grid mode (note, of course, use the version of selenium-server-standalone[x.xx.x].jar that you have, if you have a newer version, it should work the same).



And here's what your browser will say if you point to the server.



Cool, we've successfully started Selenium Grid. All looks good here. This is going to be the center point of our tests, and other Selenium instances will be reached from here. When we start Selenium Grid, we can see what options we have control over and which ones we can change. By passing in the port number (i.e. –port ####) We can use any value that we want (and have access to, of course).

By typing in

http://nameofmachine:4444/grid/console

we can see what environments are accessible (or at least assessible as far as the grid hub is concerned).

Unlike the Selenium Grid 1.0 version, 2.0 allows a machine to host multiple servers and allow access to multiple browser drivers.

Setting up Selenium Grid with a Local Server Node

This time, we'll look at starting up Selenium Grid, as well as starting up a second Selenium server.

Enter the following command in the apropriate location (note, the previous selenium grid command needs to be running for this to work. That's not directly mentioned in the book):

Start with

java -jar selenium-server-standalone-2.29.0.jar -role hub

and then run

java -jar selenium-server-standalone..jar -role node -hub http://localhost:4444/grid/register

You should see the following in your command prompt or console:



And if all goes well, this is our Selenium Grid display:




Nice! Looks good :)!

Setting up Selenium Grid With Remote Server Nodes

While having the grid running locally is cool, to really leverage the benefits of Selenium grid, what we really want to be able to do is run Selenium Server on multiple machines, and have those machine register their connections with the main Selenium Grid hub. The more machines we have that can do this (and the different variety of machines we use for this purpose), the more we can leverage the benefits of cross-platform and parallel testing. For this purpose, here's my setup with a second Darwin device and my Windows machine:

Each of the machines needs to be registered, and each needs to point to the primary grid hub, like this:

1. Make sure the hub system is running on my main Darwin system:

 java -jar selenium-server-standalone-2.29.0.jar -role hub

2. Set up a secondary local Darwin Selenium server instance and have it pointing to the hub:

java -jar selenium-server-standalone-2.29.0.jar -role node -hub http://localhost:4444/grid/register



3. Set up the second Darwin machine to run a Selenium server and register it with the first Darwin machine's hub:

java -jar selenium-server-standalone..jar -role node -hub http://74.51.157.191:4444/grid/register



4. Set up the Windows machine to run a Selenium server and register it with the first Darwin machine's hub:

java -jar selenium-server-standalone..jar -role node -hub http://74.51.157.191:4444/grid/register



Cool, so if we did that all correctly, we should have a grid with three registry entries... do we?


Indeed we do. Right on! So the key here is that we have the hub instance running, and with that, we can set up as many remote environments as we have machines. For our purposes, though, I think this will be sufficient to make the point.


Setting up Selenium Grid to dedicate OS/Browser Specific Tests

If we only needed to run on one browser and one operating system, this would be a much easier situation to deal with. In that case, much of Selenium Grid would be to merely provide for parallel tests and pointing to different instances of Selenium Server, all utilizing the same browser driver. While that's probably OK in some instances, most of us have to deal with situations that require a variety of browsers. More to the point, we don't have to just consider issues of browsers (Chrome, Firefox, Opera) in their own rights, we also have to consider the challenges of running them in a variety of Operating Systems (Windows, Mac, Linux, etc.) Even with Internet Explorer being solely on Windows, there are now multiple versions and multiple OS considerations (XP, Vista, 7, 8). Safari runs on Mac, and we haven't even started talking about Mobile yet! Selenium Grid, in a manner of speaking, gives us "One Ring (Hub?) to Rule Them All!" Well, OK, perhaps not all, but there are nine options that we can leverage at this point.

We've already seen that we can set up a base hub for the Grid, and use the -hub flag to point remote instances to it. We can use the -role flag to associate remote instances of Selenium server with our Grid hub. To get the browser level into the mix, we use a flag called -browser . The following command lets up set up a Selenium Server that registers with Internet Explorer specific options:

java \
-jar selenium-server-standalone.jar \
-role node \
-hub http://localhost:4444/grid/register \
-browser browserName="internet explorer",maxInstances=1,platform=WINDOWS


If this is doing what it's supposed to do, then we will have a Grid entry that only references Windows. That's what the book shows. My reality is a different story:


Not sure if that's going to make a big difference, but suffice it to say, we're running with the parameters the book told us to run. In our later tests, we'll see if they run correctly.

Using Selenium Grid 2 with YAML

YAML is a way that we can take commonly used data and encapsulate it into a file, so that the details we might want to update, or run with several instances, can be sourced from one place. Here's the suggested example for our YAML file (called grid_configuration.yml):


There are two different configuration options that are available. If you have Selenium 1 Gris servers (i.e. Selenium RC) and you want to run them along with the more up to date Selenium2/WebDriver servers, you can. Define the details you want to configure in the YAML file, and when you start up the Grid hub, give it the flag -grid1yml and the name of the YAML file, and you're good to go. 
 



A  quick look at the config options shows us our grid1yml file configuration options (note that we haven't created a grid 2 configuration file yet):


The key takeaway here is that a lot of the parameters that we would want to keep track of can be housed in a couple of YAML files, and that makes configuration changes quite a bit easier to track.

Actually Running Tests in the Grid

Up to this point, I have to say that my update speed has been very slow with this chapter. That's been a combination of work conspiring against me, plus some unusual issues with getting files to compile that made me decided that I had to get to the bottom of it. Through that process, i discovered that Java 7 requires a little more verbosity than Java 6 did. I could be wrong about this, but on the bright side, I think I may have found an answer to the issues of not being able to compile in previous sections.

First, let's talk running tests that leverage the grid. This is a simple example, simply because I decided I didn't want to fight multiple machines, multiple drivers, and multiple error messages just yet (hey, I'm having such fun with it, why shouldn't I let you all do the same ;) ?). But, to show that we are actually "gridding" it, here's a simple test that I put together to make sure that it goes to a particular location. In the example below, I have three servers. One's running on Windows, one's running on Linux and one is running on Mac. I want to make sure the test in question goes to the Mac instance. 


Right, so what's interesting about the above code? Glad you asked. As I was setting this example up, I kept getting the compile error "SetPlatform requires Platform, but found String".

This is so similar to all of the design pattern errors I was getting, I decided that there had to be a reason I'm seeing this. Additionally, I've gotten to the point that I couldn't believe that so many code examples were just not workable. I have met David, and I know he's way more conscientious about this stuff than to allow so many "mistakes". Well, what if it's not a mistake? What if Java 7 requires stricter type usage? As soon as I thought about that, and remembered back in my old C days that I could "force" a type casting to be applied, I started experimenting. In the process I came up with the following approach and change (note the difference between the two files):


Once we forced the type requirement, the project compiled! Not only that, but it actually ran the test to the specific server we wanted to have run it. Look below, the grid console shows the test instance being run. It's the muted firefox icon, and yes, that server is indeed the one running on my Mac:


Oh, and note... I finally got my Windows Server to declare itself an Internet Explorer only node, so yes, it's doable. I don't know what I did differently other than have the Windows version run the latest version of Selenium Server... hmmm, that might be it.

Summary:

Yeah, this section took a long time to get through, but on the plus side, I made a neat discovery, and that discovery may go a long way to solving a few other problems. Net result is that I'm going to go back and do some re-testing and re-coding of the previous examples and bring them in line with Java 7 realities. Seriously, I am ecstatic that there is a potential solution to all of the random compile errors, and if it's this simple, then there will be some easy changes to suggest to Packt so that they can perhaps make an update in the errata to reference Java 7 type conversion (or lack thereof :) ).


End of Section.

Wednesday, February 20, 2013

PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Mobile Devices


This is the next installment (in progress) of my PRACTICUM series. This particular grouping is going through David Burns' "Selenium 2 Testing Tools Beginner's Guide".

Note: PRACTICUM is a continuing series in what I refer to as a somewhat "Live Blog" format. Sections may vary in time to complete. Some may go fast. Some may take much more time to get through. Updates will be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom of the post, you will know that this entry is finished :).

Chapter 7: Mobile Devices

As David rightly points out, Mobile is the current "killer app" for our times. Some might even say it's the "killer paradigm" in the sense it is adding a whole new slew of approaches and considerations to testing. This section will look at how to get into and use three mobile platforms; Android, MobileOpera and iOS.

Note: The tests in question will be using emulators for this chapter. Real app testing, however, should be performed on real devices (the emulator will only tell part of the story).

Creating an Android Emulator

The following example requires three things. First, you need an Android emulator, and to do that, you can download the Android SDK from:

http://developer.android.com/sdk/index.html#download

I called my dowloaded directory android-sdk to be consistent with the book

Next, open a shell window and cd to android-sdk/sdk/tools. Type the following:


./android create avd -n my_android -t 1

‰ "–n my_android" gives the emulator the name "my_android".

‰ –t 1 tells it which version of android to use. "1" gives us Android 4.2.


Note, the book says to enter "14", this will not work with the current distribution.


$ ./android create avd -n my_android -t 14
Error: Target id is not valid. Use 'android list targets' to get the target ids.

$ ./android list targets
Available Android targets:
----------
id: 1 or "android-17"
Name: Android 4.2
Type: Platform
API level: 17
Revision: 1
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WSVGA, WVGA800 (default), WVGA854, WXGA720, WXGA800, WXGA800-7in
ABIs : armeabi-v7a

Entering "1" will get the default version, which is Android 4.2.


STadmins-MacBook-Pro-2:tools michaellarsen$ ./android create avd -n my_android -t 1
Auto-selecting single ABI armeabi-v7a
Android 4.2 is a basic Android platform.


When prompted "Do you wish to create a custom hardware profile [no]", hit the return button (ie. accept the "no" option).

Do you wish to create a custom hardware profile [no]
Created AVD 'my_android' based on Android 4.2, ARM (armeabi-v7a) processor,
with the following hardware config:
hw.lcd.density=240
vm.heapSize=48
hw.ramSize=512

Run the emulator with:


./emulator -avd my_android & 


If all goes well, you will see something that looks like this (note, it'll take some time to load, be patient):



Installing the Selenium WebDriver Android Server on the Emulator

Next, we need to load the android-server[ver].apk onto the Android emulator. Downloaded the APK file from http://code.google.com/p/selenium/downloads/list.

Start the emulator.

Go to android_sdk/sdk/platform-tools and run "./adb devices")


$ ./adb devices
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
List of devices attached
emulator-5554 device


Note: My serial number is "emulator-5554" your serial number will probably be different from mine.

Install the server:


$ ./adb -s emulator-5554 -e install -r /Users/michaellarsen/selenium/android-server-2.21.0.apk
2602 KB/s (1881490 bytes in 0.705s)
pkg: /data/local/tmp/android-server-2.21.0.apk
Success

On the device you will see this (I put it on the main screen for effect, you'll see it listed in the apps section, though: 



Creating a Test for Android

Those examples we used in the last chapter should work with a minor change. In this case, that change will be to use AndroidDriver. There are some steps to do before that can happen:



Start the WebDriver server on the device. After experimenting with some errors, I restarted the emulator, and then ran the server process from the command line in the android-sdk/sdk/platform-tools directory as follows:


$ ./adb -s emulator-5554 shell am start -a android.intent.action.MAIN -n org.openqa.selenium.android.app/.MainActivity
Starting: Intent { act=android.intent.action.MAIN cmp=org.openqa.selenium.android.app/.MainActivity }



Next, forward HTTP traffic to the emulator.


adb -s emulator-5554 forward tcp:8080 tcp:8080 

With that, let's try a test we're already familiar with...


All we did was add an import statement and change the webdriver to point to AndroidDriver. Let's click Compile (success!) and let's click run test...



Success!!! Cool, we just ran a test on an Android. Well, Android Emulator, but good enough for a first step. 


Working With OperaMobile

As I've come to discover over the past few years, While Opera has a dedicated fan base, they are not really a big player overall in the browser and Mobile world. Still, even though they are a small niche player here stateside, they have put a lot of time and emphasis into their tools, and really, their tools are quite nice. What's more, they have made a really strong push and commitment to making their products very responsive to Selenium, so that alone makes them deserving of a look.

Setting up OperaMobile is actually pretty easy. They have an application package that can be installed on Darwin, so if you are using a Mac like I am, setup is a breeze. Just go to http://www.opera.com/developer/tools/mobile/, get the OperaMobileEmulator.dmg file, double click, put the OperaMobile application into the Applications folder, and that's it. The default location for the application is /Applications/Opera Mobile Emulator.app/Contents/MacOS/Opera Mobile Emulator .


Once you have set up OperaMobile, you can open it up and take a look at the rather large number of emulation modes it supports:



Here's an example page with Amazon Kindle Fire HD 8.9 selected as a destination device.


Making a test is much the same as previous examples, in that we are defining in the setup stage what driver will actually open. In this case, driver will open OperaMobile, with some parameters that David has provided, including a path to the executable (which, in this instance actually compiles :) ).


From there, we can compile (success), and run our test (not successful):



So this will take some playing with, I guess. The OperaMobile profile chooser launches, and if we select something, we get a browser. We have to do that select choice, though, and I suspect that may be part of the problem. Also, we get the OperaMobile browser to appear, but the get command is not posted, and the test times out. Again, something seems to be missing from these steps. The question is what?

Next steps will be to try to figure out what's happening with OperaDriver, but I may just forge ahead and start looking at iOS and the iPhone/iTouch/iPad framework.

Working with iOS
So I have to say at this point I'm a bit disappointed. No, it has noting to do with David or his explanations. It has more to do with Apple and their need to provision my emulator, and charging me $99.00 for the privilege. In short, that annoys me and frankly, I'm not willing to do that at this immediate point in time. I may well address this later on, but for my purposes right now, I'm willing to bypass this for the time being.

Still, I read through the details, and found out much of the information is very similar for what to do to set up and start driving Android and OperaMobile. Put simply, you fork Selenium from git, you build selenium to run in the simulator or on an iOS device, and then you set up your environment (for a fee) to be provisioned to run applications. From there, create a test like we have for the rest of the examples, with the following changes.  

1. Add an import statement that points to:

import org.openqa.selenium.iphone.IphoneDriver; 


2. In the @Before setUp() block, put the following line:

driver = new IPhoneDriver();

With all things being equal, that's pretty much all you have to do to make a test that will run on iPhone.

So there you have it. Much of the details are setting up the environments and geting the code needed to run inside of the environments so that they can be controlled by WebDriver. The cool thing to see is the fact that so little "code" needs to be written at the test level to make these changes. Creating and maintaining tests to be run on multiple different browsers and environments, it's really nice to see that there is very little that one has to do to make changes.

End of Section.

Thursday, February 14, 2013

PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Working With WebDriver



This is the next installment (in progress) of my PRACTICUM series. This particular grouping is going through David Burns' "Selenium 2 Testing Tools Beginner's Guide".

Note: PRACTICUM is a continuing series in what I refer to as a somewhat "Live Blog" format. Sections may vary in time to complete. Some may go fast. Some may take much more time to get through. Updates will be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom of the post, you will know that this entry is finished :).



Chapter 6: Working With WebDriver

The whole point of running Selenium is so that we can interact with and work with different browsers and tet to make sure that interactions behave as they should, items appear where they should, and that our applications work in the environments that we want them to. Selenium WebDriver is designed to work with the major browsers currently on the market, so this chapter will show us how to interact with Chrome, Firefox, Internet Explorer and Opera. Each browser requires an executable be installed on the system, as well as the browser in question (the Firefox driver is already bundled with the Java client; it's what we've been using thus far in the examples):


Using Firefox Driver

So far, this is the approach we have been using up to this point. The example below shows a standard JUnit test:


This example shows the bare basics of a test with no modifications.


Firefox Profile Preferences

In many cases, there are functions in the browser that a user may or may not want to have configured while they run their tests. To take advantage of this, a variety of profiles can be created, and the particular profile instance can be loaded and used. To do this, we:


  • instantiate a Firefox Profile object and then update the settings.
  • pass this object into FirefoxDriver where we instantiate it. 
  • load the profile with your details you have set. 


Imagine that you wanted to have the book site be the startup page for Firefox. Below shows us how we can do that:



Another example that David shows us is that we can locate the firefox binary explicitly. By entering the path to the binary, we could load the version of firefox we want to use. The syntax would look like this, alas, I can't get the system to compile if I use this option:



We can also point to a plug in using the following syntax:



Alas, this too fails for us, and for the same reason. In fact, many of the items in this chapter have the same "fatal flaw". I think they look like great ideas, but why oh why can't I compile them?!

Working with ChromeDriver


The whole point to WebDriver is to allow us to use multiple browsers, not just Firefox.

The next example shows us how we can load the ChromeDriver, and thus connect with Chrome. For this purpose, I took a copy of ChromeDriver and put it in /usr/bin so I could always rely on its position. With that, we compiled and ran, and lo and behold, here we are:




There's a fair amount of red down at the bottom, but don't be alarmed, that's the output from ChromeDriver. The thing to focus on is that ChromeDriver opens, and the test runs, and passes. Woot!!!


However, it looks like ChromeDriver and the extended examples suffers from the same issues as FirefoxDriver. Try as I might, this won't compile :( (this is the example to explicitly call out the file location. IT's complaining that it expects a string, not a file. Remove the File declaration, and it does the same thing. I'm at a loss. Java peoples, please tell me, it it me, or is something missing from this example?):
 

Working with OperaDriver

Opera, likewise, has a driver that lets WebDriver access and run it. Let's have a look!

To load Opera, we need to get the operadriver.jar file and for good measure, associated it with the project. Once we do that, it's all good to go. Granted, the test need some tweaking. Look for the spelling errors for the words "Chapter 4" (should be "Chapter4") and "index" (should be "Index"). Once you fix those, hey, you're golden:

Well, OK,; not completely golden. Those astute viewers will notice I did a little cheat here. I set the assert value to be zero. This means it will return a true even if the element isn't there. Why would I do such a thing? I wanted to show a completed test. Alas, the element I'm looking for stubbornly refuses to respond (it may be my system settings, I'll tweak with them some more later). Just to show you the full story, set the asset value to equal one, and here's what I get, at least as of right now:

Opera also has a profile that can be adjusted. The below example turns off geolocation, and then runs the same test as before:


As we can see the test passes (but I set the size to zero to get it to do that. Again, I need to poke around just a bit more).

Working with Internet Explorer

First off, I need to say how exciting it is to see this next step. One of my frustrations of two years ago was that Selenium RC was having major issues with running on 64 Bit Windows 7 at the time. Today, WebDriver does not have that issue, and the steps to get it up and running were actually fairly easy. For those who want to get up and running on Windows 7 64 bit, here's all it takes:

  • Download Intellij IDEA and install it
  • Install Java SDK
  • Download Selenium-Server-Standalone-x-xx.jar
  • Download JUnit.jar
  • Download IEDriverServer.exe
  • Link up the IDE to find the Java SDK folder, plus add selenium-server-standalone and JUnit jars as global libraries
  • Put the IEDriverServer in a place where the PATH variable can find it (or add it to your path).
Once you do that, create your Java class file, put in some simple commands, including calling the InternetExplorerDriver class, and let it run. If you do as above, this should be what you see (along with an IE browser running the commands):



OK, wow, that was pretty cool. That's four different browsers we can drive and little in the way of tweaking top get them to do their things. I must admit, I'm a bit frustrated about the File and Dictionary calls, as well as the compilation errors. I followed all of the steps as requested but alas, many of these examples were for naught. I really would like to understand why they are not doing what they are supposed to do, and if there's a way to make these work as printed. Again, is this because of me using Darwin and not Linux? Is it something special about Java 7? Do the examples rely on something that is now deprecated? Either way, we were able to set something running for all four browsers, and the fact I could get it to work on Windows has me somewhat elated.

End of Section.

Tuesday, February 12, 2013

PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Finding Elements



This is the next installment (in progress) of my PRACTICUM series. This particular grouping is going through David Burns' "Selenium 2 Testing Tools Beginner's Guide".

Note: PRACTICUM is a continuing series in what I refer to as a somewhat "Live Blog" format. Sections may vary in time to complete. Some may go fast. Some may take much more time to get through. Updates will be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom of the post, you will know that this entry is finished :).



Chapter 5: Finding Elements

Some may be looking at this entry and thinking "wait, didn't we do this already?" Yes, in a way, this was the point of chapter 2, but this time around we are going to focus on finding elements with the WebDriver API. As its name implies, WebDriver has a number of commands that can be used/called, and these all make up the "Driver" part of WebDriver, and those commands can help us access the elements we need for our tests.

Finding an element on the page by its ID

The nice thing about looking for an element by its ID is that, well, the statement to do that is pretty straightforward:

((FindsById)driver).findElementById("secondajaxbutton");

If we enter this in the test, here's what we see:

Each of the tests will use the following stub.



Note: you'll need to change "Webdriver" to "WebDriver" to get TestExample1.java to compile.

For good measure, so that we see we are starting from a known good origin... proof that the test ran and completed successfully :).


If it didn't find the element, then we'd see something like this:




WebDriver will throw an exception if there's no element by that name (NoSuchElementFoundException).

This next example creates a list of WebElements. The benefit to running this version is that, if it fails, it won't throw an exception. Instead, it will return a list that is size zero (specifically, it has nothing in it).







Finding an Element on the Page by its Name

When we look for an element by its name, the process is similar to what we just used to look for an ID. Also, just like the ID example, in this singular example, if an element is not found, an exception will be thrown.



Note: if you want to keep the examples as a handy little reference, you can set up another test method and stash them in there. If you do, though, modify your variables so that the instances created will be unique. Also, I love the fact that the IDE lets you collapse methods and classes so that, if you aren't making changes, you can just minimize them to one line, so we can focus on the current example. Hmmm, my resistance to this IDE might be crumbling a little ;).

Now, I know what you're thinking… hey, is there an elements example for Name like there is for ID? Yep, there is, and it works much the same way. Good thing, because while in reality there's likely only to be any one item with a particular ID, the chance of having lots of elements with the same name is very possible. The approach is likewise similar to the example for ID:



Similar to the elements example for id, this name examples list option will not throw an exception if the element is not found. It will also return a list that has a size of zero.



Finding an Element on the Page by Their ClassName

So far, these examples all follow a pattern, and that, frankly, is nice to see. Looking for an element by ClassName looks very similar to the previous two element types. If we have more than one element that has the same class name, this approach will return the first ClassName element that it gets. Additionally, this will throw an exception if we do not find the element.



The elements example works the same way.




In addition to ClassName, there's also an option to look for an item by CSS selector by using findElementByCssSelector or findElementByCssSelector



Note: if you ran this example as displayed, you would get an exception because storetext isn't a CSS selector.

Finding an Element on the Page by XPath

We can use XPath to help us find elements as well. XPath is a more expensive option, but it does work, especially if we are looking for multiple items. The following example shows both the single and list approaches to using findElementByXPath and findElementsByXPath:


Finding an Element on the Page by its Link Text

If you are looking for a link that has a particular text string in it, you're in luck. findElementByLinkText and findElementsByLinkText fills the bill. Also, it uses the same format as the other examples (I figure by now I don't need to overdo the point, right? Still, this time, Dave gives us a slightly different approach, as well as a different page to go to:





Finding Elements Using a More Generic Method

Each of the methods we have used up to this point are specific and defined to their scope. Plus side, their easy to spot and easy to implement. Down side, change your mind for how to access  an element, and you may have a bunch of updating to do. There's a more "generic" way to do this that doesn't call on the specific method, but instead calls it internal to the findElement() and findElement() methods. To do this, we enter the commands as follows:



The rules we've learned for the specific methods work in this way as well. single instance will throw an exception if its not found, the list option will not, but will return a list value of zero.



Finding if an Element Exists Without Throwing an Error

All of the examples we have seen up to this point have a similar reaction when the singular version of getElement() is called. If there's no element there, then it throws an exception. We have also seen that, if we don't want to deal with exceptions, we can also call getElements() and set it up to look at the list value and verify the value is 0. Depending on our goals, the list check may be the best option.

Waiting for Elements to Appear on the Page

The bane of a test automators existence is to have an element not be there when we need it. For many of us, the way we have dealt with this in the past is that we have put in sleep statements or other ways to place a delay in the test. the problem with doing this is that, if we wait, and the element isn't there, we have wasted that time. If the element is there, we still have to wait the allotted and pre-programmed amount of time. Once or twice, not a big deal. Over thousands of tests, it could prove to be a major time suck. thus, we want a more dynamic approach to how we handle waiting for elements to appear. WebDriver does this by using implicit and explicit waits.

Implicit Waits

An Implicit Wait is where we tell Selenium to wait for a certain amount of time before it throws an exception due to not finding an element. Here's an example as to how this can be used:



Explicit Waits

Explicit waits are what we use when we know what we want to happen and the error needs to fit that situation. The example David gives looks like this.



Well, we were on a roll here, but alas, I don't know what or why this isn't working. I may be able to figure it out as I dig into this more, but I don't want to hold up the rest of the review, so I'm just going to have to let this one hang as is for a bit.

So there it is, some examples of finding elements using Java and running them singly or in groups (the older test causes method has every single listing listed in this chapter running simultaneously. It'll work as a reference repository while I get more savvy as to how the use the API. Someday, I hope to know and remember enough that I won't need the cheat sheet, but I'm not there just yet. Hope to be soon enough, though :).


End of Section.