Google Analytics

Search

To search for specific articles you can use advanced Google features. Go to www.google.com and enter "site:darrellgrainger.blogspot.com" before your search terms, e.g.

site:darrellgrainger.blogspot.com CSS selectors

will search for "CSS selectors" but only on my site.


Tuesday, May 7, 2013

Is an element on the visible screen

A number of times I have been on a website where clicking a link goes to a specific page with a specific element at the top of the page. For example, I am reading an article and it quotes a book. The quote is actually from page 17, paragraph 2, first sentence. So when I click the link to the article it should take me to page 17, paragraph 2, first sentence.

So how would you automate testing this?

The simple answer would be to find the WebElement which is expected to be at the top of the page. This is the easy part. Then you need to see if the WebElement is on the visible screen. If you click it, WebDriver will scroll it into view. This is not what we want.

So what do we do? The answer is find out the size of the visible window then see if the bottom-right corner of the WebElement is inside that dimension. So here is the code for that:

  private boolean isWebElementVisible(WebElement w) {
    Dimension weD = w.getSize();
    Point weP = w.getLocation();
    Dimension d = driver.manage().window().getSize();

    int x = d.getWidth();
    int y = d.getHeight();
    int x2 = weD.getWidth() + weP.getX();
    int y2 = weD.getHeight() + weP.getY();

    return x2 <= x && y2 <= y;
  }
This will tell me of the element is on the visible window. If the element is not on the visible window it will return false. If the element is on the visible window it will return true... well almost. Unfortunately, you can get the size of the browser window but you really want the size of the chrome, inside the window. So if the window dimension is 1024x768 it is really telling you how big the OUTSIDE of the window is and not the inside. If the element is located at 1024x768 it is really off the visible window. For example, on my Google Chrome the tabs/title is 22px high. So the visible screen would really be 768 - 22 or 746px.

So this is a close approximation but there is a small chance of the element being just off the bottom of the window and still return true. If you are running driver.manage().window().maximize() the odds that something is going to be off the bottom of the visible window is small enough that it is not worth worrying about. Add to that we would hopefully be manually testing the area occasionally during exploratory testing and the risk should be acceptable.

There is another problems with this. We aren't actually checking that the upper-left corner of the element is at the top of the screen. You might think, why not just check that the element we are looking for is at position (0, 0)? The reason for not checking this is because the element might not be exactly at (0, 0). If the screen is large enough for 20 elements, the page only has 4 elements and the element we are looking for is at the second position, it will be impossible for the element we are looking for to scroll. So it will be below (0, 0) but still on the visible window.

A good example if this code would be:

    driver.get("http://www.w3schools.com");
    WebElement we = driver.findElement(By.cssSelector("#gsc-i-id1"));
    assertTrue(isWebElementVisible(we));
    WebElement we2 = driver.findElement(By.cssSelector("#footer"));
    assertFalse(isWebElementVisible(we2));

This will go to www.w3schools.com, find the Google search input at the top of the page, confirm it is visible. Then it will find the footer at the bottom of the page and confirm it is not visible.

Wednesday, May 1, 2013

Why using JavascriptExecutor in WebDriver can be dangerous

I have occasionally seen people recommending running javascript using the JavascriptExecutor implementation. For example, I was working on a project where a test would pass on the developer's computer but would fail on the functional test machine. The line of code which failed was:
driver.findElement(By.cssSelector(".save")).click();
So the developer changed it to:
((JavascriptExecutor)driver).executeScript("$('.save').click();");

It seemed harmless and it worked.

The GUESS was that WebDriver found the button because it was always in the DOM with style="display: none;" but the click failed because it wasn't waiting for the button to become visible.

The idea was that the test was REALLY:

- open the dialog
- wait for the button to become visible
- click the button

If we used javascript we didn't have to wait for the button to be visible. So javascript seemed faster but was still testing the right thing.

No problem, right? Wrong. It turned out that the save button was on a javascript dialog which did not scroll. If you scrolled up and down the page the dialog remained still; the dialog ALWAYS stay exactly 120px from the top of display. When all the tests ran it created data which made the dialog 830px high. This placed the bottom of the dialog at 950px. The developers machine was 1600x1200 display. It made the dialog fully visible on the display. The functional test machine was set to 800x600. This forced the bottom of the dialog off the bottom of the display. Even when you made the browser full screen you could not see the save button.

So on the developers machine WebDriver would see and click the save button because it was visible. On the functional test machine (set to 800x600 because that was the minimum requirement) it was not visible and you could not scroll it into view because the dialog did not scroll.

When they switched to the javascript code it clicked the button regardless of whether the button was visible or not. If we shipped this application, any customer who was using a computer with 800x600 display (a significant number of people based on analytics) would be unable to click the save button even though the functional test passed.

The moral of the story is, if the javascript solution doesn't test EXACTLY the same requirement as the WebDriver solution, you could be making your tests report a false positive.

Saturday, April 13, 2013

Determining which version of Selenium goes with which browsers

Sometimes it is hard to know which version of Selenium you should be using. There is no hard and fast rule of which Selenium works with which browser but I have always found that you want a Selenium which was released after the browser but as close to the browser release date as possible.

It has been my experience that the latest version of Selenium and the latest version of Chrome go together. I have never found that the latest version of Selenium does not work with the latest version of Chrome.

On the other hand, I have seen Mozilla release a new version of Firefox and it takes a few weeks for a new version of Selenium to appear. During this period I find the latest version of Selenium does not work with the latest version of Firefox.

For example, Firefox 18.0 was released on 08-Jan-2013. At the time the latest version of Selenium was 2.28.0, released on 11-Dec-2012. If you updated to Firefox 18.0 the moment it was available, you might find that some of your Selenium tests started failing unexpectedly. Selenium 2.29.0 was released on 17-Jan-2013. I always disabled the ability for Firefox to automatically upgrade. When Selenium 2.29.0 was released, I upgraded my Selenium to 2.29.0 and my Firefox to 18.0.

You can see the release dates of Firefox (and other Mozilla browsers) on https://wiki.mozilla.org/Releases. What I do is create a list of Selenium release dates from the Selenium download area (https://code.google.com/p/selenium/downloads/list). I would then look at the Mozilla wiki and determine which Firefox had been released on an older date. From my example above:

11-Dec-2012    Selenium 2.28.0
30-Nov-2012    Firefox 17.0.1
or
17-Jan-2013    Selenium 2.29.0
08-Jan-2013    Firefox 18.0

Or in other words, if the project I am on has set a specific version of Firefox to support then I look for the Selenium which was released AFTER the Firefox release date. That is the combination I would test with.

For Internet Explorer I can find the release dates by searching for "Internet Explorer Release Dates". This currently takes me to IE Downloads. I also find the Wikipedia has an Internet Explorer page which gives release dates as well.

For the most part however, I let the version of Firefox drive which version of Selenium I need. Because I tend to have clients request IE7, IE8 and IE9 support, I find it best to go with the latest version of Selenium to support the latest version of IE.

Selenium does have limited support for Safari but this is typically not an issue. Much like IE, I let the version of Firefox drive which version of Selenium I need regardless of which version of Safari I need to support.

It should be noted that this is a general idea of how I determine which version of Selenium I want. If I use this rule and start finding that the version of Chrome matters, I would start trying to match the release date of Chrome to the release date of Selenium.


Tuesday, November 27, 2012

List of Selenium/WebDriver blogs.

I was recently pointed to a nice list of Selenium/WebDriver blogs. If you are looking for more information about Selenium/WebDriver you should check out http://it-kosmopolit.de/Selenium/blog/selenium-blogs/selenium_blogs.php.

I haven't checked out all the links but there appears to be a good start to the list of Selenium/WebDriver blogs available out there.

Monday, October 29, 2012

Generating a file of a specific size

Every once in a while someone is looking for a file of a specific size. Occasionally, it must be real data. If you are transmitting the file and the data will be compressed then the type of data will make a difference.

However, if you just need a file to fill some space or there will be no compression then Windows has a neat little utility called FSUTIL.

The FSUTIL file can be used for a number of things but the nicest feature is creating a new file filled with zero bytes. First, you need to know how many bytes. If you want a file which is 38 gigabytes then you need to figure out how many bytes that is. Technically, it is 1024*1024*1024*38. If you want  a rough idea you can just use 38,000,000,000 but a 38 gigabyte file is really 40,802,189,312. Next is which file you want to hold the data. Let's say you want to create C:\DELETEME.TXT then the full FSUTIL command is:

fsutil file createnew C:\DELETEME.TXT 40802189312

This will create a 38G file is a matter of seconds.

For UNIX, Mac OS X or Linux you can use DD. The DD command is for converting and copying files. If we wanted to create the 38G file with DD the command would be:

dd of=deleteme.txt oseek=79691776

The oseek is the magic. It will seek n*512 bytes. The standard size of a block is 512. So we take 79691776*512, which is 38G. Even easier would be:

dd of=deleteme.txt oseek=38m obs=1024

This will generate a file of 38M * 1024 or 38G. Much easier to figure things on working with values like these. That is, no need for a calculator.

IMPORTANT: after you press enter on the DD command it will take the standard input as its input. So you need to enter CONTROL-D.

The other option for UNIX/Linux/Mac OS X is to copy a file of a set size. The nice thing about this is you can take a file with real data and copy it enough times to make a single file of the correct size. For example, if I have a text file with 512 bytes of real data I can set the if= to that file and make multiple copies of that one file into the output file.

Thursday, July 26, 2012

Removing logout button

When I set up a Selenium Server it only works when someone is logged in. In a previous article I wrote how to make a user automatically log in. For this article I'll write how to prevent that user from logging out.

  1. Run regedit.exe
  2. Go to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies
  3. Create a new Key called Explorer
  4. Go to Explorer folder
  5. Create the DWORD key StartMenuLogoff.
  6. Set it to 1.
  7. Go to the Start Menu and use Shutdown or Reboot (so Logoff is not the last option used).
When you log in as that user now, they will not have a Logoff button available to them. This has been tested on Windows 7.


automatic log in, automatic run

When writing test scripts for testing an installer, on Windows, one of the challenges is when the installer requires a reboot. To handle this I use automatic log in and the run once features of Windows.

To create automatic log in:
  1. Run regedit.exe
  2. Go to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
  3. Set DefaultUserName to the name of the person you want to automatically log in. If the key does not exist add it as REG_SZ.
  4. Set DefaultPassword to the user's password. If the key does not exist add it as REG_SZ. Note: anyone who can read the registry can see the user's name and password. Create a local user with no permission on your network.
  5. Set AutoAdminLogon to 1. If the key does not exist add it as REG_SZ.
  6. Set ForceAutoLogon to 1. If the key does not exist add it as REG_SZ.
And that is all you need to have the computer automatically log in after a reboot.

The second part is to create a script which will start up the automation at the right place. What usually happens is the installer will put something in place so that after the reboot it will continue with the install the moment the user logs in. If this is the case for your installer, write a script which continues the automation and add it to the RunOnce key. Assuming you have a batch file which starts part 2 of your automation:
  1. Run regedit.exe
  2. Go to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
  3. Add a string value
  4. The Name of the should be something like zzz_Automation
  5. The Data value will be the full path to the batch file. It is important to note that the current directory will not be the location of the batch file. Do not assume it will be in your script. Either use full paths for everything in the script or change to the directory you think you should be in then continue with the script.
Enjoy.