Google Analytics


To search for specific articles you can use advanced Google features. Go to and enter "" before your search terms, e.g. CSS selectors

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

Wednesday, February 7, 2018

Clearing space on a macOS hard drive

As a tester I'm often hoarding articles, data, VMs and tools on my hard drive.

The hard drives a decade ago where IDE or SATA hard drives. It is easy to find 1 terabyte (1000 gigabyte) hard drives. So I tend to put 1 or 2 terabyte hard drives in my computer.

Today you tend to find computers using SSD hard drives. When they first came out all you could find was 128 gigabyte or 256 gigabyte hard drives. Getting 128 gigabytes was normal because the 256 gigabyte hard drive was often a few hundred dollars more.

As time went on, the cost of SSD drives came down. Now it is common to find 256 gigabyte hard drives and it is a few hundred dollars more for a 512 gigabyte hard drive. Still 256 gigabyte is a LOT smaller than a 1 terabyte hard drive.

Large data sets and VMs for testing different operating systems and browsers would often take up a LOT of space. Add to that all the tools I typically use (development, automation, communication, productivity, etc.) and I quickly find a 256 gigabyte hard drive full.

Recently, I kept finding I would have to backup something on my hard drive and delete it to make room for something on a new project. I kept trying to figure out how to free up more space on my macOS hard drive. I have only a 250 gigabyte flash drive in my laptop and it always seemed to be at 230 gigabytes used.

Recently I read about how backing up your hard drive using Time Machine would create these local backups on your hard drive. The article talked about where the folders with the local backup were and how you could just delete the folder and it would free up a lot of room.

With the latest version of macOS (High Sierra 10.13), it uses APFS. This new file system has a number of advantages around speed, encryption, reliability, etc.. However, new file systems often mean just deleting things from the Terminal or using older hard drive clean up applications, could result in the file system getting a little messed up.

So rather than just delete local Time Machine backups, I would recommend using the tools which come with the operating system. In this case the tool is called tmutil.

If you go to a Terminal and enter tmutil it will give me a list of things it can do. One of those things is listing the local backups. To see them you can use:
tmutil listlocalsnapshots /
This will list the local snapshots on the root hard drive. From the output, you can then delete one or more of the local backups. I deleted all the local backups and found my hard drive went from 230 gigabytes used down to 117 gigabytes used. Essentially, the local backups were taking 113 gigabytes (almost half my hard drive).

To delete a local backup, I'd use:
tmutil deletelocalsnapshots <snapshot_date> 
where <snapshot_date> would be the date of the snapshot. Basically, the output of listlocalsnapshots would be:<snapshot_date>
where <snapshot_date> is something like 2018-01-14.

Wednesday, March 29, 2017

How to use secrets

From time to time you heard about how someone's site has been compromised and customer's personal information has been leaked. For example, Target Got Hacked Hard.

What can you do? Good passwords is a start.

First is understanding how do we choose a password.

If the password can be 10 characters with uppercase, lowercase, digits and symbols it could be (26 + 26 + 10 + 32) to the power of 10 or 5.386151140948997e19 different possible passwords. Even if you could attempt thousands of password attempts a second, it would take you eons to be able to crack this. Most systems will also throttle how many attempts to you can make per minute.

A good hacker won't attempt all possible combinations. They would use a dictionary to restrict the attempts to known password combinations. They might be able to reduce the number of different possible passwords to something they could attempt within a year. So systems will often request you change your password every 90 days.

Additionally, if the system allows for more characters (password length of 20 or 30 characters) just adding a few characters will make it exponentially harder to crack.

So don't use known patterns (dictionary attack), make your password as long as possible, change it every few months. The change should also be significant.

Now maybe you have to type the password into a mobile device and a really long, complicated password is going to be a bother. So you end up shortening it. Also, if you password is something like "CBVcP3Zj/i}3mK,xUL7U", you are never going to remember that. You will be tempted to make it shorter, easy to remember and you won't want to change it too often. So something like "!Passw0rd!" seems like a good password. It has uppercase, lowercase, digit, symbols, it is easy to remember, it is 10 characters long. However, it is easy to guess. A hacker will DEFINITELY have this in their dictionary.

What about changing the password? If your password was "My!S3cr3t!Passw0rd!" and I changed it to "My!S3cr3t!Passw0rd!01", next I used "My!S3cr3t!Passw0rd!02", someone will guess this with a dictionary attack.

Additionally, it used to be that a 6 character password wasn't crackable by brute force. As computers got faster we needed 8 character passwords. Today it seems that companies are recommending 12 character passwords. So if you want to be safe, you should use at least 20 character passwords.

So REALLY the password of "CBVcP3Zj/i}3mK,xUL7U" is what we want to use. That said, I've known security staff walk around the office looking for post-it notes. People will write their password on a post-it note and stick the note to a monitor. A lot of time, systems are hacked because of an insider getting a password which was written down. When I first got into computers, a high school teacher wrote the password to the system on a sheet in his desk. I know this because students would see him looking in his desk then logging in the system. One of the students stole the password from his desk.

What about saving it on a file in the computer. That works even better for some things. I need to log into a website. I open my text file, copy the password, paste it into the website. What happens if someone gets a copy of my text file. Then they have all my passwords.

I can put them in a spreadsheet with a password or a zip file with a password. Is the password to the spreadsheet going to be "CBVcP3Zj/i}3mK,xUL7U"? And I don't write it down? Probably not.

This brings us to dynamic and static storage. If my password is in a variable or the clipboard, I can turn off my computer and it is gone. If it is stored in a text file, someone can make a copy of the file and take days trying to crack it. Hackers will sometimes get encrypted database files then spend weeks trying to crack it. This is where they get common passwords for their dictionary attacks.

What if your files are automatically backed up to iCloud or Google? Then someone might be able to intercept them and take weeks trying to crack them.

Also, how do you think I came up with "CBVcP3Zj/i}3mK,xUL7U"? The answer is a password vault program. There are a few. I use 1Password (because it works on all the devices I use). There are free options like LastPass, KeePass, Dashlane. Have a look at List of password managers for these and other options. Now you just have to pick one good, strong password to secure your vault.

Additionally, if you don't backup your vault to a cloud or let people have access to it, they cannot hack it.

Another bad practice I see people doing is saving passwords in variables. This is less for your personal passwords and more for programmers accessing enterprise sites. I might have a utility which accesses the XYZ system. If variables are set, it never asks me for a password. I might have:

export XYZ_USERNAME='abssass'
export XYZ_USERNAME='2eD$g^^nJk5wHki6Lsst4Gwr'
Now if I run the utility it will see these variable are set and use them to log in. Or I might  have something like: "http://$XYZ_USERNAME:$XYZ_PASSWORD@hostname" and so long as the variables are set, it will automatically log me into the website.

But now we are back to saving passwords in a text file. Things like export statements are saved in ~/.bash_profile on my computer.

For the team they might save the passwords in a team password manager. For example, vault by Hashicorp. To get my secrets I might execute something like:

vault read /secrets/team/storage/xyz
This might return something like:


So now I can use my UNIX/Linux skills to parse the username and password out and save them in a variable. For example:

export XYZ_PASSWORD=$(vault read /secrets/team/storage/xyz | grep xyz_password | awk '{print $2}')export XYZ_USERNAME=$(vault read /secrets/team/storage/xyz | grep xyz_username | awk '{print $2}')
This will read the information from the vault, parse out the appropriate information and save it to a variable. When I turn off my computer the variables are gone and the password isn't saved in a text file... not even encrypted.

Tuesday, March 21, 2017

Using Charles from the command line

If you are testing network traffic you are probably familiar with Fiddler. Fiddler is a nice, easy to use tool for monitoring network traffic.

It works very easy. You start up Fiddler and it configures your Internet Settings. Now when you start up a web browser, it automatically routes traffic through Fiddler. As you hit web pages on the browser, the HTTP requests and response show up in Fiddler. It is very easy to read and understand what is going on.

If you are using a macOS computer you will be sad to learn that Fiddler does not exist for macOS. It is a Windows only product. If you check for free options to do the same thing you find Wireshark (formerly Ethereal). But Wireshark's configuration and output assumes you have knowledge of TCP, HTTP, Sockets, packets, etc. You can get the information that you need but it is not as easy as Fiddler.

Additionally, to play back a request with some modifications is a lot harder with Wireshark than with Fiddler.

So what do you do? Charles Proxy. Unfortunately, it is not free but at $50 it is a good investment. If you are working at a company with many people needing it, there are discounts available as well.

Now if you get Charles you will find it automatically starts up and changes the Network Settings on your macOS. So all the browsers and anything which uses Network Settings, will automatically go through Charles. 

What about command line? For example, I have a Docker script which creates a container, deploys a web service and waits for someone to hit it. What if I'm creating automation using Python, Java, bash script, etc.? These do not use the macOS Network Settings. So you will see nothing in Charles.

The solution is to add the necessary information to the shell before you launch your test scripts.

The way Charles works is rather simple. If my machine is using and I want to hit ( it might following the following route:
The way Charles works is creating a MITM (Man-In-The-Middle). So if I want Charles to be able to observe the traffic the route might be:
  • CharlesProxy
The way it does this is by creating proxy settings in Network Settings. To create proxy settings on the command line you need to set certain variables. For HTTP traffic and HTTPS traffic Charles tells macOS to set it to use IP address and port 8888.

For the command line you want to use:
export http_proxy=""
export https_proxy=""
Additionally, Charles tells the macOS to bypass certain addresses. What I do is go to System Preferences, select Network, select the Advanced... button, to to the Proxies tab.

On this page, assuming you are running Charles, you will see a bunch of addresses in the Bypass proxy settings box. Select all of them, copy them into the clipboard, go back to the command line and enter:
export no_proxy="<paste>"
With these three settings, anything you run from the command line will go through Charles.

However, if you close the shell you lose all the settings. If you want to keep the settings you can add them to your ~/.bash_profile text file. Every time you open a shell it will add the proxy information to the shell. HOWEVER, you don't want this if you are not using Charles. To disable this you need to enter:
unset http_proxy
unset https_proxy
unset no_proxy
So what I do is add the following to my ~/.bash_profile text file:
# Charles shortcuts
function charles_on {
        export http_proxy=""
        export https_proxy=""
        export no_proxy=",,,,,,,,,,"
function charles_off {
        unset http_proxy
        unset https_proxy
        unset no_proxy
By adding this to my ~/.bash_profile text file I can use:
to enable Charles. And I can use:
to disable Charles. Whenever Charles is not running I MUST disable Charles on the command line.

Wednesday, August 24, 2016

Mobile web testing

I've been working on a project recently which required testing on a mobile device. The project started in April this year and was focused solely on iOS.

When I looked into what was available for mobile testing I found a number of different tools:

  • KIF
  • Appium
  • Frank
  • Calabash
  • EarlGray
  • UI Automation
What I found next was a bother. I need a tool which would be used for testing the IPA we would ship from an app store. Tools like Frank and Calabash are great at automating tests but they required you to build a special version of the app. This would not be the same app you deployed to an app store.

This made it easy to eliminate those two great tools from my list of potential test automation tools.

I then looked into KIF and EarlGray. They had great reviews and looked really promising until I noticed Apple made significant changes to the UI Automation framework and broke KIF and EarlGray. So if I wanted to test against iOS 9.3 developed with XCode 7 and Swift I was probably not going to want to use KIF or EarlGray.

So the obvious choice was Appium. However, even Appium seem to be affected by the changes Apple announced at the July 2015 Developer Conference. :(

Since our iterations were one week and waiting to see who would 'fix' issues with their framework wasn't really an option, we branched Frank and started developing the app using Frank for UI testing. In the meantime we looked at UI Automation (our app was iOS only, so we didn't need to worry about Android support).

Initial use of UI Automation seemed good. So we started automating UI tests with it but continued to keep the Frank tests running in parallel. However after a few iterations we started to see maintaining the UI Automation tests was becoming increasingly difficult. Since I got into UI automation in 1998 I have found that failure to maintain a test automation framework is one of the common reasons for UI automation to fail. We didn't have a team of 20 QA Automation experts to keep the UI Automation framework going. :(

So I had a second look at the previously discarded frameworks. To my surprise and delight I found that support for them had been re-established and I took a second look at using Appium. 

Appium is definitely not fast and I'm looking for ways I can reduce the execution time of the Appium test suite (currently 15 minutes when run on hardware; I'd like to get it down to 5 minutes plus add more tests; maybe run tests in parallel on four or more phones).

Bottom line, Appium seems to be working well for us. I've created a page object model framework. In my next article I'll talk about using the Appium Inspector on a Mac laptop and things I found blocked me or slowed me down.

The difference between NotFoundException, NoSuchElementException and StateElementReferenceException

Been a while since I posted something here...

Recently, someone on the WebDriver Google Group asked what the difference between NotFoundException, NoSuchElementException and StateElementReferenceException are. Here is the answer I posted:

The NotFoundException is a super class which includes the subclass NoSuchElementException. The known direct subclasses of NotFoundException are: NoAlertPresentException, NoSuchContextException, NoSuchElementException, NoSuchFrameException and NoSuchWindowException. So if I want one catch statement to catch all five exception and they will all be handled the same way then I can just handle NotFoundException. But if I want to handle any of these five exceptions differently, I can catch the more specific subclass.

The NoSuchElementException is thrown when the element you are attempting to find is not in the DOM. This can happen for three reasons. 

The first is because the element does not exist and never will. To fix this, change your findElement to be correct.

The second is that you need to do something on the page to make the element appear. For example, the user selects Country and javascript populates a City field. If you attempt to look for a city before you select a country, the city you are looking for does not exist and you get a NoSuchElementException. To fix this you have to make sure the steps in your test are correct.

The third is that the element is generated by javascript but WebDriver attempts to find the element before the javascript has created it. The fix for this is to use WebDriverWait to wait for the element to appear (visibility and/or clickable).

StaleElementReferenceException is when you find an element, the DOM gets modified then you reference the WebElement. For example,

WebElement we = driver.findElement(By.cssSelector("#valid"));
// you do something which alters the page or a javascript event alters the page;

A classic example if this might be:

List<WebElement> listOfAnchors = driver.findElements(By.tag("a"));
for(WebElement anchor : listOfAnchors) {;

This code will get all the anchor elements into a list. Lets say there are 5 anchors on the page. The list now has 5 WebElement references. We get the first reference and click it. This take us to a new page. This is a new DOM. We print the title of the new page. Then we use back() to go back to the original page. The DOM looks just like the same DOM but it is a different DOM. So now all the references in the list a stale. On the second iteration, it gets the second reference and clicks it. This will throw a StaleElementReferenceException.

More difficult to debug is:

WebElement we = driver.findElement(...);
// javascript event gets fired by the website;

Sometimes this will throw a StaleElementReferenceException but sometimes the timing will be different and the click will work. I've seen many people have this intermittent problem. They add more code which doesn't fix the problem. The extra code just changes the timing and hides the problem. The problem comes back a few days later. So they add more random code. It looks like they fixed the problem but they just changed the timing. So if you get a StaleElementReferenceException and it is not clear why, it is probably this problem and you need to figure out how to make the findElement and click atomic.

Friday, January 8, 2016

Difference between using current node (.) and text() function in XPath for Selenium locators

Recently someone asked about using the partial link text to find an anchor with an IMG tag in the middle of the text. The HTML snippet was:

<a href="something.html">
<img src="filename.gif">
partial link text
The initial attempt for a locator was:
"//a[contains(text(),'partial link text')]"

Normally I would expect this to work. However, the text() function does not seem to find it. Peter Jeffery Gale (thanks Peter) noticed that the following locator did work:
"//a[contains(.,'partial link text')]"
The . notation is the current node in the DOM. This is going to be an object of type Node. I'm guessing that the Node is getting cast to a string. Something similar to:
"//a[contains(string(.),'partial link text')]"
The end result seems to be that getting the entire Node, convert it to a string and scanning the string for a substring always works. Using the XPath function text() to get the text for an element only gets the text up to the first inner element. If the text you are looking for is after the inner element you must use the current node to search for the string and not the XPath text() function.

Thursday, September 25, 2014

Silencing ChromeDriver with WebDriver

While setting up a test environment today we decided to have the tests running on the same machine as the build radiator.

A build radiator takes up the entire display. It shows a green bar for each job on the build server. If someone checks in a change and it breaks a test, the bar turns red and everyone stops to fix the build.

The consequence of this is that the build radiator has to be visible to everyone in the room. Having a browser open on the display is not an option.

So we need to run our WebDriver tests without showing the browser or any other output. Our build server is running Linux. So we have WebDriver tests. We can run them from the command line using something like:
java org.testng.TestNG testng.xml
where testng.xml is a TestNG test suite example. When we run it as this we see the browser open and the tests executing. The tests were written using ChromeDriver. When we run this on the build radiator however, we don't want the browser opening. The solution is actually quite easy for Linux. We use an application called Xvfb:
xvfb-run --server-args="-screen 0 1600x1200x24" java org.testng.TestNG testng.xml
The command xvfb-run will run the application using the X Virtual FrameBuffer. The --server-args lets us pass arguments to the server. The "-screen 0" tells xvfb to use screen 0. The "1600x1200x24" tells xvfb to make the virtual display 1600 by 1200 with 24 bit depth. If your application has to work on 1024 by 768 and 16 bit colour then you can use "1024x768x16".

When you execute this you will not see the browser open. It almost seems like nothing is happening. The only thing you will see is the output from TestNG (a dot for a pass, an I for an ignore and an F for a failure) and the output from chromedriver. What if you want to look at the logs and see just the output from TestNG; not interlaced with output from chromedriver?

This requires a few changes to the creation of the WebDriver object. Normally, you might have something like:
System.setProperty("", "./chromedriver");
WebDriver driver = new WebDriver();
but this outputs chromedriver log information to the screen. You could use:
System.setProperty("", "./chromedriver");
System.setProperty("", "--disable-logging");
WebDriver driver = new WebDriver();
This will stop most the output but you will see the header for when chromedriver starts up:
Starting ChromeDriver (v2.9.248307) on port 9515
So how do you get rid of this? I was digging through the code for chromedriver (remember it is open source) and I found some code where it was checking for the property If this was set to true then it would run with the silent flag set to true. So I tried:
System.setProperty("", "./chromedriver");
System.setProperty("", "--disable-logging");
System.setProperty("", "true");
WebDriver driver = new WebDriver();
Sure enough that did it. Complete silence from chromedriver.