Автоматизация тестирования верстки сравнениям двух скриншотов

Добрый день. Подскажите варианты внедрения автоматического тестирования верстки. Занимаюсь автоматизацией функциональних тестов java-webdriver-TestNG-gradle-jenkins. Интересуют варианти с сравнениям сделаного скриншота с еталонним. Есть ли готовие решения? И на сколько ефективно такое тестирования?

Попробуй посмотреть в сторону https://applitools.com/

Есть замечательный фреймворк Yandex AShot. В последних коммитах есть моя доработка, при которой можно сравнивать скриншот не просто с шаблоном, а с другим скриншотом где нужным цветом замазаны области для игнорирования сравнения (например номера договоров клиента и т.д.)

Единственный минус - если нужен функционал закрашивания областей для игнора, то придется самому собрать либу и подключать ее (автор еще не зарелизил последние изменения)

Посмотрите ещё в сторону http://backtrac.io

Если я правильно понял, то этот сервис делает снимок страниц из sitemap. Но есть ограничение : до 100 страниц ?

Там есть возможность ручного ввода адресов.
Про 100 снимков экрана — это в бесплатной подписке. Надо больше?

Не, думаю достаточно)
Просто пытаюсь разобраться в возможностях сервиса.

тестирую фреймворк. Сразу же наткнулся на следующий баг:

org.openqa.selenium.WebDriverException: $ is not defined

Вот код:

WebDriver driver;
@Test
public void ashotTest() throws IOException
{
	driver = new FirefoxDriver();
	driver.get("https://www.google.com.ua/");
	WebElement field = driver.findElement(By.xpath(".//*[@id='lst-ib']"));
	new AShot()
	  .takeScreenshot(driver, field);
}

Полний лог:

FAILED: ashotTest
org.openqa.selenium.WebDriverException: $ is not defined
Command duration or timeout: 59 milliseconds

Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities [{applicationCacheEnabled=true, rotatable=false, handlesAlerts=true, databaseEnabled=true, version=46.0.1, platform=WINDOWS, nativeEvents=false, acceptSslCerts=true, webStorageEnabled=true, locationContextEnabled=true, browserName=firefox, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}]
Session ID: fddaba4d-9b61-465e-abc8-06ae04ae5b85
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:206)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:158)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:678)
at org.openqa.selenium.remote.RemoteWebDriver.executeScript(RemoteWebDriver.java:577)
at ru.yandex.qatools.ashot.util.JsCoords.findCoordsWithJquery(JsCoords.java:30)
at ru.yandex.qatools.ashot.coordinates.JqueryCoordsProvider.ofElement(JqueryCoordsProvider.java:13)
at ru.yandex.qatools.ashot.coordinates.CoordsProvider.ofElements(CoordsProvider.java:21)
at ru.yandex.qatools.ashot.AShot.takeScreenshot(AShot.java:115)
at ru.yandex.qatools.ashot.AShot.takeScreenshot(AShot.java:132)
at myPackage.TestLayout.ashotTest(TestLayout.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
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:1246)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1171)
at org.testng.TestNG.run(TestNG.java:1066)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:113)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:206)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:177)
Caused by: org.openqa.selenium.WebDriverException: $ is not defined

Вопрос к dimand58

@Furik_Vasil
Порядок анализа проблемы такой:

  1. В стектрейсе явно видно, что некий символ $ не определен
  2. По названию одного из методов JqueryCoordsProvider.ofElement можно догадаться, что идет работа с JQuery внутри браузера и тут возникает проблема
  3. Далее можно залезть на страницу фреймворка и по слову jquery найти раздел документации:

As noted earlier aShot will find element’s size and position and crop original image. WebDriver API provides a method to find the WebElement’s coordinates but different WebDriver implementations behave differently. In my opinion the most general approach to find coordinates is to use jQuery. So aShot uses jQuery by default. But some drivers have problems with Javascript execution such as OperaDriver. In this case there is another way to find the WebElement’s coordinates.

new AShot()
  .coordsProvider(new WebDriverCoordsProvider()) //find coordinates with WebDriver API
  .takeScreenshot(webDriver, myWebElement);

Т.е. нужно сказать AShot’у использовать API драйвера, а не JQuery.

Надеюсь, что я натолкнул на правильный путь - читать стектрейс и документацию =)

пользуюсь ImageMagick

умеет и отличающиеся пиксели считать и красным их подсвечивать и gif-ки делать из двух разных скриншотов.

1 лайк

На текущем проекте используем https://github.com/webdriverio/webdrivercss (regression tests) ,результат и скриншоты отображаются в репорте robotframework-a.

какие язики поддерживает ?

у него api есть ?

есть пример как использовать Ваш compare подход с Ashot ?

@Taras
Если коротко, то последний раздел документации:

Сама картинка из тестов - в данном случае линия с цветом 255,0,255 будет проигнорирована при сравнение этой картинки с актуальным изображением

Как красиво встроить в свой проект - дело вкуса уже.

1 лайк

Вот тут список api http://www.imagemagick.org/script/api.php

но я использую консольный интерфейс - сначала собираю скриншоты, потом следующим шагом в jenkins сравниваю их с оригиналом.

Вообще я его начал использовать еще до того как осознал, что все тоже самое можно делать самому без всяких библиотек, например вот простой код, который сравнивает две картинки попиксельно:

private int diff(BufferedImage expected, BufferedImage current) {
       int skipColor=0; //цвет который не будем сравнивать (замазываем на оригиналах места, где допускается разница)
       int diff=0;
      for(int y=0;y<expected.getHeight();y++){ //Цикл по рядам
        for(int x=0;x<expected.getWidth();x++){//Цикл по столбцам
            if(expected.getRGB(x, y)!=skipColor && expected.getRGB(x, y)!=current.getRGB(x, y)) {
                diff++;
            }
        }
      }
      return diff;
}

Использую следующую структуру:

  1. так как все функциональные тесты написаны на роботфрейморке, то и регрешн тесты решили также показывать в общем репорте, который генерит робот. Регрешн тесты написаны на node.js, если тест фейлится то скрин попадает в лог репорта.

    `*** Settings ***
    Force Tags 403 404 regression
    Resource …/…/Resources/Project.robot
    Resource …/…/Resources/Common.robot

    *** Test Cases ***
    Regression Css Test to Check 404 Error Page
    ${result} run regression test ${test_path}/tests/access/regressions/404_403_page.js
    ${status} ${value}= Run keyword and ignore error Should Be True ${result}
    Run Keyword If ‘${status}’ == ‘FAIL’ run keywords
    Log html=yes
    Should Be True ${result}
    Run Keyword If ‘${status}’ == ‘PASS’ Log html=yes
    `

  2. run regression test реализован так:

    from Naked.toolshed.shell import execute_js, muterun_js
    def run_regression_test(js_file_path):
    success = execute_js(js_file_path)
    if success:
    return True
    по сути средствами пайтона выполняем node js скрипт

  3. сам тест на ноде

    var assert = require(‘assert’);
    var proj = require(’…/…/…/Resources/project.conf.js’);

    var client = require(‘webdriverio’).remote({
    desiredCapabilities: {
    browserName: proj.browserName
    }
    });

    require(‘webdrivercss’).init(client, {
    screenshotRoot: ‘Results/Regression/403_404/my-shots’,
    failedComparisonsRoot: ‘Results/Regression/403_404/diffs’,
    misMatchTolerance: 0.05,
    screenWidth: proj.screenWidth
    });

    client
    .init()
    .url(proj.domain + ‘not-found’)
    .webdrivercss(‘not found’, [
    {
    name: ‘not_found’,
    elem: proj.content,
    }, {
    name: ‘not_found_full_page’,
    exclude:[
    proj.pane_page_logo,
    proj.pane_site_name,
    proj.pane_main_menu,
    proj.pane_footer_menu,
    ]
    }
    ], function(err, res) {
    assert.ifError(err);
    assert.ok(res.not_found[0].isWithinMisMatchTolerance);
    assert.ok(res.not_found_full_page[0].isWithinMisMatchTolerance);
    })
    .end()
    надеюсь поможет )

thanks)