Web Driver SamplerIntroductionUnlike most Samplers, the Web Driver Sampler provides the reader with an empty editor field, much like a blank canvas. Do not be dismayed, as with great responsibility comes great power! This wiki will document what each of these fields does, and will also detail some of the common use cases that the scripter may have. If the reader has not yet done so, it is highly recommended that they quickly go over the 2 minute tutorial before continuing on with this section. General conceptsWhen a new Web Driver Sampler is added, the user interface will resemble something as follows: The main fields that the scripter can make use of are:
Within the Script section, the Sampler automatically injects a WebDriverScriptable object with the name of WDS. This object has the following properties for the scripter to use:
<code> vars.get("VAR1"); vars.put("VAR2","value"); vars.remove("VAR3"); vars.putObject("OBJ1",new Object()); </code>
<code> props.get("START.HMS"); props.put("PROP1","1234"); </code>
Reader's responsibilityAs mentioned previously, this sampler provides the scripter with a lot of control. This means that unlike most samplers, the scripter is responsible for performing several tasks within the Script panel:
The following is a very simple sampler that captures all responsibilities mentioned above. // 1a. Start capturing the sampler timing WDS.sampleResult.sampleStart() // 2. Perform the Sampler task WDS.browser.get('http://google.com.au') // 1b. Stop the sampler timing WDS.sampleResult.sampleEnd() // 3. Verify the results if(WDS.browser.getTitle() != 'Google') { WDS.sampleResult.setSuccessful(false) WDS.sampleResult.setResponseMessage('Expected title to be Google') } There is a way to create sub-samples within main sample. To enable that, you need to set JMeter property: webdriver.sampleresult_class=com.googlecode.jmeter.plugins.webdriver.sampler.SampleResultWithSubs Then use `WDS.sampleResult.subSampleStart(String label)` and `WDS.sampleResult.subSampleEnd(boolean successful)` to create intermediary measurements in the middle of the process (available only when not overridden by property). Script fieldAs mentioned above, the *WDS* object is automatically available to the scripter to use. However, since JMeter is running on a JVM, the scripter has access to any class loaded in the environment. The following is an example of creating a java Date object: var d = new java.util.Date() Notice that the variables are declared with the full package and class name. The Rhino environment allows the scripter to provide shortcuts to some frequently used packages and classes. This is well documented on the Rhino website, and the following illustrates an example where a package is represented by a javascript variable: var support_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait) var wait = new support_ui.WebDriverWait(WDS.browser, 5000) LoggingThis is useful for the scripter especially when they are attempting to debug their scripts. To see the `jmeter.log` file, refer to the jmeter docs, and the scripter can easily append to this by following the instructions below: WDS.log.info(WDS.name + ' has logged an entry'); The `WDS.log` object is just a reference to the `Apache Logger` instance, and although all public methods are available on this object, it is recommended the scripter restrict the logging to the following methods:
Parameters and argsWhenever strings are specified in the `Parameters` field, they are automatically split by the space character and made available as an `args` array. Furthermore, the args string is trimmed to minimise scripting errors. It is also possible to pass in JMeter variables to the Script context. The table below should illustrate this:
Declaring JMeter variables is outside the scope of this document. Rather the scripter should refer to the comprehensive documentation on the JMeter website. BrowserThere are already a number of simple example usages for the `WDS.browser` object. This section will now detail some of the more advanced usages of scripting the `WDS.browser` instance. Form submissionThe getting started section has already covered the use case of navigating to a URL. We will now turn our attention to form submission. The script below illustrates the following sequence of events:
// 1. Go to a page with a form WDS.browser.get('http://mobile.yellow.com.au') // 2. Enter characters into the text input field var pkg = JavaImporter(org.openqa.selenium) var what = WDS.browser.findElement(pkg.By.id('what')) what.sendKeys(['tyres']) var where = WDS.browser.findElement(pkg.By.id('where')) where.sendKeys(['melbourne vic']) // 3. Click on the button to submit the form var button = WDS.browser.findElement(pkg.By.cssSelector('button.button-search')) button.click() // 4. Verify successful form submission var results = WDS.browser.findElements(pkg.By.cssSelector('ul.search-results-list li')) if(results.empty) { WDS.sampleResult.successful = false WDS.sampleResult.responseMessage = 'There were no results returned' } The first step of loading a URL has already been covered. The second step is where we expand on the idea of importing all classes from a package and assign it to the `pkg` variable. All classes from the `org.openqa.selenium` packages are now available within the context of this script, and the script above makes use of the By class to access the HTML form fields by their ids. The first text field is assigned to the `what` variable, and this is just a standard WebElement. We then make use of the `sendKeys` functionality to send a string of characters to this field. We then do the same to the `where` field and send another string of characters to the other field. The astute scripter would have picked up the fact that the string is enclosed within an array. This is on purpose as the Javadoc for the sendKeys method is of type `varargs` which essentially compiles down to an array of strings. For this script to work in Java 6, the scripter must use an array for varargs parameters. However if the scripter is using Java 7, they can omit the array and just use a string. For maximum compatibility, the above script defaults to Java 6 syntax. The third step introduces another method on the `By` class to allow the scripter to find elements by CSS selectors, and after locating this button, the script will now click on it. Finally, the scripter is responsible for asserting the script completed its actions successfully. This is where we introduce the findElements method which will return a `List` of `WebElements` instead of a single one. This allows the scripter to verify that the list is not empty and that they did indeed land on the search results page. One thing is missing from the example above, and it is an important one. The timing. The following script enhances the one previously by adding the timing to the relevant sections: ... // 3. Click on the button to submit the form var button = WDS.browser.findElement(pkg.By.cssSelector('button.button-search')) WDS.sampleResult.sampleStart() button.click() // 4. Verify successful form submission var results = WDS.browser.findElements(pkg.By.cssSelector('ul.search-results-list li')) WDS.sampleResult.sampleEnd() ... What is important to note is the locations where the timing begins and ends. `sampleStart()` was called before the click - this is obvious. However the corresponding `sampleEnd()` was not called until after the verification of the content on the page. By ensuring that the page has now loaded (ie. by verifying its content) we can now safely assume that the page is loaded and we can now end our timing. Note: The example above is suitable for a site which generates HTML on the serverside, however for client-side templates, the check for completion could be very different. The next section (AJAX) introduces some more advanced techniques for interrogating the content and status of the page.AJAXTesting for AJAX content is one of the more complex parts, and if not scripted properly, it may be quite brittle as well. The following script will automate the following steps:
// 1. Go to a page with a form WDS.browser.get('http://mobile.yellow.com.au') // 2. Variables used for interacting with AJAX content var pkg = JavaImporter(org.openqa.selenium, org.openqa.selenium.support.ui) var what = WDS.browser.findElement(pkg.By.id('what')) var wait = new pkg.WebDriverWait(WDS.browser, 10) // 3. Enter characters and wait for the AJAX content to display - timing out at 10 seconds what.sendKeys(['ty']) WDS.sampleResult.sampleStart() wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('ul.suggestions'))) WDS.sampleResult.sampleEnd() // 4. Verify successful form submission var results = WDS.browser.findElements(pkg.By.cssSelector('ul.suggestions li')) if(results.empty) { WDS.sampleResult.successful = false WDS.sampleResult.responseMessage = 'There were no suggestions' } The script above is quite similar to the Form submission example, but there are a few new concepts that should be covered. The first thing to note, is that the JavaImporter allows multiple packages to be imported and aliased to a single javascript variable. This allows the ExpectedConditions class and WebDriverWait class to be declared. These classes are used to wait for AJAX content to appear. When Declaring the WebDriverWait, the second parameter is the maximum amount of time in seconds to wait for the AJAX content to appear. If nothing appears the default behaviour of this class is to throw a NoSuchElementException, which can be suppressed if desired. After all the required variables are declared, we will now enter some text into the input field and wait for the AJAX content to display. This is where we will now wait (up to 10 seconds) for the HTML list to appear. It is also important to note that we include the requisite calls to WDS.sampleResult.sampleStart() and WDS.sampleResult.sampleEnd() to track the timing. Finally we ensure that the list returned via. AJAX contains content. Failing otherwise. For more details on AJAX and Selenium WebDriver, it would be useful for the scripter to refer to the Selenium Advanced Usage page. Resource FootprintBecause of running real browser, WebDriver tests require a lot of resources. In general case, you need 1 CPU core per virtual user with it. This makes difficult to scale WebDriver test to have hundreds and thousands of vurtual users. However, the load testing cloud providers may help to scale WebDriver test up to thousands of real browsers, look at BlazeMeter for example. |
On this page:
|