Estoy realizando la prueba de navegador cruzado de una aplicación web GWT en diferentes PC usando Selenium Grid. El problema al que me enfrento es que el tamaño de las capturas de pantalla generadas (tomadas durante las pruebas) es diferente para diferentes PC y quiero que mi código sea genérico, es decir, para establecer un tamaño predeterminado de las capturas de pantalla. Aquí está mi código que estoy usando para tomar la captura de pantalla y luego comparar la imagen generada con la imagen almacenada localmente en mi PC.

En primer lugar, llamaré al método CallScreenshotAndCompareImage con argumentos (canvas, className).

Aquí el lienzo es el elemento web que representa el lienzo HTML5 en la aplicación GWT.

FileBase es el archivo almacenado localmente en mi proyecto y fileActual es la imagen de captura de pantalla generada.

public class Browser {
    //ThreadLocal will provide thread-safe tests
        protected ThreadLocal<RemoteWebDriver> threadLocal = null;
        String serverMachine = "xxx.xxx.xxx.xxx:xxx/hub"; //IP Address of hub
        @BeforeTest
        @Parameters("browser")
        public void setup(String browser) throws MalformedURLException{

            if(browser.equalsIgnoreCase("chrome")) {

                System.setProperty("webdriver.chrome.driver", ".src/Drivers/chromedriver.exe");
                DesiredCapabilities capability = null;
                capability = DesiredCapabilities.chrome();
                capability.setPlatform(Platform.WINDOWS);
                capability.setBrowserName("chrome");
                createRemoteWebDriver(capability);
            }
            else if(browser.equalsIgnoreCase("firefox")) {

                System.setProperty("webdriver.gecko.driver", ".src/Drivers/geckodriver.exe");
                DesiredCapabilities capability = null;
                capability = DesiredCapabilities.firefox();
                capability.setPlatform(Platform.WINDOWS);
                capability.setBrowserName("firefox");
                createRemoteWebDriver(capability);
            }

        }
        public void createRemoteWebDriver(DesiredCapabilities capability) throws MalformedURLException {
            threadLocal = new ThreadLocal<RemoteWebDriver>();
            threadLocal.set(new RemoteWebDriver(new URL(serverMachine), capability));
        }

        public WebDriver getDriver() {
            return threadLocal.get();
        }

public void CallScreenshotAndCompareImage(WebElement element, String className) throws IOException, InterruptedException {
            File fileBase1 = new File("./src/Images/baseDrawing"+className+"Chrome.png");
            File fileBase2 = new File("./src/Images/baseDrawing"+className+"Firefox.png");
            Capabilities cap = ((RemoteWebDriver) getDriver()).getCapabilities();
            String browserName = cap.getBrowserName().toLowerCase();
            File fileActual = new File("./src/Images/actualDrawing"+className+browserName+".png");
            File elementImage = this.takeElementScreenshot(element,"png");
            FileUtils.copyFile(elementImage, fileActual);
            if(browserName.equalsIgnoreCase("chrome"))
                this.compareImage(fileBase1,fileActual);
            else if(browserName.equalsIgnoreCase("firefox"))
                this.compareImage(fileBase2,fileActual);
            Thread.sleep(3000);
        }

public File takeElementScreenshot(WebElement element, String imageFormat) throws IOException{

            Point elementXY = element.getLocation();
            int elementHeight = element.getSize().getHeight();
            int elementWidth = element.getSize().getWidth();
            Rectangle elementRectArea = new Rectangle(elementWidth,elementHeight);
            WrapsDriver wrapsDriver = (WrapsDriver) element;
            File pageImage = ((TakesScreenshot)wrapsDriver.getWrappedDriver()).getScreenshotAs(OutputType.FILE);
            BufferedImage bufferedImage = ImageIO.read(pageImage);
            BufferedImage elementImage = bufferedImage.getSubimage(elementXY.getX(), elementXY.getY(), elementRectArea.width, elementRectArea.height);
            ImageIO.write(elementImage, imageFormat, pageImage);
            return pageImage; 
        }

        public void compareImage(File fileBase, File fileActual) {
            /* 
         STEPS:
         1) For first image file, recognize the contents of the file and decodes it into a BufferedImage which can be directly used by Java 2D.
         2) Get the raster from the bufferedImage object which is a copy of image data.
         3) Get the DataBuffer associated with the raster.
         4) Get the size of the all the banks(data arrays) for the DataBuffer object.
         5) Repeat steps 1-4 for the second image file.
         6) If sizes of both of the images are different, then images won't be same.
         7) If sizes are same, then compare all the data array elements for both of the DataBuffer objects. If they are same. then both images will be same.
             */

            try {

                BufferedImage bufferedImage = ImageIO.read(fileBase); 
                DataBuffer dataBufferFirst = bufferedImage.getData().getDataBuffer(); 
                int sizeFirst = dataBufferFirst.getSize();              
                BufferedImage bufferedImage2 = ImageIO.read(fileActual);
                DataBuffer dataBufferSecond = bufferedImage2.getData().getDataBuffer();
                int sizeSecond = dataBufferSecond.getSize();
                int count=0;
                Assert.assertEquals(sizeFirst, sizeSecond,"Size of Base Drawing and actual Drawing is not same");
                if(sizeFirst == sizeSecond) 
                {
                    for(int i=0; i<sizeFirst; i++) 
                    { 
                        if(dataBufferFirst.getElem(i) != dataBufferSecond.getElem(i)) //getElem() returns the data array element at the specified index.
                        {
                            count++;
                        }

                    }
                    Assert.assertEquals(count, 0,"Both images are not same");
                }
            } catch (Exception e) { 
                Assert.fail("Failed to compare image files...!!!");
            }
        }
}

Después de ejecutar este código, cuando comparé las propiedades de la imagen base (local) y la imagen real (generada), hubo una pequeña diferencia entre ambas imágenes.

Dibujo base : tamaño -> 253 KB, profundidad de bits -> 32, dimensiones -> 1570 x 873 píxeles

Dibujo real : tamaño -> 232 KB, profundidad de bits -> 24, dimensiones -> 1570 x 873 píxeles

Todo lo demás era igual en las propiedades de ambas imágenes.

¿Qué debo agregar en mi código para que las capturas de pantalla generadas desde diferentes PC siempre sean del mismo tamaño?

3
TheHungryCoder 11 oct. 2017 a las 10:25

3 respuestas

La mejor respuesta

Aunque la respuesta de @Florent B. me dio una dirección para abordar la solución, pero esto es lo que hice para resolver este problema.

  1. Se verificó si la profundidad de bits de la imagen es 24 o 32.
  2. Si es 32, eliminó todos los canales alfa.
  3. A continuación, establezco un rango que si la diferencia entre los valores RGB de los píxeles de dos imágenes correspondientes era inferior a 10, entonces consideraría esas imágenes como iguales.
0
TheHungryCoder 21 oct. 2017 a las 06:20

El problema no es el tamaño de la imagen, sino el canal alfa (transparencia) que está presente en el dibujo base y que falta en la captura de pantalla.

Se supone que el controlador devuelve una cadena codificada PNG Base64. Pero no se especifica si debe ser un PNG RGB de 24 bits o RGBA de 32 bits. Entonces, para poder comparar los búferes, primero deberá convertir cada uno de ellos al espacio de color deseado.

Este es un ejemplo:

public static void main(String[] args) throws Exception {
    BufferedImage imageA = ImageIO.read(new File("C:\\temp\\img_24bits.png"));
    BufferedImage imageB = ImageIO.read(new File("C:\\temp\\img_32bits.png"));
    boolean same = isSameImage(imageA, imageB);
}

public static boolean isSameImage(BufferedImage imageA, BufferedImage imageB) throws IOException {
    DataBufferInt bufferA = getImageBuffer(imageA);
    DataBufferInt bufferB = getImageBuffer(imageB);

    if (bufferA.getSize() != bufferB.getSize() || bufferA.getNumBanks() != bufferB.getNumBanks())
        return false;

    for (int i = 0; i < bufferA.getNumBanks(); ++i) {
        if (!Arrays.equals(bufferA.getData(i), bufferB.getData(i)))
            return false;
    }

    return true;
}

private static DataBufferInt getImageBuffer(BufferedImage img) throws IOException {
    BufferedImage  bi  = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
    ColorConvertOp cco = new ColorConvertOp(bi.getColorModel().getColorSpace(), img.getColorModel().getColorSpace(), null);
    cco.filter(img, bi);
    return (DataBufferInt)bi.getRaster().getDataBuffer();
}
1
Florent B. 16 oct. 2017 a las 15:24

Creo que debe usar un comando para establecer la resolución del controlador ejecutado. Para hacerlo, agregue Java

driver.manage().window().setSize(new Dimension (1280, 1024));

Antes de tus pasos de prueba. Ahora la captura de pantalla siempre tendrá la misma resolución.

-1
Arno Don Calzone 11 oct. 2017 a las 08:53