Automated Testing Charts in Selenium WebDriver
How to verify your chart generation using Selenium WebDriver
This article is also included in the “How to in Selenium WebDriver” series.
Charting, such as HighCharts, is commonly seen on modern web apps. These charts packages usually generate charts in an SVG (Scalable Vector Graphics) format.
We probably want to test charts to see if they are being displayed correctly — but how can we do that with automation?
Test Design
Verify the chart is present by checking the
svg
tagSave the chart to a file
Verify the image file
Visually inspect the image file on the Continuous Testing (CT) server
1. Verify the chart exists
To verify that the chart exists, we need to check whether the div
(or figure
) that you used to trigger the chart contains the chart. In HighCharts, you must create a div
, and give it an id and then HighCharts will render the chart there for you. Here are the first few lines of the JavaScript I used to generate a chart in chart-container-9
.
Highcharts.chart('chart-container-9', {
chart: {
type: 'column',
},
// other chart settings...
});
If we view the page source, you will notice that the chart is not there. There is nothing under chart-container-9
.
JavaScript renders the chart afterwards, so it doesn’t show up in the Page Source. Once rendered properly, it will show on Inspect Element.
However, using Inspect Element, we can see that the chart container (in my case, chart-container-9
, which is the top-most chart) has an SVG.
To accommodate this in our test, we will:
Wait for the JS to render
Then verify that the
svg
tag exists
visit("/servers/1")
sleep 2 # wait JS rendering
elem = driver.find_element(:id, "chart-container-9")
elem_html = driver.execute_script("return arguments[0].outerHTML;", elem)
expect(elem_html).to include("<svg")
If you run this test, it will pass! Great, but it only checks that some svg
was rendered — did your chart display correctly?
So how can we verify your chart was displayed with an end to end test?
2. Saving your chart as an image
The solution: save the svg
as a PNG image.
Before doing this, decide the file destination (where you will save the image). Before checking the image file, make sure the image does not already exist.
Also, I recommend using a relative path to save the image so that the test will run on any machine.
tmp_dir = File.expand_path File.join(File.dirname(__FILE__), "..", "tmp")
dest_image_file_path = File.join(tmp_dir, "chart.png")
FileUtils.rm dest_image_file_path if File.exists?(dest_image_file_path)
# save the chart image, selenium 4 new feature
elem.save_screenshot(dest_image_file_path)
expect(File.exists?(dest_image_file_path)).to be true
By the way, saving a specific web element to an image is a Selenium 4 feature.
3. Verify the image file
Furthermore, we can verify whether what we saved is a valid image or not.
If we can open the image, it is valid, and then you can perform checks on the image (PNG), such as the dimensions, using the FastImage gem.
require('fastimage')
puts FastImage.type(dest_image_file_path) # => "png"
puts FastImage.size(dest_image_file_path) # => [300, 60]
Alternatively, we can extract the dimensions directly from a PNG file.
img_dim = IO.read(dest_image_file_path)[0x10..0x18].unpack('NN')
expect(img_dim).to eq([300, 60])
4. Visually inspect the image file on the Continuous Testing (CT) server
Apart from the automated test’s purposes, we may want to make the saved image file available to all team members. This can be beneficial if you manually want to verify the chart contents or other team members also want to look at the chart.
Automated Tests have little value unless you run them frequently in a continuous server. We can set this up with a BuildWise CT Server.
In BuildWise, you may specify specific files or directories to archive under the project settings.
After triggering a build, you can click the dropdown for “Build artifacts”, then you can see the chart image listed there.
Once you click on it, you can view the chart — straight from the CT server!
Complete Code below
load File.dirname(__FILE__) + '/../test_helper.rb'
describe "Sequential Test - Project Chart" do
include TestHelper
before(:all) do
@driver = Selenium::WebDriver.for(browser_type, browser_options)
driver.manage().window().resize_to(1280, 720)
driver.get(site_url)
relogin("pro")
end
after(:all) do
driver.quit unless debugging?
end
it "Chart exists on server project page" do
visit("/servers/1")
sleep 2 # wait JS rendering
elem = driver.find_element(:id, "chart-container-9")
elem_html = driver.execute_script("return arguments[0].outerHTML;", elem)
expect(elem_html).to include("<svg")
# save chart image, make sure no existing files first, relative path
tmp_dir = File.expand_path File.join(File.dirname(__FILE__), "..", "tmp")
dest_image_file_path = File.join(tmp_dir, "chart.png")
FileUtils.rm dest_image_file_path if File.exists?(dest_image_file_path)
# save the chart image, selenium 4 new feature
elem.save_screenshot(dest_image_file_path)
expect(File.exists?(dest_image_file_path)).to be true
img_dimension = IO.read(dest_image_file_path)[0x10..0x18].unpack('NN')
puts img_dimension.inspect
expect(img_dimension).to eq([300, 60])
end
end
Related reading