Layout Testing with Galen Framework

Galen is a layout testing framework developed by Ivan Shubin. It is an open-source project that you can support (https://github.com/galenframework/galen ).

  • It is an automated layout and responsive testing framework.
  • Tests locations of objects relatively to each other on the page.
  • Runs in Selenium Grid. (SauceLabs & BrowserStack)
    You can test responsive websites on different mobile devices.
  • Supports Parallel Testing
    Thus, tests run faster and we save time.
  • Responsive Design Tests are easy with Galen.
    Opens -> Resizes -> Tests with given specifications.
  • Galen has an own DSL which specifies the constraints about the layout design.

Programming Language Support?

  • Basic Syntax
  • JavaScript Tests
  • Java & Selenium Webdriver

Galen Reporting

  • Error Reporting
    Generates Html reports where you can see all your test objects.
  • ScreenShots
    Highlights the misaligned elements.
  • Image Comparison
    Compares images and shows differences

Galen Example with JAVA & Webdriver

Note: You can find source code of the sample project at below page:
https://github.com/swtestacademy/galenswtestacademy

Step-1: Add Galen Maven Dependency to the pom.xml

<dependencies>
    <dependency>
        <groupId>com.galenframework</groupId>
        <artifactId>galen-java-support</artifactId>
        <version>2.0.3</version>
    </dependency>
</dependencies>

Step-2: Create a Selenium Maven Test Project

Create an empty test class as shown below:

Resize the browser for 1200×800 resolution and go to swtestacademy.com:

import com.galenframework.api.Galen;
import com.galenframework.reports.GalenTestInfo;
import com.galenframework.reports.HtmlReportBuilder;
import com.galenframework.reports.model.LayoutReport;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by can on 29/01/17.
 */
public class GalenExampleTest
{
    private WebDriver driver;

    @Before
    public void setUp()
    {
        //Create a Chrome Driver
        driver = new ChromeDriver();
        //Set the browser size for desktop
        driver.manage().window().setSize(new Dimension(1200, 800));
        //Go to swtestacademy.com
        driver.get("http://www.swtestacademy.com/");
    }


    @After
    public void tearDown()
    {
        driver.quit();
    }

}

In order to check the layout, we need to use LayoutReport class and instantiate a layoutReport object and assign it to Galen.checkout(param1, param2, param3). Here Galen.checkout function has three parameters:

param1 = webdriver instance (it is our driver object)

param2 = .gspec file

param3 = it is a tag for a specific layout

LayoutReport layoutReport = Galen.checkLayout(driver, "specs/homepage.gspec", Arrays.asList("desktop”));

Above code will generate an HTML report based on homepage.gspec file. You can find this report under tartget/ directory and test code should be like that:

@Test
    public void homePageLayoutTest() throws IOException
    {
        //Create a layoutReport object
        //checkLayout function checks the layout and returns a LayoutReport object
        LayoutReport layoutReport = Galen.checkLayout(driver, "specs/homepage.gspec", Arrays.asList("desktop"));

        //Create a tests list
        List<GalenTestInfo> tests = new LinkedList<GalenTestInfo>();

        //Create a GalenTestInfo object
        GalenTestInfo test = GalenTestInfo.fromString("homepage layout");

        //Get layoutReport and assign to test object
        test.getReport().layout(layoutReport, "check homepage layout");

        //Add test object to the tests list
        tests.add(test);

        //Create a htmlReportBuilder object
        HtmlReportBuilder htmlReportBuilder = new HtmlReportBuilder();

        //Create a report under /target folder based on tests list
        htmlReportBuilder.build(tests, "target");

        //If layoutReport has errors Assert Fail
        if (layoutReport.errors() > 0)
        {
            Assert.fail("Layout test failed");
        }
    }

Now, you have to create a Galen Specification (.gspec) file under resources folder to describe your website’s layout and rules. If you want to do image comparison, you should also add baseline image under this folder. Under the “target” folder we will generate test reports.

Step-3: Write a Galen Spec File

This gspec (Galen Spec) fileis for swtestacademy.com’s home page and it consists of many controls and checks such as:

  • Alignment control
  • Image comparison
  • Below check
  • Above check
#Declaring objects with css and xpath locators
@objects
  header               css     div.fusion-secondary-header
  sw-logo              css     .fusion-logo-link
  #Navigation links are multi-line object type. Thus, we add * at the end of its decleration.
  navigation-links-*   xpath   //ul[@id='menu-main']/li[not((contains(@id,'mobile-menu-item')))]
  nav-menu             css     div.fusion-secondary-main-menu
  follow-us-box        xpath   //div[contains(@class,'fusion-alert')][1]

#Home Page Tag
= Home Page =
  #This is for Desktop
   @on desktop
       #Header properties
       header:
           inside screen 0px top
           inside screen 0px left
           inside screen 0px right

       #Logo properties
       sw-logo:
           #31 px below the header
           below header 31px
           #Image comparison with %2 precision ratio
           image file sw-logo.png, error %5
       
       #Each navigation links must be alligned horizontally to each other
       #itemName -> Current item and nextItem -> Next item
       @forEach [navigation-links-*] as itemName, next as nextItem
           ${itemName}:
               aligned horizontally all ${nextItem}

       #Navigation menu must be 20px above to the follow us allert box
       nav-menu:
           above follow-us-box 20px

@On Mening:

Quite often you need to declare different specs for different conditions (e.g. various devices like mobile, tablet, desktop etc.). You can specify tags in your spec file so that it is easier to manage your layout testing. You can wrap all your checks inside @on statement like this:

= Main section =
    @on mobile
        menu:
            height 300 px 

    @on desktop
        menu:
            height 40 px

In case your specs apply to all of the tags you can express that by using * symbol:

= Main section = 
    @on *
        menu:
            height 70px 

    @on mobile
        login-button:
            width 100px

You can also combine multiple tags using comma-separated tag notation

= Main section =
    @on mobile, desktop
        menu:
            height 300 px

Image Comparison:

As for image comparison – it is applied differently. Instead of comparing the complete page screenshot you can choose which specific element you would like to compare. And for each image comparison you can tune the algorithm with different settings (e.g. color tolerance, error rate etc.) and custom image filters (e.g. blur, saturation, quantinize, denoise). If you want to know more you can watch the video where it is  explained how to prepare individual image samples and configure the image comparison for elements with noise background.
Ref: https://www.youtube.com/watch?v=bheFQfEGR6U

Step-4: HTML Reporting

When you run the code,

1- If there is a image comparison error, it will highlight it as follows:

2- Also, when we click the “Showimage comparison” link, it shows the mismatches:

3- If there is a layout error, it will highlight it as shown below:

4- Also, we can see the elements heat-map as follows:

5- Successful HTML report will look like this:

Thanks.
-Can

10 thoughts on “Layout Testing with Galen Framework”

  1. Hi Nice article, I have one query
    I am running script parallel through testng.xml
    But HTML report is not generated for both browser which i have mentioned in xml

    Reply
    • I haven’t tried layout testing in parallel Stephen. Maybe Can Yıldırım has knowledge of this. It is better to put some breakpoints and debug your project. Maybe you will get some insights.

      Reply
  2. Hi, Thanks for creating such a nice article, I have just cloned the code into my PC and tried to execute the tests and finally ended up with error, following is the error details, could you help me in resolving the issue

    ReferenceError: “org” is not defined.
    (; line 1)
    at org.mozilla.javascript.NativeGlobal.constructError(NativeGlobal.java:597)
    at org.mozilla.javascript.NativeGlobal.constructError(NativeGlobal.java:557)
    at org.mozilla.javascript.ScriptRuntime.name(ScriptRuntime.java:1076)
    at org.mozilla.javascript.gen.c2.call(:1)
    at org.mozilla.javascript.gen.c2.exec()
    at org.mozilla.javascript.Context.evaluateReader(Context.java:820)
    at org.mozilla.javascript.Context.evaluateString(Context.java:784)
    at com.galenframework.javascript.GalenJsExecutor.importClasses(GalenJsExecutor.java:85)
    at com.galenframework.javascript.GalenJsExecutor.importAllMajorClasses(GalenJsExecutor.java:62)
    at com.galenframework.javascript.GalenJsExecutor.(GalenJsExecutor.java:58)
    at com.galenframework.speclang2.pagespec.PageSpecHandler.createGalenJsExecutor(PageSpecHandler.java:97)
    at com.galenframework.speclang2.pagespec.PageSpecHandler.(PageSpecHandler.java:65)
    at com.galenframework.speclang2.pagespec.PageSpecReader.read(PageSpecReader.java:59)
    at com.galenframework.speclang2.pagespec.PageSpecReader.read(PageSpecReader.java:45)
    at com.galenframework.api.Galen.checkLayout(Galen.java:68)
    at com.galenframework.api.Galen.checkLayout(Galen.java:59)
    at com.galenframework.api.Galen.checkLayout(Galen.java:155)
    at com.galenframework.api.Galen.checkLayout(Galen.java:129)
    at com.sample.test.screens.GalenFrameworkTest.checkLogoVisibleAndImageVerification(GalenFrameworkTest.java:64)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:643)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
    at org.testng.TestRunner.privateRun(TestRunner.java:782)
    at org.testng.TestRunner.run(TestRunner.java:632)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
    at org.testng.SuiteRunner.run(SuiteRunner.java:268)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
    at org.testng.TestNG.run(TestNG.java:1064)
    at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
    at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109)

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.