diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47989c2..07ef718 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ Create a feature branch and start improving: % git checkout -b my-feature-branch ``` -HEAD-based development is prefered, which means all changes are applied +HEAD-based development is preferred, which means all changes are applied directly on top of master. ### Step 3: Commit diff --git a/README.md b/README.md index 0242478..cce3c1c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Selenium Shutterbug is a utility library written in Java for making screenshots ## Code Example -Screenhot of the page with scrolling (for Chrome to make screenshot of the whole page but not viewport only): +Screenshot of the page with scrolling (for Chrome to make screenshot of the whole page but not viewport only): ``` Shutterbug.shootPage(driver, ScrollStrategy.BOTH_DIRECTIONS).save("C:\\testing\\screenshots\\"); ``` diff --git a/pom.xml b/pom.xml index c444585..a91e6bc 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,11 @@ commons-io 2.6 + + org.projectlombok + lombok + 1.18.8 + diff --git a/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java b/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java index 1e343bb..0687d79 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java @@ -9,7 +9,6 @@ import com.assertthat.selenium_shutterbug.utils.web.Coordinates; import com.assertthat.selenium_shutterbug.utils.web.ElementOutsideViewportException; import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; import java.awt.image.BufferedImage; import java.awt.image.RasterFormatException; diff --git a/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java b/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java index be8e3b6..f291712 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java @@ -5,9 +5,9 @@ package com.assertthat.selenium_shutterbug.core; -import com.assertthat.selenium_shutterbug.utils.web.ElementOutsideViewportException; import com.assertthat.selenium_shutterbug.utils.image.ImageProcessor; import com.assertthat.selenium_shutterbug.utils.web.Coordinates; +import com.assertthat.selenium_shutterbug.utils.web.ElementOutsideViewportException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; diff --git a/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java b/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java index 81de24c..0479533 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java @@ -69,7 +69,7 @@ public T withTitle(String title) { * @return instance of type Snapshot */ public T withThumbnail(String path, String name, double scale) { - File thumbnailFile = new File(path.toString(), name); + File thumbnailFile = new File(path, name); if(!Files.exists(Paths.get(path))) { thumbnailFile.mkdirs(); } @@ -90,15 +90,12 @@ public T withThumbnail(String path, String name, double scale) { * @return instance of type Snapshot */ public T withCroppedThumbnail(String path, String name, double scale, double cropWidth, double cropHeight) { - File thumbnailFile = new File(path.toString(), name); - if(!Files.exists(Paths.get(path))) { - thumbnailFile.mkdirs(); - } + File thumbnailFile = getFile(path, name); thumbnailImage=ImageProcessor.cropAndScale(image,scale, cropWidth, cropHeight); FileUtil.writeImage(thumbnailImage, EXTENSION, thumbnailFile); return self(); } - + /** * Generate cropped thumbnail of the original screenshot. * Will save different thumbnails depends on when it was called in the chain. @@ -111,15 +108,27 @@ public T withCroppedThumbnail(String path, String name, double scale, double cr * @return instance of type Snapshot */ public T withCroppedThumbnail(String path, String name, double scale, int maxWidth, int maxHeight) { - File thumbnailFile = new File(path.toString(), name); - if(!Files.exists(Paths.get(path))) { - thumbnailFile.mkdirs(); - } + File thumbnailFile = getFile(path, name); thumbnailImage=ImageProcessor.cropAndScale(image,scale, maxWidth, maxHeight); FileUtil.writeImage(thumbnailImage, EXTENSION, thumbnailFile); return self(); } - + + /** + * Generate file for cropped thumbnail of the original screenshot. + * + * @param path to save thumbnail image to + * @param name of the resulting image + * @return instance of type File + */ + private File getFile(String path, String name) { + File thumbnailFile = new File(path, name); + if (!Files.exists(Paths.get(path))) { + thumbnailFile.mkdirs(); + } + return thumbnailFile; + } + /** * Generate cropped thumbnail of the original screenshot. * Will save different thumbnails depends on when it was called in the chain. diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java index 024a465..320b11b 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java @@ -24,7 +24,7 @@ public static String getJsScript(String filePath) { try { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath); if (is == null) { - // This is needed to load the files in an OSGI enviroment when enclosed in a bundle + // This is needed to load the files in an OSGI environment when enclosed in a bundle is = FileUtil.class.getClassLoader().getResourceAsStream(filePath); } // if the input stream is still null, this will avoid a non descriptive null pointer exception diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java index dd7a7cc..9faeca0 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java @@ -5,8 +5,6 @@ package com.assertthat.selenium_shutterbug.utils.file; -import org.openqa.selenium.WebDriverException; - /** * Created by Glib_Briia on 17/06/2016. */ diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java index 19ca528..35656fc 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java @@ -5,13 +5,18 @@ package com.assertthat.selenium_shutterbug.utils.image; -import com.assertthat.selenium_shutterbug.utils.file.FileUtil; +import com.assertthat.selenium_shutterbug.utils.image.model.ImageData; import com.assertthat.selenium_shutterbug.utils.web.Coordinates; import java.awt.*; import java.awt.color.ColorSpace; -import java.awt.image.*; -import java.io.File; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorConvertOp; +import java.awt.image.ColorModel; +import java.awt.image.ConvolveOp; +import java.awt.image.Kernel; +import java.awt.image.PixelGrabber; /** * Created by Glib_Briia on 17/06/2016. @@ -19,7 +24,7 @@ public class ImageProcessor { private static final int ARCH_SIZE = 10; - private static float[] matrix = new float[49]; + private static final float[] matrix = new float[49]; private static double pixelError = Double.MAX_VALUE; static { @@ -57,27 +62,21 @@ public static BufferedImage getElement(BufferedImage sourceImage, Coordinates co public static BufferedImage blurArea(BufferedImage sourceImage, Coordinates coords) { BufferedImage blurredImage = blur(sourceImage.getSubimage(coords.getX(), coords.getY(), coords.getWidth(), coords.getHeight())); - BufferedImage combined = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D g = combined.createGraphics(); - g.drawImage(sourceImage, 0, 0, null); - g.drawImage(blurredImage, coords.getX(), coords.getY(), null); - g.dispose(); - return combined; + return getBufferedImage(sourceImage, coords, blurredImage, sourceImage); } public static BufferedImage monochromeArea(BufferedImage sourceImage, Coordinates coords) { BufferedImage monochromedImage = convertToGrayAndWhite(sourceImage.getSubimage(coords.getX(), coords.getY(), coords.getWidth(), coords.getHeight())); - BufferedImage combined = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D g = combined.createGraphics(); - g.drawImage(sourceImage, 0, 0, null); - g.drawImage(monochromedImage, coords.getX(), coords.getY(), null); - g.dispose(); - return combined; + return getBufferedImage(sourceImage, coords, monochromedImage, sourceImage); } public static BufferedImage blurExceptArea(BufferedImage sourceImage, Coordinates coords) { BufferedImage subImage = sourceImage.getSubimage(coords.getX(), coords.getY(), coords.getWidth(), coords.getHeight()); BufferedImage blurredImage = blur(sourceImage); + return getBufferedImage(sourceImage, coords, subImage, blurredImage); + } + + private static BufferedImage getBufferedImage(BufferedImage sourceImage, Coordinates coords, BufferedImage subImage, BufferedImage blurredImage) { BufferedImage combined = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g = combined.createGraphics(); g.drawImage(blurredImage, 0, 0, null); @@ -87,8 +86,7 @@ public static BufferedImage blurExceptArea(BufferedImage sourceImage, Coordinate } public static BufferedImage cropAround(BufferedImage sourceImage, Coordinates coords, int offsetX, int offsetY) { - BufferedImage subImage = sourceImage.getSubimage(coords.getX()-offsetX, coords.getY()-offsetY, coords.getWidth()+offsetX*2, coords.getHeight()+offsetY*2); - return subImage; + return sourceImage.getSubimage(coords.getX() - offsetX, coords.getY() - offsetY, coords.getWidth() + offsetX * 2, coords.getHeight() + offsetY * 2); } public static BufferedImage addTitle(BufferedImage sourceImage, String title, Color color, Font textFont) { @@ -108,156 +106,99 @@ public static BufferedImage convertToGrayAndWhite(BufferedImage sourceImage) { } public static boolean imagesAreEquals(BufferedImage image1, BufferedImage image2, double deviation) { - int width1 = image1.getWidth(null); - int width2 = image2.getWidth(null); - int height1 = image1.getHeight(null); - int height2 = image2.getHeight(null); - if ((width1 != width2) || (height1 != height2)) { - throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + width1 + "x" + height1 + "; image2 - " + width2 + "x" + height2); + ImageData image1Data = new ImageData(image1); + ImageData image2Data = new ImageData(image2); + if (image1Data.notEqualsDimensions(image2Data)) { + throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + image1Data.getWidth() + "x" + image1Data.getHeight() + "; image2 - " + image2Data.getWidth() + "x" + image2Data.getHeight()); } - long diff = 0; - for (int y = 0; y < height1; y++) { - for (int x = 0; x < width1; x++) { - int rgb1 = image1.getRGB(x, y); - int rgb2 = image2.getRGB(x, y); - int r1 = (rgb1 >> 16) & 0xff; - int g1 = (rgb1 >> 8) & 0xff; - int b1 = (rgb1) & 0xff; - int r2 = (rgb2 >> 16) & 0xff; - int g2 = (rgb2 >> 8) & 0xff; - int b2 = (rgb2) & 0xff; - diff += Math.abs(r1 - r2); - diff += Math.abs(g1 - g2); - diff += Math.abs(b1 - b2); - } - } - double n = width1 * height1 * 3; - double p = diff / n / 255.0; - return p == 0 || p <= deviation; + return image1Data.equalsEachPixels(image2Data, deviation); } /** * Extends the functionality of imagesAreEqualsWithDiff, but creates a third BufferedImage and applies pixel manipulation to it. - * @param image1 The first image to compare - * @param image2 The second image to compare + * + * @param image1 The first image to compare + * @param image2 The second image to compare * @param pathFileName The output path filename for the third image, if null then is ignored - * @param deviation The upper limit of the pixel deviation for the test + * @param deviation The upper limit of the pixel deviation for the test * @return If the test passes */ public static boolean imagesAreEqualsWithDiff(BufferedImage image1, BufferedImage image2, String pathFileName, double deviation) { - BufferedImage output = new BufferedImage(image1.getWidth(), image1.getHeight(), BufferedImage.TYPE_INT_RGB); - - int width1 = image1.getWidth(null); - int width2 = image2.getWidth(null); - int height1 = image1.getHeight(null); - int height2 = image2.getHeight(null); - if ((width1 != width2) || (height1 != height2)) { - throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + width1 + "x" + height1 + "; image2 - " + width2 + "x" + height2); + ImageData image1Data = new ImageData(image1); + ImageData image2Data = new ImageData(image2); + if (image1Data.notEqualsDimensions(image2Data)) { + throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + image1Data.getWidth() + "x" + image1Data.getHeight() + "; image2 - " + image2Data.getWidth() + "x" + image2Data.getHeight()); } - long diff = 0; - long recordedDiff = 0; // Records the difference so it can be compared, saves having to do three if statements - for (int y = 0; y < height1; y++) { - for (int x = 0; x < width1; x++) { - recordedDiff = diff; - - // Grab RGB values of both images, then bit shift and bitwise AND to break them down into R, G and B - int rgb1 = image1.getRGB(x, y); - int rgb2 = image2.getRGB(x, y); - int r1 = (rgb1 >> 16) & 0xff; - int g1 = (rgb1 >> 8) & 0xff; - int b1 = (rgb1) & 0xff; - int r2 = (rgb2 >> 16) & 0xff; - int g2 = (rgb2 >> 8) & 0xff; - int b2 = (rgb2) & 0xff; - diff += Math.abs(r1 - r2); - diff += Math.abs(g1 - g2); - diff += Math.abs(b1 - b2); - - // If difference > recorded difference, change pixel to red. If zero, set to image 1's original pixel - if(diff > recordedDiff) - output.setRGB(x,y,new Color(255,0,0).getRGB() & rgb1); // Dark red = original position, Light red is moved to - else - output.setRGB(x,y,rgb1); - } - } - int colourSpaceBytes = 3; // RGB is 24 bit, or 3 bytes - double totalPixels = width1 * height1 * colourSpaceBytes; - pixelError = diff / totalPixels / 255.0; - - // Write the image as png, with the filename based on the path provided - if(pixelError > 0) - FileUtil.writeImage(output,"png",new File(pathFileName+".png")); - return pixelError == 0 || pixelError <= deviation; + return image1Data.equalsEachPixelsWithCreateDifferencesImage(image2Data, deviation, pathFileName); } public static BufferedImage scale(BufferedImage source, double ratio) { - return cropAndScale(source, ratio, 1.0,1.0); + return cropAndScale(source, ratio, 1.0, 1.0); } - - public static BufferedImage cropAndScale(BufferedImage source,double ratio, double cropWidth, double cropHeight) { + + public static BufferedImage cropAndScale(BufferedImage source, double ratio, double cropWidth, double cropHeight) { int w = (int) (source.getWidth() * ratio); int h = (int) (source.getHeight() * ratio); - BufferedImage scaledImage = getCompatibleImage(w, h, source); - Graphics2D resultGraphics = scaledImage.createGraphics(); - resultGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BICUBIC); - resultGraphics.drawImage(source, 0, 0, w, h, null); - resultGraphics.dispose(); - return scaledImage.getSubimage(0, 0, (int)(w*cropWidth),(int)(h*cropHeight)); + BufferedImage scaledImage = createAndDrawImage(source, w, h); + return scaledImage.getSubimage(0, 0, (int) (w * cropWidth), (int) (h * cropHeight)); } - - public static BufferedImage cropAndScale(BufferedImage source,double ratio, int maxWidth, int maxHeight) { + + public static BufferedImage cropAndScale(BufferedImage source, double ratio, int maxWidth, int maxHeight) { int w = (int) (source.getWidth() * ratio); int h = (int) (source.getHeight() * ratio); + BufferedImage scaledImage = createAndDrawImage(source, w, h); + if (maxWidth != -1 && w > maxWidth) { + w = maxWidth; + } + if (maxHeight != -1 && h > maxHeight) { + h = maxHeight; + } + return scaledImage.getSubimage(0, 0, w, h); + } + + private static BufferedImage createAndDrawImage(BufferedImage source, int w, int h) { BufferedImage scaledImage = getCompatibleImage(w, h, source); Graphics2D resultGraphics = scaledImage.createGraphics(); resultGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); resultGraphics.drawImage(source, 0, 0, w, h, null); resultGraphics.dispose(); - if(maxWidth != -1 && w > maxWidth){ - w = maxWidth; - } - if(maxHeight != -1 && h > maxHeight){ - h = maxHeight; - } - return scaledImage.getSubimage(0, 0, w,h); + return scaledImage; } - - + private static BufferedImage getCompatibleImage(int w, int h, BufferedImage source) { - BufferedImage bimage = null; - try{ + BufferedImage bImage = null; + try { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); GraphicsConfiguration gc = gd.getDefaultConfiguration(); - bimage = gc.createCompatibleImage(w,h); + bImage = gc.createCompatibleImage(w, h); } catch (HeadlessException e) { // The system does not have a screen } - if (bimage == null) { + if (bImage == null) { boolean hasAlpha = hasAlpha(source); int type = BufferedImage.TYPE_INT_RGB; if (hasAlpha) { type = BufferedImage.TYPE_INT_ARGB; } - bimage = new BufferedImage(w, h, type); + bImage = new BufferedImage(w, h, type); } - return bimage; + return bImage; } public static boolean hasAlpha(Image image) { // If buffered image, the color model is readily available if (image instanceof BufferedImage) { - BufferedImage bimage = (BufferedImage)image; - return bimage.getColorModel().hasAlpha(); + BufferedImage bImage = (BufferedImage) image; + return bImage.getColorModel().hasAlpha(); } // Use a pixel grabber to retrieve the image's color model; // grabbing a single pixel is usually sufficient PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); try { pg.grabPixels(); - } catch (InterruptedException e) { + } catch (InterruptedException ignored) { } // Get the image's color model ColorModel cm = pg.getColorModel(); diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java index 204ab54..490f520 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java @@ -9,6 +9,7 @@ * Created by Glib_Briia on 25/06/2016. */ public class UnableToCompareImagesException extends RuntimeException { + public UnableToCompareImagesException() { super(); } diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/model/ImageData.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/model/ImageData.java new file mode 100644 index 0000000..211f914 --- /dev/null +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/model/ImageData.java @@ -0,0 +1,90 @@ +package com.assertthat.selenium_shutterbug.utils.image.model; + +import com.assertthat.selenium_shutterbug.utils.file.FileUtil; +import lombok.Getter; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; + +@Getter +public class ImageData { + private final int RED_RGB = new Color(255, 0, 0).getRGB(); + private final BufferedImage image; + private final int width; + private final int height; + + public ImageData(BufferedImage image) { + this.image = image; + this.width = image.getWidth(null); + this.height = image.getHeight(null); + } + + public boolean notEqualsDimensions(ImageData imageData) { + return !equalsDimensions(imageData); + } + + private boolean equalsDimensions(ImageData imageData) { + return this.width == imageData.width && this.height == imageData.height; + } + + public boolean equalsEachPixelsWithCreateDifferencesImage(ImageData imageData, double deviation, String pathDifferenceImageFileName) { + return equalsEachPixelsWithCreateDifferencesImage(imageData.getImage(), deviation, pathDifferenceImageFileName); + } + + private boolean equalsEachPixelsWithCreateDifferencesImage(BufferedImage image, double deviation, String pathDifferenceImageFileName) { + createDifferencesImage(image, pathDifferenceImageFileName); + return equalsEachPixels(image, deviation); + } + + private void createDifferencesImage(BufferedImage image, String pathDifferenceImageFileName) { + BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int rgb1 = this.getImage().getRGB(x, y); + int rgb2 = image.getRGB(x, y); + + // If difference > recorded difference, change pixel to red. If zero, set to image 1's original pixel + if (rgb1 != rgb2) + output.setRGB(x, y, RED_RGB & rgb1); // Dark red = original position, Light red is moved to + else + output.setRGB(x, y, rgb1); + } + } + + FileUtil.writeImage(output, "png", new File(pathDifferenceImageFileName + ".png")); + } + + public boolean equalsEachPixels(ImageData imageData, double deviation) { + return equalsEachPixels(imageData.getImage(), deviation); + } + + private boolean equalsEachPixels(BufferedImage image, double deviation) { + double p = calculatePixelsDifference(image); + + return p == 0 || p <= deviation; + } + + private double calculatePixelsDifference(BufferedImage image) { + long diff = 0; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int rgb1 = this.getImage().getRGB(x, y); + int rgb2 = image.getRGB(x, y); + int r1 = (rgb1 >> 16) & 0xff; + int g1 = (rgb1 >> 8) & 0xff; + int b1 = (rgb1) & 0xff; + int r2 = (rgb2 >> 16) & 0xff; + int g2 = (rgb2 >> 8) & 0xff; + int b2 = (rgb2) & 0xff; + diff += Math.abs(r1 - r2); + diff += Math.abs(g1 - g2); + diff += Math.abs(b1 - b2); + } + } + double n = width * height * 3; + + return diff / n / 255.0; + } +} diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java index 2b8289b..21b2634 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java @@ -8,8 +8,12 @@ import com.assertthat.selenium_shutterbug.utils.file.FileUtil; import com.google.common.collect.ImmutableMap; import org.openqa.selenium.Dimension; -import org.openqa.selenium.*; +import org.openqa.selenium.JavascriptExecutor; +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.remote.CommandInfo; import org.openqa.selenium.remote.HttpCommandExecutor; @@ -35,17 +39,17 @@ */ public class Browser { - public static final String RELATIVE_COORDS_JS = "js/relative-element-coords.js"; - public static final String MAX_DOC_WIDTH_JS = "js/max-document-width.js"; - public static final String MAX_DOC_HEIGHT_JS = "js/max-document-height.js"; - public static final String VIEWPORT_HEIGHT_JS = "js/viewport-height.js"; - public static final String VIEWPORT_WIDTH_JS = "js/viewport-width.js"; - public static final String SCROLL_TO_JS = "js/scroll-to.js"; - public static final String SCROLL_INTO_VIEW_JS = "js/scroll-element-into-view.js"; - public static final String CURRENT_SCROLL_Y_JS = "js/get-current-scrollY.js"; - public static final String CURRENT_SCROLL_X_JS = "js/get-current-scrollX.js"; - public static final String DEVICE_PIXEL_RATIO = "js/get-device-pixel-ratio.js"; - public static final String ALL_METRICS = "js/all-metrics.js"; + private static final String RELATIVE_COORDS_JS = "js/relative-element-coords.js"; + private static final String MAX_DOC_WIDTH_JS = "js/max-document-width.js"; + private static final String MAX_DOC_HEIGHT_JS = "js/max-document-height.js"; + private static final String VIEWPORT_HEIGHT_JS = "js/viewport-height.js"; + private static final String VIEWPORT_WIDTH_JS = "js/viewport-width.js"; + private static final String SCROLL_TO_JS = "js/scroll-to.js"; + private static final String SCROLL_INTO_VIEW_JS = "js/scroll-element-into-view.js"; + private static final String CURRENT_SCROLL_Y_JS = "js/get-current-scrollY.js"; + private static final String CURRENT_SCROLL_X_JS = "js/get-current-scrollX.js"; + private static final String DEVICE_PIXEL_RATIO = "js/get-device-pixel-ratio.js"; + private static final String ALL_METRICS = "js/all-metrics.js"; private WebDriver driver; private int docHeight = -1; @@ -57,9 +61,9 @@ public class Browser { public Browser(WebDriver driver, boolean useDevicePixelRatio) { this.driver = driver; - if(useDevicePixelRatio) { + if (useDevicePixelRatio) { Object devicePixelRatio = executeJsScript(DEVICE_PIXEL_RATIO); - this.devicePixelRatio = devicePixelRatio instanceof Double? (Double)devicePixelRatio: (Long)devicePixelRatio*1.0; + this.devicePixelRatio = devicePixelRatio instanceof Double ? (Double) devicePixelRatio : (Long) devicePixelRatio * 1.0; } } @@ -67,15 +71,15 @@ public Double getDevicePixelRatio() { return devicePixelRatio; } - public static void wait(int milis) { + public static void wait(int ms) { try { - Thread.sleep(milis); + Thread.sleep(ms); } catch (InterruptedException e) { throw new UnableTakeSnapshotException(e); } } - public void setScrollTimeout(int scrollTimeout){ + public void setScrollTimeout(int scrollTimeout) { this.scrollTimeout = scrollTimeout; } @@ -86,19 +90,21 @@ public BufferedImage takeScreenshot() { } catch (IOException e) { throw new UnableTakeSnapshotException(e); } finally { - // add this to clean up leaving this file in the temporary directory forever... - if (srcFile.exists()) { - srcFile.delete(); - } - } + // add this to clean up leaving this file in the temporary directory forever... + if (srcFile.exists()) { + srcFile.delete(); + } + } } - /**Using different screenshot strategy dependently on driver: + /** + * Using different screenshot strategy dependently on driver: * for chrome - chrome command will be used * for others - their default screenshot methods + * * @return BufferedImage resulting image - * */ + */ public BufferedImage takeScreenshotEntirePage() { if (driver instanceof EventFiringWebDriver) { driver = ((EventFiringWebDriver) this.driver).getWrappedDriver(); @@ -116,20 +122,20 @@ public BufferedImage takeScreenshotEntirePage() { public BufferedImage takeScreenshotEntirePageDefault() { final int _docWidth = this.getDocWidth(); - final int _docHeight = this.getDocHeight(); - BufferedImage combinedImage = new BufferedImage(_docWidth, _docHeight, BufferedImage.TYPE_INT_ARGB); + final int _docHeight = this.getDocHeight(); + BufferedImage combinedImage = new BufferedImage(_docWidth, _docHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D g = combinedImage.createGraphics(); int _viewportWidth = this.getViewportWidth(); int _viewportHeight = this.getViewportHeight(); final int scrollBarMaxWidth = 40; // this is probably too high, but better to be safe than sorry - if (_viewportWidth < _docWidth || (_viewportHeight < _docHeight && _viewportWidth - scrollBarMaxWidth < _docWidth)) - _viewportHeight-=scrollBarMaxWidth; // some space for a scrollbar + if (_viewportWidth < _docWidth || (_viewportHeight < _docHeight && _viewportWidth - scrollBarMaxWidth < _docWidth)) + _viewportHeight -= scrollBarMaxWidth; // some space for a scrollbar // TODO viewportHeight and scrollVarMaxWidth? if (_viewportHeight < _docHeight) - _viewportWidth-=scrollBarMaxWidth; // some space for a scrollbar + _viewportWidth -= scrollBarMaxWidth; // some space for a scrollbar - int horizontalIterations = (int) Math.ceil(((double) _docWidth) / _viewportWidth); - int verticalIterations = (int) Math.ceil(((double) _docHeight) / _viewportHeight); + int horizontalIterations = (int) Math.ceil(((double) _docWidth) / _viewportWidth); + int verticalIterations = (int) Math.ceil(((double) _docHeight) / _viewportHeight); outer_loop: for (int j = 0; j < verticalIterations; j++) { this.scrollTo(0, j * _viewportHeight); @@ -138,7 +144,7 @@ public BufferedImage takeScreenshotEntirePageDefault() { wait(scrollTimeout); Image image = takeScreenshot(); g.drawImage(image, this.getCurrentScrollX(), this.getCurrentScrollY(), null); - if(_docWidth == image.getWidth(null) && _docHeight == image.getHeight(null)){ + if (_docWidth == image.getWidth(null) && _docHeight == image.getHeight(null)) { break outer_loop; } } @@ -150,7 +156,7 @@ public BufferedImage takeScreenshotEntirePageDefault() { public BufferedImage takeScreenshotEntirePageUsingChromeCommand() { //should use devicePixelRatio by default as chrome command executor makes screenshot account for that Object devicePixelRatio = executeJsScript(DEVICE_PIXEL_RATIO); - this.devicePixelRatio = devicePixelRatio instanceof Double? (Double)devicePixelRatio: (Long)devicePixelRatio*1.0; + this.devicePixelRatio = devicePixelRatio instanceof Double ? (Double) devicePixelRatio : (Long) devicePixelRatio * 1.0; try { CommandInfo cmd = new CommandInfo("/session/:sessionId/chromium/send_command_and_get_result", HttpMethod.POST); @@ -186,31 +192,36 @@ public WebDriver getUnderlyingDriver() { } public int getCurrentScrollX() { - return (int)(((Long) executeJsScript(Browser.CURRENT_SCROLL_X_JS))*devicePixelRatio); + return (int) (((Long) executeJsScript(Browser.CURRENT_SCROLL_X_JS)) * devicePixelRatio); } public int getCurrentScrollY() { - return (int)(((Long) executeJsScript(Browser.CURRENT_SCROLL_Y_JS))*devicePixelRatio); + return (int) (((Long) executeJsScript(Browser.CURRENT_SCROLL_Y_JS)) * devicePixelRatio); } public int getDocWidth() { - return docWidth != -1 ? docWidth : (int)(((Long) executeJsScript(MAX_DOC_WIDTH_JS))*devicePixelRatio); + if (docWidth == -1) docWidth = (int) (((Long) executeJsScript(MAX_DOC_WIDTH_JS)) * devicePixelRatio); + return docWidth; } public int getDocHeight() { - return docHeight != -1 ? docHeight : (int)(((Long) executeJsScript(MAX_DOC_HEIGHT_JS))*devicePixelRatio); + if (docHeight == -1) docHeight = (int) (((Long) executeJsScript(MAX_DOC_HEIGHT_JS)) * devicePixelRatio); + return docHeight; } public int getViewportWidth() { - return viewportWidth != -1 ? viewportWidth : (int)(((Long) executeJsScript(VIEWPORT_WIDTH_JS))*devicePixelRatio); + if (viewportWidth == -1) viewportWidth = (int) (((Long) executeJsScript(VIEWPORT_WIDTH_JS)) * devicePixelRatio); + return viewportWidth; } public int getViewportHeight() { - return viewportHeight != -1 ? viewportHeight : (int)(((Long) executeJsScript(VIEWPORT_HEIGHT_JS)).intValue()*devicePixelRatio); + if (viewportHeight == -1) + viewportHeight = (int) (((Long) executeJsScript(VIEWPORT_HEIGHT_JS)) * devicePixelRatio); + return viewportHeight; } public Coordinates getBoundingClientRect(WebElement element) { - String script = FileUtil.getJsScript(RELATIVE_COORDS_JS); + FileUtil.getJsScript(RELATIVE_COORDS_JS); ArrayList list = (ArrayList) executeJsScript(RELATIVE_COORDS_JS, element); Point start = new Point(Integer.parseInt(list.get(0)), Integer.parseInt(list.get(1))); Dimension size = new Dimension(Integer.parseInt(list.get(2)), Integer.parseInt(list.get(3))); @@ -222,7 +233,7 @@ public void scrollToElement(WebElement element) { } public void scrollTo(int x, int y) { - executeJsScript(SCROLL_TO_JS, x/devicePixelRatio, y/devicePixelRatio); + executeJsScript(SCROLL_TO_JS, x / devicePixelRatio, y / devicePixelRatio); } public Object executeJsScript(String filePath, Object... arg) { diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java index 5d17f9b..1295e32 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java @@ -14,10 +14,10 @@ */ public class Coordinates { - private int width; - private int height; - private int x; - private int y; + private final int width; + private final int height; + private final int x; + private final int y; public Coordinates(WebElement element, Double devicePixelRatio) { Point point = element.getLocation(); diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java index e980f99..82b05c7 100644 --- a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java +++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java @@ -4,6 +4,7 @@ * Created by Glib_Briia on 10/07/2016. */ public class ElementOutsideViewportException extends RuntimeException { + public ElementOutsideViewportException() { super(); } diff --git a/src/main/resources/js/all-metrics.js b/src/main/resources/js/all-metrics.js index f0ddafe..e9c87b4 100644 --- a/src/main/resources/js/all-metrics.js +++ b/src/main/resources/js/all-metrics.js @@ -1,3 +1,5 @@ -({width: Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)|0, -height: Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)|0, -deviceScaleFactor: window.devicePixelRatio || 1,mobile: typeof window.orientation !== 'undefined'}) +({ + width: Math.max(window.innerWidth, document.body.scrollWidth, document.documentElement.scrollWidth) | 0, + height: Math.max(window.innerHeight, document.body.scrollHeight, document.documentElement.scrollHeight) | 0, + deviceScaleFactor: window.devicePixelRatio || 1, mobile: typeof window.orientation !== 'undefined' +}); diff --git a/src/main/resources/js/relative-element-coords.js b/src/main/resources/js/relative-element-coords.js index 42770d8..67d74f2 100644 --- a/src/main/resources/js/relative-element-coords.js +++ b/src/main/resources/js/relative-element-coords.js @@ -1,2 +1,2 @@ -var rect = arguments[0].getBoundingClientRect(); -return [ '' + parseInt(rect.left), '' + parseInt(rect.top), '' + parseInt(rect.width), '' + parseInt(rect.height) ] \ No newline at end of file +var rect = arguments[0].getBoundingClientRect(); +return ['' + parseInt(rect.left), '' + parseInt(rect.top), '' + parseInt(rect.width), '' + parseInt(rect.height)]; \ No newline at end of file diff --git a/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java b/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java index 9f46121..5515f3e 100644 --- a/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java +++ b/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java @@ -19,7 +19,6 @@ import com.assertthat.selenium_shutterbug.utils.web.Coordinates; import org.junit.Ignore; import org.junit.Test; -import org.openqa.selenium.*; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; @@ -28,7 +27,7 @@ import java.awt.image.BufferedImage; import java.io.IOException; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; /** * Created by Glib_Briia, Inha Briia on 26/06/2016.