Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

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

screenshot
gradle
jenkins
java
webdriver
testng
Теги: #<Tag:0x00007f7b65f69f68> #<Tag:0x00007f7b65f69ce8> #<Tag:0x00007f7b65f69a90> #<Tag:0x00007f7b65f69838> #<Tag:0x00007f7b65f69608> #<Tag:0x00007f7b65f69310>

(Василь ) #1

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


Java + Selenium Помогите разобраться с автотестами для карты
(Ugin Berets) #2

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


(Dmitrii Demin) #3

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

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


(Сергей Блохин) #4

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


(Ugin Berets) #5

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


(Сергей Блохин) #6

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


(Ugin Berets) #7

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


(Василь ) #8

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

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


(Василь ) #9

Вопрос к dimand58


(Dmitrii Demin) #10

@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.

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


(X-NoNAME) #11

пользуюсь ImageMagick

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


(rom4ikkk) #12

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


(Taras) #13

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


(Taras) #14

у него api есть ?


(Taras) #15

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


(Dmitrii Demin) #16

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

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

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


(X-NoNAME) #17

Вот тут список 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;
}

(rom4ikkk) #18

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

  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()
    надеюсь поможет )


(Taras) #19

thanks)