line-graph-dribbbble

Selenium WebDriver – How To Automate Charts And Graphs Validation

Overview:

Automated validation of Charts & Graphs is one of the biggest challenges in test automation. In our application, We have tons of charts. I would show you how I have automated that to give you some idea.

Ocular:

I would be using Ocular – the image validation library! In fact, I created this Ocular lib just for this purpose!

Sample Application:

In order to explain things better, I am going to create 2 simple HTML files as shown below (I took the HTML from this site) & each HTML file contains 3 charts.

chart-base-2-html

Basically here we are going to assume that we would expect the right side charts to be exactly like the ones on the left side. Right side charts are almost same – except the January data of the Income chart.

Our expectation here is – as part of our automated testing, this difference should be reported and the test should fail!

The HTML source looks like this.

chart-source

 

Now It is time for us to design the Page Object for the above HTML file.

Page Object:

public class SampleChartPage {

    private WebDriver driver;
    private Map<String, String> map;

    @FindBy(id = "buyers")
    private WebElement buyersChart;

    @FindBy(id = "countries")
    private WebElement countriesChart;

    @FindBy(id = "income")
    private WebElement incomeChart;

    public SampleChartPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);

        // Page object should contain the location of the baseline images
        // these images no need to be present
        // Ocular will create these images if they are not found
        map = new HashMap<String, String>();
        map.put("buyers", "buyers.png");
        map.put("countries", "countries.png");
        map.put("income", "income.png");
    }

    public boolean verifyBuyersChart() {
        return this.verifyChart(map.get("buyers"), buyersChart);
    }

    public boolean verifyCountriesChart() {
        return this.verifyChart(map.get("countries"), countriesChart);
    }

    public boolean verifyIncomeChart() {
        return this.verifyChart(map.get("income"), incomeChart);
    }

    // common method to compare the baseline image against actual whole page / specific element
    private boolean verifyChart(String fileName, WebElement element) {

        Path path = Paths.get(fileName);

        OcularResult result = Ocular.snapshot()
                                    .from(path)
                                    .sample()
                                    .using(driver)
                                    .element(element)
                                    .compare();

        return result.isEqualsImages();
    }

}

I assume above page object is self-explanatory. I create folders like this in the project.

  • snap folder should contain all the baseline images
  • result will contain the comparison result

ocular-base-location

Initially these folders can be empty.  Because we would not have the images of those 3 charts web elements.  [Ocular will create these images under the snap folder during the first run].

Now it is time for us to create the Test.

 

TestNG Test:

In my testNG test for this sample application, I have 3 tests.

  • baseline_test – aim of this test to produce the baseline images first – when you run the test for the first time, Ocular creates the baseline images. So that, you can use it for any future validation. This test will always PASS.
  • visual_test_without_any_change – here, basically I am going to call the same HTML file. So Ocular will compare the charts against the baselines created as part of the previous test (baseline_test). This test will PASS because since the same HTML is launched with same data, charts would be as expected.
  • visual_test_after_change – in this test, I would launch another HTML where the income chart data is slightly changed.  So Ocular will validate and report the differences.

Once I run the baseline_test, snap folder will contain all the images we need!

ocular-snap-location

 

public class OcularDemo {

    private WebDriver driver;
    private SampleChartPage page;

    @BeforeSuite
    public void ocularConfig() {

        // update ocular config
        // set the base location of the baseline images - this folder should be present
        // set the base location of the result after comparison - this folder should be present
        Ocular.config()
               .snapshotPath(Paths.get(".", "src/test/resources/snap"))
               .resultPath(Paths.get(".", "src/test/resources/result"));
        
    }

    @BeforeMethod
    public void beforeMethod() {
        driver = new ChromeDriver();
    }

    @AfterMethod
    public void afterMethod() {
        driver.quit();
    }

    // during this test, snap folder is empty. ocular does not find any baseline images. 
    // so, ocular creates the baseline images and comparison result will be always TRUE.
    @Test
    public void baselineTest() throws InterruptedException {
        driver.get("file:///" + Paths.get("chart-js.html").toAbsolutePath());

        page = new SampleChartPage(driver);

        Assert.assertTrue(page.verifyBuyersChart());
        Assert.assertTrue(page.verifyCountriesChart());
        Assert.assertTrue(page.verifyIncomeChart());
    }

    // during this test, snap folder contains the baseline images.
    // so, ocular compares the actual webelement against the given image & returns the result
    @Test(dependsOnMethods = "baselineTest")
    public void visaul_test_without_any_change() throws InterruptedException {
        driver.get("file:///" + Paths.get("chart-js.html").toAbsolutePath());

        page = new SampleChartPage(driver);

        Assert.assertTrue(page.verifyBuyersChart());
        Assert.assertTrue(page.verifyCountriesChart());
        Assert.assertTrue(page.verifyIncomeChart());
    }

    // snap folder already contains the baseline images.
    // so, ocular compares the actual webelement against the given image & returns the result
    // income chart data is changed - so it will fail
    @Test(dependsOnMethods = "visaul_test_without_any_change")
    public void visaul_test_after_change() throws InterruptedException {
        driver.get("file:///" + Paths.get("chart-js-changed.html").toAbsolutePath());

        page = new SampleChartPage(driver);

        Assert.assertTrue(page.verifyBuyersChart());
        Assert.assertTrue(page.verifyCountriesChart());
        Assert.assertTrue(page.verifyIncomeChart());  // this will fail - because data is changed
    }
}

Executing the above test produced below result.

chart-result-2

For the failed test, difference was highlighted as shown here!!
chart-result-1

Summary:

Most of the automation suites compares the charts by reading the chart data and compare if the data is as expected assuming actual validation of the chart is difficult. But if we see the above example, Verifying the charts is no longer a big challenge with Ocular! If we pass the baseline image location and element, Ocular compares and highlights the differences easily!

Hope the above example was easy for you to understand this better. Ocular can do a lot more than this!! So, Please check that out and leave a comment / suggestion.

 

Happy Testing & Subscribe 🙂

 

Share This:

Categories: Articles, Extend WebDriver, Framework, Ocular, Selenium

1 comment

  • Shakti

    Hi ,
    Thanks for sharing your knowledge, i have been following your blog for very long and always find it very useful .
    I just wanted to seek some information , can you share on this topic – how we can validate the UI /WebElement with respect with truncation , overlap etc kind of bug detection logic in it in our script .

    PS: I am sorry i am using this post for commenting.