3

I am trying to compare two screen shots on a webpage. It is a practice page on saucelab. When you login as a standart_user and click the login button, it takes you to the products page. Then you see the pictures of products. (Backpacks, t-shirts etc.)

When you login as a problem_user, you see puppy pictures instead of products' picture. I want to screen shot the both pages and compare them. I took the shots by using WebdriverWait.

But the shots are taken before the pictures were loaded fully. What should I use to wait until the pictures on products page are fully loaded?

Below is my code.

public void waitElementVisibility(By visibleImage) {
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(40));
    wait.until(ExpectedConditions.visibilityOfElementLocated(visibleImage));
}

public void captureSuccesfulPageScreenShot() {
    waitElementVisibility(visibleImage);
    TakesScreenshot screenshot = (TakesScreenshot) driver;
    File file = screenshot.getScreenshotAs(OutputType.FILE);
    File path = new File("images/screenshot.png");
    try {
        FileUtils.copyFile(file, path);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

public void captureProblemUserScreenShot() {
    waitElementVisibility(visibleImage);
    TakesScreenshot screenshot = (TakesScreenshot) driver;
    File file = screenshot.getScreenshotAs(OutputType.FILE);
    File path = new File("images/problemUserScrSh.png");
    try {
        FileUtils.copyFile(file, path);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
Alex
  • 31
  • 4
  • Hard to tell without seeing the page and knowing the `visibleImage` value. Make sure you have the right locator of the image not some parrent div. Check if there is some loading element you have to wait until it is gone. Try some different `ExpectedConditions` as well. – pburgr Aug 23 '22 at 06:45
  • The webpage is https://www.saucedemo.com/ . It is one of those practice pages on the web. I tried implicit wait and fluent wait too. So each time I took screen shot, I get the pictures half loaded or not at all. Pictures are also clickable or selectable. So tried them as expected condition too. It looks like they become clickable or/and selectable before pictures become all visible. You can see my project on https://github.com/abnerAlexis/SauceDemoProject – Alex Aug 23 '22 at 14:32

1 Answers1

0

I've managed to create a wait method, but it fails on fifth image. Performing the render check take some time and I'm unable to simulate slow rendering.

Code:

package tests;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class Saucedemo {

    
    public static void main(String[] args) {
        WebDriver driver = startChromeDriver();
        driver.get("https://www.saucedemo.com/");
        
        logIn(driver, "standard_user");
        List<WebElement> inventoryContainerImages = inventoryContainerImages(driver);
        waitForRenderingImages(driver, inventoryContainerImages, 4);
        saveScreenShotAs(driver, "standard_user");
        logOut(driver);
        
        logIn(driver, "problem_user");
        inventoryContainerImages = inventoryContainerImages(driver);
        waitForRenderingImages(driver, inventoryContainerImages, 4);
        saveScreenShotAs(driver, "problem_user");
        logOut(driver);
        
        driver.quit();
    }   

    public static WebDriver startChromeDriver() {
        String chromedriverPath = System.getProperty("user.dir") + "\\resources\\chromedriver.exe";
        System.setProperty("webdriver.chrome.driver", chromedriverPath);
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--ignore-certificate-errors");
        options.addArguments("--start-maximized");
        options.addArguments("--disable-notifications");
        WebDriver driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        return driver;
    }
    
    public static void logIn(WebDriver driver, String userName) {
        System.out.println("Login as user: " + userName);
        driver.findElement(By.id("user-name")).sendKeys(userName);
        driver.findElement(By.id("password")).sendKeys("secret_sauce");
        driver.findElement(By.id("login-button")).click();
    }
    
    public static void saveScreenShotAs(WebDriver driver, String fileName) {
        TakesScreenshot screenshot = (TakesScreenshot) driver;
        File file = screenshot.getScreenshotAs(OutputType.FILE);
        File path = new File(fileName + ".png");
        try {
            FileUtils.copyFile(file, path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void logOut(WebDriver driver) {
        System.out.println("Logout");
        driver.findElement(By.id("react-burger-menu-btn")).click();
        driver.findElement(By.id("logout_sidebar_link")).click();
    }
    
    public static BufferedImage getBufferedImageOfElement(WebDriver driver, WebElement element) {
        BufferedImage elementImage = null;
        BufferedImage fullImage = null;     
        TakesScreenshot screenshot = (TakesScreenshot) driver;
        File file = screenshot.getScreenshotAs(OutputType.FILE);
        try {
            fullImage = ImageIO.read(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Point point = element.getLocation();
        int width = element.getSize().getWidth();
        int height = element.getSize().getHeight();
        elementImage = fullImage.getSubimage(point.getX(), point.getY(), width, height);
        return elementImage;
    }
    
    public static BufferedImage getBufferedImageFromUrl(String imgSrc) {
        BufferedImage image = null;
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) new URL(imgSrc).openConnection();
            connection.connect();
            image = ImageIO.read(connection.getInputStream());
            connection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
    }
    
    public static Boolean imagesAreEqual(BufferedImage source, BufferedImage target) {
        Boolean samePixelColors = true;
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();
        BufferedImage resizedTarget = resizeBufferedImage(source, sourceWidth, sourceHeight);
        for (int x = 0; x < sourceWidth; x++) {
            for (int y = 0; y < sourceHeight; y++) {
                int sourceRgb = source.getRGB(x, y);
                int resizedTargetRgb = resizedTarget.getRGB(x, y);
                if (sourceRgb != resizedTargetRgb) {
                    samePixelColors = false;
                    break;
                }
            }
        }
        if (samePixelColors) {
            return true;
        }
        else {
            return false;
        }
    }
    
    public static Boolean elementsImageEqualSrcImage(WebDriver driver, WebElement element) {
        BufferedImage imageOfElement = getBufferedImageOfElement(driver, element);
        String src = element.getAttribute("src");
        BufferedImage imageFromUrl = getBufferedImageFromUrl(src);
        return imagesAreEqual(imageFromUrl, imageOfElement);
    }
    
    public static void waitForRenderingImages(WebDriver driver, List<WebElement> images, int maxImages) {
        int maxIndex = maxImages - 1;
        if (maxIndex <= images.size()) {
            WebDriverWait wait10s = new WebDriverWait(driver, 10);
            for (int i = 0; i <= maxIndex; i++) {
                WebElement image = images.get(i);
                if (!elementsImageEqualSrcImage(driver, image)) {
                    System.out.println("Image " + (i + 1) + " of " + images.size() + " not equal with its URL source, waiting 100 ms.");
                    wait10s.until(new Function<WebDriver, Boolean> () {
                        public Boolean apply(WebDriver driver) {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                
                            }
                            return elementsImageEqualSrcImage(driver, image);
                        }
                    });
                }
                else {
                    System.out.println("Image " + (i + 1) + " of " + images.size() + " equal with its URL source, no waiting.");
                }
            }
        }
        else {
            System.out.println("Error - argument maxImames is greater than images.size()");
        }
    }
    
    public static List<WebElement> inventoryContainerImages(WebDriver driver) {
        WebElement inventoryContainer = driver.findElement(By.id("inventory_container"));
        return inventoryContainer.findElements(By.tagName("img"));
    }
    
    public static BufferedImage resizeBufferedImage(BufferedImage sourceImage, int width, int height) { 
        Image image = sourceImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = resizedImage.createGraphics();
        g2d.drawImage(image, 0, 0, null);
        g2d.dispose();
        return resizedImage;
    } 
    
}

Output:

Starting ChromeDriver 104.0.5112.79 (3cf3e8c8a07d104b9e1260c910efb8f383285dc5-refs/branch-heads/5112@{#1307}) on port 22424
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
Srp 29, 2022 2:12:39 ODP. org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
Login as user: standard_user
Image 1 of 6 equal with its URL source, no waiting.
Image 2 of 6 equal with its URL source, no waiting.
Image 3 of 6 equal with its URL source, no waiting.
Image 4 of 6 equal with its URL source, no waiting.
Logout
Login as user: problem_user
Image 1 of 6 equal with its URL source, no waiting.
Image 2 of 6 equal with its URL source, no waiting.
Image 3 of 6 equal with its URL source, no waiting.
Image 4 of 6 equal with its URL source, no waiting.
Logout
pburgr
  • 1,722
  • 1
  • 11
  • 26
  • Inside the waitForRendering class, you declare the size of your list. But then in the parameters you send a number 4. By doing that you are overriding your list size declaration. I think that is why you get an error after the 5th. – Alex Aug 30 '22 at 22:02
  • No, I limited the comparison because another error, with `waitForRenderingImages(driver, inventoryContainerImages, inventoryContainerImages.size());` I'm getting `java.awt.image.RasterFormatException: (y + height) is outside of Raster ... at tests.Saucedemo.getBufferedImageOfElement(Saucedemo.java:98)`. Fifth image is out of viewport and scroll down is needed. But in that case `getBufferedImageOfElement` method will not return desired cut of screen and comparison will fail. – pburgr Aug 31 '22 at 06:06