Automated Web App Testing With phpStorm

Selenium IDE was a great way to handle automated web app testing like the Store Locator Plus plugins for WordPress.    Selenium IDE is a simple script recorder and playback too that runs on Firefox.    Or, I should say, it used to run on Firefox.  That broke in 2017 when Firefox 52 came out.

After a lot of research I finally found a viable alternative to Selenium IDE that will work with modern browsers.  It is also free, locally installed, and open source. All winning attributes.  Paying for services is not much of an issue so the free part is not a requirement just a “that’s nice” feature.

Web app testing services

I tried several paid alternatives including Browserstack — a paid monthly service that runs virtual desktops and mobile device simulations hosting various browsers. Having to connect to a remote server via proxies or tunnels is a pain.    It also means no testing when offline or when the network is unreliable.    Having multiple browsers is great but 90% of the testing that needs to happen is base functionality which is the same across browsers.    Modern browser are also very good at testing mobile with browser like Safari going beyond simple screen sizing in their mimic of IOS, for example.

Other alternatives included several locally installed proprietary test frameworks.   Nearly every one of them ranges from mediocre to downright horrid.    This is clearly an industry stuck in the 1990s mindset of application development — from the start where you have to fill out a form with all your contact info to be “allowed” to demo the product (and be later harassed by sales people) to the 1980s desktop-centric interfaces.    Many did not work on MacOS.   Those that worked were heavy, bloated, and had a steep learning curve.    Does nobody integrate with my phpStorm, my web app IDE?

It just so happens that the best local testing suite today happens to be free.

The winner?   Selenium Webdriver with a few libraries like WebDriverIO + Mocha + Chai to make things easy.
Read More

Should The WordPress PHP Version Be Updated?

WordPress LOVES backwards compatibility as can be witnessed by the minimum-allowed WordPress PHP version remaining at 5.2.4 a decade after its end-of-life date.  It  may be  one of the reasons they have continued to garner market share.  Don’t require people to do anything to improve their site and they’ll wallow in complacency.  It makes sense.  Inertia is a big thing to overcome.  If you are a business focused on writing content, selling widgets, or doing just about anything else other than managing websites, upgrading software is way at the bottom of the priority list.

This backwards compatibility is one of the reasons why WordPress continues to RECOMMEND PHP 7 for performance and security reasons but allows the minimum WordPress PHP version to remain 5.2.4 without breaking the core application.    It is the reason why so many plugins, including Store Locator Plus, continue to do some convoluted things to reach that PHP 5.2 audience and keep their potential market as big as possible.
Read More

wp_enqueue_scripts Deep Dive

While trying to figure out why the footer-loaded scripts in Store Locator Plus are not being output on some admin page, I went deep down the rabbit hole of the WordPress wp_enqueue_scripts function.   Here are my notes from an analysis of WordPress (5.0-alpha-42191) .

wp_enqueue_scripts

/Users/lancecleveland/vagrant-local/www/wpslp/public_html/wp-includes/functions.wp-scripts.php

This is a PHP inline function.

The local $wp_scripts variable is set as a copy of the global $wp_scripts variable which is an instantiation of the WP_Scripts class.
Read More

Selenium on JavaScript : New WordPress Site Config Script

This article continues the journey into learning Selenium on JavaScript (SoJa).  It builds on the lessons of the previous articles and adds some common library functions to make our tests more readable and starts to employ the Don’t Repeat Yourself (DRY) concept.

In this case we are going to build a common library module that we will re-use in future scripts. It will load our configuration and environment.  It will also export some methods that make our test script code a lot easier to read. The configuration and environment setup functionality is covered in prior articles so we’ll leave that out of this discussion.

What This Script Does

This script automates the very first steps of setting up a WordPress site after the software has been installed.  We use this on our Store Locator Plus development systems after doing a “fresh install” of WordPress so our dev team doesn’t have to keep typing in the same 5 things over-and-over every week when we spin up a new release to be tested “from scratch”.

The script will select our language (English, the default) wait for the next screen to load and then type in the title of the site, our username, email, check some boxes and click the install button.      The other elements of setting up our site such as the database name, etc. has been completed as part of our base dev box setup so you won’t see that here.   You can easily extend this test to cover the other WordPress install forms.

The Scripts

We’ll leave out the configuration and environment scripts as they have been covered a few times in other articles. Our main test script and the common lib are below.

Main Test

Common Lib

Discussion

The Main Script

The main script itself is fairly self-explanatory thanks to our new helper methods in our common library.   The main script load the common library and assigns it to the local test variable.    That library has setup logging for us, the Selenium Webdriver, and some “nice to have” functions that we’ll get into later.

We output that our activate site test has started to the log window, load up our WordPress site URL with the get command and when the page is loaded click the continue button, wait for various form elements like the blog title to appear and fill it in.  We also click some things as well.

Simple, right?

The Magic, aka Common Library

The real magic happens in the common library.   It employs the tricks we’ve learned in previous lessons to build reusable code and make our main scripts easier to read.   It uses the standard NodeJS module export technique to define names for our methods as well as their functionality.

There are some things that are common for most web tests, type a value into a form field, click a button on a form.    We’ve added some “make this stuff behave” logic using the Selenium Promise-based style to ensure things are more stable than randomly typing stuff and hoping they are on our page.

Let’s review our new methods in more detail.

When ID Exists Type

This method is used to look for an input on a page by its HTML ID and type something into the form.    We could just “jam some key strokes” into a field and assume it is on our page.  However we often are waiting for dynamic JavaScript elements to appear on modern websites.   We also have pre-filled input fields like password suggestions to deal with.   Things are not as simple as they seem.

In this method we first tell Selenium to wait for the element to appear on our page.   Our wait loop will give the web page 6 seconds to present the element or throw an error.   That is the driver.wait() part with until.elementLocated() within.

If the element is located run the success function defined within the then() follow-on method attached to the driver.wait() call.

Notice we assign findElement() to var el.   Why?  We want to make sure the input field is EMPTY when we start.    We do that by click on the input field first, then clearing it out, then ending our value in as keystrokes.   This addresses any pre-filled fields like the WordPress password suggestion as well as any add ons your browser may be employing that auto-fill forms (if you did not disable them, which you should).

The when_id_exists_click() is the same idea as the input method but in this case we have less work to do since we are clicking a button and don’t have to clear the element out.   No need to explain further.

When Name Visible Click

This method is a bit different than the ID Exists Click or ID Exists Type methods.   While the concept is the same the difference is in the execution.    The Selenium until.elementIsVisible() method has been constructed differently than the other methods in the library.    This is one of those language inconsistencies, and every language has them, that drives developer crazy.

 

Many of the other until.blah() methods take a LOCATOR as the parameter, in other words the By.id or By.name method where the locator is what is being processed.   elementIsVisible() takes the actual web element itself.    It’s a gotcha that has tripped up more than a couple of Selenium coders.   It is why our Visible Click method is more complex.

To not repeat ourselves and ensure consistency we setup our locator in the by variable to locate an element by name.    We let the driver wait until our element is found by name on the page, using the standard 6 second delay.   Once we know the element is on the page we assign it to the el variable and then do another wait until the element is visible.

Remember, just because an element is within the web page (part of the DOM structure) it does not mean it is visible.   It is also important to know that many Selenium functions will NOT let you interact with an element that is not visible.

 

JavaScript Selenium Newb Cheat Sheet

Finding documentation on Selenium is hard enough for the “main languages” of Java or Python.    There are lots of examples of how to do things there in those languages but very little for the JavaScript libraries.   While you can translate most of the Java example to JavaScript there are some differences.    You’ll also find that there is a LOT of outdated information.    To make things more interesting you’ll also find that the older the example the more likely the code samples include browser or environment-specific methods.

Writing Selenium tests in JavaScript for Safari has very little documentation.   I decided to create my own cheat-sheet for future reference when I forget how I did this stuff.

Loading The “Nice To Have” Shorthands

It took me a little longer than it should have to figure out how to load up the shorthand notation for the webdriver libs so the example code provided would run outside the webdriver directory.

This neat trick now allows the script to refence things like By.id() or until.titleIs() so that we can do things like click a button and then wait until the page title is “New Page Title” to pace our test scripts.

Running Commands In Sequence

For many tests it is important to run the steps so that A finished before running B.    Opening a web page, clicking a button, then typing information into a form that was previously hidden for example.

The trick?  String together .then() methods.    I like to do this on a page get but it can also be done after nearly any webDriver command.    The simplified “on success” format works well in most cases to create a simple syntax:

Setting The Safari Window Size

The default window size for Safari while running in “Enable Remote Automation” mode is based on 1985 screen sizes.   I’ve not checked but it looks to be the size of 132 column x 80 row terminal or possibly the new-fangled 640×480 high resolution screens that came out when AOL first  came online.

I prefer to see more than a postage-stamp size view of my website when running testing.    You can set the window size after the driver is connected with the setSize() method.

Setting The Window Placement

For some reason Safari seems to like to throw the testing window near the bottom of the screen so it runs off the edge of the monitor.  If you like watching the tests run, especially during test development, this kind of sucks.   Force the position near the top-left of the screen with the setPosition() method.

Logging Things

You can console.log() the crap out of your test cases.    However most decent test suites have a logging utility.   Selenium does too and it is in webdriver.logging.     If you used the shorthand aliases above you can turn on the console handler then log every single detail to the console.

You’ll probably want to crank that down a few notches from 11, so you need to know the level names.   They are in the logging.js lib:

At first glance, Level.DEBUG seems to be a good starting point for things but we’ll see how that goes as more complex tests are developed.

To log stuff at an “Info” level:

Related

How to write reliable browser tests using Selenium and Node.js is a cool article on writing functional Selenium tests with Node.js.

Video Time

A short video on how this stuff looks on MacOS with Safari, phpStorm, and Selenium running in JavaScript with NodeJS.

%d bloggers like this: