Common Testing Scenarios

A collection of common scenarios that come up while browser testing

Search our documentation:

Toggle Documentation Menu

Common Testing Scenarios

Jump to...
  • Reusing Test Steps - Reuse test steps (ex: Login steps) across various tests
  • Assert URLs - Verify the URL of the current page
  • Stripe Checkout - Testing a checkout flow that uses Stripe
  • A/B Testing - Testing a user journey that involves A/B testing
  • Date Pickers - Interacting with date pickers and other widgets
  • Select2 Menus - Interacting with select2 dropdown menus
  • iFrames & Frames - Interacting within iframes and traditional frames
  • Popup Windows - Interacting within popup windows
  • jQuery - Injecting jQuery for use during your tests
  • Google Analytics - How to exclude, or check for, Google Analytics during testing
  • CAPTCHAs - Dealing with CAPTCHA human challenge widgets
  • SMS OTP - Fetching one-time passwords that are sent via SMS using Twilio
  • Embedded Editors - Interacting within embedded editors such as CKEditor
  • Scrolling - Manually scrolling a page within a test
  • Image Loading - Check to ensure that an image loaded properly

Assert URLs

You may wish to verify the URL of the page that you are on during your test. There are two methods available for doing this. The simplest is to use a stardard assertion step, such as "Element text equals", and set the target of the step to url. Alternative, you can check the URL of the current page using your own JavaScript code in a JavaScript returns true assertion:

return window.location.href === 'https://www.sampleurl.com';


Testing Stripe Checkout

Stripe Checkout should always be tested in "Test" mode using dummy information. This typically means using a card number of "4242 4242 4242 4242". Live credit card numbers should not be used in your Ghost Inspector tests.

Stripe is a common payment platform used across the web. They offer various ways of capturing payments, one of which is a drop-in JavaScript + iFrame checkout module for your website. Ghost Inspector is fully capable of testing checkout flows that use this payment module. However, due to the form validation involved and the dynamic attribute tags, small tweaks may sometimes need to be applied after your test has been recorded.

If you've used the test recorder to capture your actions during a Stripe checkout, you should see a set of steps similar to the ones shown below.

Recorded Stripe checkout steps

These steps should work properly from the get go in your test. However, the __privateStripeFrame8 that is used in the name attribute of the iframe could potentially change. In most cases, you can broaden these selectors by changing the iframe[name="__privateStripeFrame8"] portion to simply iframe. Ghost Inspector will still be able to locate the elements and will continue to work even if the iframe's name attribute changes.

Broadened Stripe checkout steps

If you find that the credit card information is being jumbled when it is assigned during the test run, that typically means that the assignment is happening too quickly and is conflicting with Stripe's validation logic. In this case, it's best to break up the single "Assign" step into individual "Keypress" steps to key in the values one digit at a time. The step selector can remain the same. You'll simply add a "Keypress" step for each digit.

Keypress Stripe checkout steps

Please keep in mind that there are multiple versions of Stripe Checkout and it is continually being updated. If you've attempted the approach above and you are seeing different selectors or having trouble getting your test to pass properly, please feel free to reach out to support.


A/B Testing

Dealing with A/B testing can be a little tricky since Ghost Inspector can be sent down different routes which may prevent the test steps from working as expected. However, we do have some options to work around it.

If you're able to control the A/B test's variations with some kind of parameters (like a GET parameter in the start URL or a custom HTTP header which can be set in your test's settings), you could then just duplicate the test for each variation and select them explicitly.

If you're doing the A/B testing by loading a JavaScript file, you can use a network filter to simply block the script from loading. For example, if you're using something like Optimizely, you can typically just add the string "optimizely" to the network filter. You can get as specific as you want with the matching. This will prevent the script from loading in the browser session, and thus the A/B switching will not happen. This approach is nice and easy, though it may limit you to a single (default) variation in the test.


Date Pickers

Date picker widgets often present both the challenge of dealing with a complex UI and the need to keep the selection current, so that it doesn't become "stale" as time progresses. Selecting tomorrow's date for a hotel booking today may be acceptable, but could result in an error 2 days from now when that date has passed. Unfortunately Ghost Inspector's test recorder isn't able to determine intentions while recording, so it will typically generate a selector which matches the exact date you chose. This will need to be adjusted in the test editor after the test is recorded.

In many cases, selecting the next available date is acceptable for testing purposes. Fortunately, most date picker widgets include classes that make it fairly easy to target the next available day with a selector like .datepicker td.day.available. It's worth investigating the DOM around your date picker widget to see if a simple, durable selector can be created to always target the next available day.


Select2 Menus

Ghost Inspector supports interacting with Select2 menus, but your steps may need a bit of tweaking in the editor after being recorded. Select2 hides your HTML select element and replaces it with a rendered version using regular HTML elements. Select2 will often use dynamic ID attributes — meaning that it will assign an ID attribute that changes on each page load. When this happens, the Ghost Inspector test runs can't find the selection you've recorded because the associated element is constantly changing. There are two different approaches that can be used for interacting with Select2 menus.

Making Selections with a Click Step

In order to click on the proper menu selection, we'll need to make sure the step selector being used is sustainable and is not using a dynamic ID (which may have been captured by the test recorder). We'll use an Xpath selector to do this because it has the ability to target an element using it's text contents. The click step's target should look something like this (where "Option Label" is the label of the option that you want to select):

//*[contains(@class, "select2-container--open")]//li[@role="treeitem"][contains(text(), "Option Label")]

That selector is essentially saying, within the open Select2 menu, find the menu item labeled "Option Label".

Making Selections using Select2's JavaScript API

We can trigger changes on our Select2 dropdown using the Select2 programmatic API. The Select2 API is identical to the jQuery API for changing a select element, so given this select element:

<select id="my-select-box">
  <option value="val1">Value 1</option>
  <option value="val2">Value 2</option>
</select>

We can use an Execute JavaScript step to change our Select2 selection:

$("#my-select-box").val("val2").trigger("change")

This code assumes that jQuery is present on the page (which should be the case when using Select2). If jQuery is not present, you can add the library dynamically. Check out the Select2 API docs for more details.


iFrame & Frame Support

Ghost Inspector supports both iframes and traditional frames, but you must use iframe in the selector for the step target. For instance, consider a DOM that looks like this:

<div class="abc">
    <iframe name="xyz">
        <button class="btn">Click me</button>
    </iframe>
</div>
‚Äč

You cannot target the button with simply .abc .btn. You need to target it with something like iframe[name="xyz"] .btn or even just iframe .btn. The iframe element must be targeted specifically in the selector with iframe to tip off the system. The same applies to traditional frame elements.

The test recorder should do this automatically, though it may occasionally need to be tweaked afterwards.


Popup Window Support

Popup windows are supported and you're able to record directly inside them with the test recorder. When running tests, we don't have a specific syntax for targeting popups. Instead, our system will first check the main window for the element you've specified. If it doesn't find the element, it'll begin cycling through any open popups looking for the element there.

This means that if you're targeting an element in a popup, you need to make sure the selector used in the step doesn't accidentally match an element inside of the main window or another popup. It needs to be unique enough to ensure that only a match within the popup exists. In some cases you may need to tweak the CSS selector generated by the test recorder and make it a bit more specific to avoid collision.

If a popup window is created during your test, Ghost Inspector will not show it in the video until you interact with an element in that window (as outlined above). It will not automatically show up in the video simply by being present. Ghost Inspector always shifts focus back to the main window between each step, so your test will need to explicitly target an element that exists only in the popup window in order to see it in the video.


Injecting and Using jQuery

jQuery is a useful JavaScript library which can help you carry out actions on a web page. We do not inject jQuery on the page for you. However, you can access it within JavaScript steps if it's already present, or you can inject it yourself.

If jQuery is already present on the page you're interacting with, you can typically access it using the standard $() function. In some cases, jQuery is only available through it's proper function name: jQuery() instead of $().

If you would like to use jQuery and it's not present on the page, you can load it yourself with an Execute JavaScript step and this code (which adds jQuery v2.2.4 to the page):

var resource = document.createElement('script');
resource.src = "https://code.jquery.com/jquery-2.2.4.min.js";
var script = document.getElementsByTagName('script')[0];
script.parentNode.insertBefore(resource, script);

We recommend adding a 5 second (5000ms) "Pause" step afterwards to ensure that the library has time to download. Once complete, you can then use the injected jQuery with window.$() in future JavaScript steps on that page. Note that if you change pages during the test you will need to inject jQuery again.


Google Analytics

Google Analytics is a common on-page analytics system used by many websites. In some cases, you may want to check to ensure that Google Analytics is setup properly. In other cases, you may wish to exclude Ghost Inspector's traffic to ensure that it doesn't affect your analytics.

Check for Google Analytics on a Page

It's relatively easy to check for Google Analytics with a JavaScript returns true assertion that checks for it in the global window object using code like this:

return (typeof window.ga === "function")
That assertion will pass if Google Analytics is setup and fail if it isn't. We recommend adding a 5 second (5000ms) "Pause" step before performing this check, since Google Analytics is typically loaded asynchronously.

Exclude Ghost Inspector Traffic from Google Analytics

We provide the IP addresses that our service uses to test your website, which you can exclude from your Google analytics data. Assuming that you're just using our "Northern Virginia, USA" region (which is the default), you'll just need to exclude the 4 IP addresses that we list at the top of the page. If you're using other geolocations, you'll need to exclude those IPs as well.


CAPTCHAs

A CAPTCHA is a program or system intended to distinguish human from machine input, typically as a way of thwarting spam and automated extraction of data from websites. CAPTCHAs are a bit tough to deal with during automated testing since they're specifically designed to prevent bots and automation from getting through — including something like Ghost Inspector. They cannot be solved in an automated way, so they need to be worked around or disabled during testing. Here are some options for dealing with CAPTCHAs:


SMS OTP

One-time passwords (OTP) are sometimes sent to a phone number using SMS (text messages) in situations like two-factor authentication. If you need to access an OTP that is sent to a phone number during a Ghost Inspector test, you can do so with the help of Twilio. Twilio provides APIs for sending and receiving SMS messages (among other things). A phone number can be setup using Twilio to receive the SMS, then we can use their API to access the message inside of a JavaScript step during the Ghost Inspector test.

In order for this to work, you'll need the ability to send the SMS messages to a Twilio phone number that you control. Note that setting up a phone number with Twilio and receiving messages may incur changes from Twilio.

Once you have the required Twilio phone number and credentials, you can use an asynchronous "Extract from JavaScript" to access the Twilio API, fetch the most recent message that was sent to the phone number, then parse out and return the OTP (or whatever you may need). The JavaScript code below can be used for this "Extract from JavaScript" step. You'll need to swap in your Twilio phone number, account ID and account key. You'll also need to modify the const code = body.replace('Your code is: ', '') line to fit your message and parse out the value as needed.

return new Promise(function (resolve, reject) {
  // Specify your Twilio phone number (without the + in front)
  const phoneNumber = '15555555555'
  // Specify your Twilio account number (on your dashboard)
  const acctId = 'xxxxxxxxxxxxxxxxxxxxxxxx'
  // Specify your the SID of your Twilio API key
  const sid = 'xxxxxxxxxxxxxxxxxxxxxxxx'
  // Specify your the secret of your Twilio API key
  const secret = 'xxxxxxxxxxxxxxxxxxxxxxxx'
  // Fetch most recent message to the phone number
  window.fetch(`https://api.twilio.com/2010-04-01/Accounts/${acctId}/Messages.json?To=%2B${phoneNumber}&PageSize=1`, {
    method: 'GET',
    headers: {
      'Authorization': 'Basic ' + window.btoa(`${sid}:${secret}`)
    }
  }).then(function (response) {
    return response.json()
  }).then(function (data) {
    try {
      // Fetch body of message
      const body = data.messages[0].body
      let code = body
      // Perform custom parsing on the body of the message and resolve
      code = code.replace('Your code is: ', '')
      resolve(code)
    } catch (err) {
      reject(err)
    }
  })
})

Keep in mind that this step needs to come after the SMS message is sent during the test steps. It's recommended that you add a 30 second "Pause" step before checking for the message to ensure time for deliverly. Lastly, it's strongly recommended that you create a separate Twilio API for this operation with limited access for Ghost Inspector.

Steps for extracting an OTP from an SMS to a Twilio phone number


Embedded Editors

Embedded editors like CKEditor often make use of contenteditable elements, which are challenging for Ghost Inspector to interact with directly. Simple "Assign" steps cannot be used. Fortunately, CKEditor (and most other editors) provide a JavaScript API for interacting. This means you can add an Execute JavaScript step via our test editor and interact with the editor using JavaScript.

CKEditor

CKEDITOR.instances["instance-name-here"].setData("This is sample text.");

Draft.js

When interacting with Draft.js, you can use a normal "Assign" step and set the CSS target to .public-DraftEditor-content.

Kendo UI Editor

$("#editor").data("kendoEditor").value("This is sample text.");

TinyMCE

tinyMCE.activeEditor.setContent("This is sample text.");

Note: These examples generally let most users accomplish what they need to accomplish — though you'll need to experiment with it. We recommend keeping interactions inside of embedded editors to minimum to avoid complexity.


Scrolling a page within a test

Some websites use lazy loading techniques to trigger events and reveal elements as the user scrolls down the page. By default, our browsers do not manually scroll down and trigger these events. However, if necessary, that effect can be achieved through the combination of JavaScript steps and a Pause step.

First, add a new step and set the operation to “Execute JavaScript”. Add this code to your step:

var body = document.documentElement || document.body;
body.scrollTop = 0;
window.scroller = setInterval(function(){
  body.scrollTop += 500;
}, 500);

The code above scrolls the page by 500 pixels every 500 milliseconds (a total of 1000 pixels per second).

Next, add a “Pause” step so that the Javascript code has time to scroll all the way down the page. Pause steps use milliseconds, and since the ratio of pixels to milliseconds is 1:1, we can simply set the pause value to the height of our page in pixels. If our page is 10000px, set the pause value to 10000.

Lastly, we'll need to add another “Execute JavaScript” step to cancel the scrolling loop and scroll back to the top of the page. Add this code to your second JavaScript step:

clearInterval(window.scroller);
var body = document.documentElement || document.body;
body.scrollTop = 0;

Once complete, your steps should look like the screenshot below and scroll all the way down your page — triggering any events along the way.

Scroll steps in test editor
Note: Scrolling will not be captured in the test video due to the way we capture video frames. However, the scrolling is taking place.


Ensure that an image has loaded properly

You can check to see if an image has loaded during a test by checking the "naturalWidth" field of the image element. If this field is equal to 0, then the image has not loaded. A non-zero value means that the image has loaded. This means that you can use a JavaScript returns true assertion to check whether an image has loaded with code like this:

return (document.querySelector('.image-selector').naturalWidth !== 0);

(Where ".image-selector" is the selector for the image element.)

This assertion will pass if the image loads and fail if it does not.