Automated Testing Charts in Canvas in Selenium WebDriver

In a previous article, I showed you how to test charts in an SVG format. Charts (and other diagrams) can also be embedded in a Canvas on a web page.

Test Site

In this tutorial I will use the demo bar chart on ChartJS’ website (link: https://www.chartjs.org/docs/latest/samples/bar/vertical.html).

Test Design

  1. Verify the chart is present by checking the canvas tag
  2. Extract the Canvas & Save the chart to a file
  3. Verify the image file

Test Steps

1. Verify the chart exists

Right-click the chart to inspect, thecanvas tag is highlighted.

HTML Source:

// ...
<div class="chart-view">
<canvas width="1175" height="586">
</canvas>
</div>
// ...

Verifying the existence of the canvas tag is good enough for now (we will do further verification later).

canvas_elem = driver.find_element(:xpath, "//div/canvas")
# if it does not exist, the above will throw error

Rendering charts (by JavaScript) takes a short time, so add a minor wait. The complete test statements look like below.

driver.get("https://www.chartjs.org/docs/latest/samples/bar/vertical.html")
sleep 1 # wait for the canvas to load
canvas_elem = driver.find_element(:xpath, "//div/canvas")

However, we can not be sure that the chart is actually displayed correctly. The solution: save the chart as a PNG.

2. Extract the Canvas & Save the chart to a file

There is no content under the canvas tag, that’s just how Canvas’ are. We can extract a canvas’s content (image) using JavaScript’s toDataURL , then decode it (Base64 format) to get the image binary data.

canvas_elem = driver.find_element(:xpath, "//div/canvas")# extract canvas element's contents
js = "return arguments[0].toDataURL('image/png').substring(21);"
canvas_base64 = driver.execute_script(js, canvas_elem)
# decode from the base64 format, get the image binary data
canvas_png = Base64.decode64(canvas_base64)

Now save it to a PNG file.

dest_file = File.join(File.dirname(__FILE__), "..", "tmp", "saved_canvas.png")
fio = File.open(dest_file, "wb") # b indicates binary file
fio.write(canvas_png)
fio.flush
fio.close
expect(File.exists?(dest_file)).to be_truthy

3. Verify the image file

We can use a PNG image library, e.g. FastImage gem to verify whether it is a valid PNG image or not.

require('fastimage')
puts FastImage.type(dest_image_file_path) # => "png"
puts FastImage.size(dest_image_file_path) # => [1760, 880]

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([1760, 880])

Complete Code

it "Save a canvas to a PNG image" do
driver.get("https://www.chartjs.org/docs/latest/samples/bar/vertical.html")
sleep 1 # wait canvas is loaded
canvas_elem = driver.find_element(:xpath, "//div/canvas")
js_extract_canvas = "return arguments[0].toDataURL('image/png').substring(21);"
canvas_base64 = driver.execute_script(js_extract_canvas, canvas_elem)
canvas_png = Base64.decode64(canvas_base64)
dest_file = File.join(File.dirname(__FILE__), "..", "tmp", "saved_canvas.png")
fio = File.open(dest_file, "wb") # b indicates binary file
fio.write(canvas_png)
fio.flush
fio.close
expect(File.exists?(dest_file)).to be_truthy
img_dim = IO.read(dest_file)[0x10..0x18].unpack("NN")
expect(img_dim).to eq([1760, 880])
end

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Unit testing with mocha, Chai and Istanbul

The CSS position property is used to set the position for an element.

JavaScript Array Methods (EVERY & SOME)

Ascending Functional Reactive Programming 7/7

How to Configure React with Typescript, Redux, and Redux-observables

Empty string comparison in JavaScript

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Courtney Zhan

Courtney Zhan

More from Medium

S2E5 — Test Automation with WebdriverIO + Node.js

How to switch from one app to other App in Appium [Android]

How to use Playwright Fixtures to improve your testing code

Selenium or Tosca? Which QA Tool is Right For You