How to use remember method of io.appium.java_client.ScreenshotState class

Best io.appium code snippet using io.appium.java_client.ScreenshotState.remember

Run io.appium automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

ScreenshotStateTests.java

Source: ScreenshotStateTests.java Github

copy
1package io.appium.java_client.utils;
2
3import static org.hamcrest.CoreMatchers.is;
4import static org.hamcrest.CoreMatchers.notNullValue;
5import static org.hamcrest.Matchers.greaterThanOrEqualTo;
6import static org.hamcrest.Matchers.lessThan;
7import static org.junit.Assert.assertThat;
8
9import io.appium.java_client.ScreenshotState;
10import org.junit.Before;
11import org.junit.Test;
12
13import java.awt.Color;
14import java.awt.Graphics2D;
15import java.awt.geom.Rectangle2D;
16import java.awt.image.BufferedImage;
17import java.time.Duration;
18import java.util.Random;
19
20public class ScreenshotStateTests {
21    private static final Random rand = new Random();
22    private static final Duration ONE_SECOND = Duration.ofSeconds(1);
23    private static final double MAX_SCORE = 0.999;
24
25    private ImagesGenerator randomImageOfStaticSize;
26    private ImagesGenerator randomImageOfRandomSize;
27    private ImagesGenerator staticImage;
28
29    private static class ImagesGenerator {
30        private boolean isRandom;
31        private boolean isSizeStatic;
32
33        private static final int DEFAULT_WIDTH = 100;
34        private static final int MIN_WIDTH = 50;
35        private static final int DEFAULT_HEIGHT = 100;
36        private static final int MIN_HEIGHT = 50;
37
38        ImagesGenerator(boolean isRandom, boolean isSizeStatic) {
39            this.isRandom = isRandom;
40            this.isSizeStatic = isSizeStatic;
41        }
42
43        private BufferedImage generate() {
44            final int width = isSizeStatic ? DEFAULT_WIDTH : MIN_WIDTH + rand.nextInt(DEFAULT_WIDTH);
45            final int height = isSizeStatic ? DEFAULT_HEIGHT : MIN_HEIGHT + rand.nextInt(DEFAULT_HEIGHT);
46            final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
47            final Graphics2D g2 = result.createGraphics();
48            try {
49                g2.setColor(isRandom ? new Color(rand.nextInt(256), rand.nextInt(256),
50                        rand.nextInt(256)) : Color.red);
51                g2.fill(new Rectangle2D.Float(0, 0,
52                        isRandom ? rand.nextInt(DEFAULT_WIDTH) : DEFAULT_WIDTH / 2,
53                        isRandom ? rand.nextInt(DEFAULT_HEIGHT) : DEFAULT_HEIGHT / 2));
54            } finally {
55                g2.dispose();
56            }
57            return result;
58        }
59    }
60
61    @Before
62    public void setUp() {
63        randomImageOfStaticSize = new ImagesGenerator(true, true);
64        randomImageOfRandomSize = new ImagesGenerator(true, false);
65        staticImage = new ImagesGenerator(false, true);
66    }
67
68    //region Positive Tests
69    @Test
70    public void testBasicComparisonScenario() {
71        final ScreenshotState currentState = new ScreenshotState(staticImage::generate)
72                .remember();
73        assertThat(currentState.verifyNotChanged(ONE_SECOND, MAX_SCORE), is(notNullValue()));
74    }
75
76    @Test
77    public void testChangedImageVerification() {
78        final ScreenshotState currentState = new ScreenshotState(randomImageOfStaticSize::generate)
79                .remember();
80        assertThat(currentState.verifyChanged(ONE_SECOND, MAX_SCORE), is(notNullValue()));
81    }
82
83    @Test
84    public void testChangedImageVerificationWithDifferentSize() {
85        final ScreenshotState currentState = new ScreenshotState(randomImageOfRandomSize::generate)
86                .remember();
87        assertThat(currentState.verifyChanged(ONE_SECOND, MAX_SCORE,
88                ScreenshotState.ResizeMode.REFERENCE_TO_TEMPLATE_RESOLUTION), is(notNullValue()));
89    }
90
91    @Test
92    public void testChangedImageVerificationWithCustomRememberedImage() {
93        final ScreenshotState currentState = new ScreenshotState(randomImageOfRandomSize::generate)
94                .remember(randomImageOfRandomSize.generate());
95        assertThat(currentState.verifyChanged(ONE_SECOND, MAX_SCORE,
96                ScreenshotState.ResizeMode.REFERENCE_TO_TEMPLATE_RESOLUTION), is(notNullValue()));
97    }
98
99    @Test
100    public void testChangedImageVerificationWithCustomInterval() {
101        final ScreenshotState currentState = new ScreenshotState(randomImageOfRandomSize::generate)
102                .setComparisonInterval(Duration.ofMillis(100)).remember();
103        assertThat(currentState.verifyChanged(ONE_SECOND, MAX_SCORE,
104                ScreenshotState.ResizeMode.REFERENCE_TO_TEMPLATE_RESOLUTION), is(notNullValue()));
105    }
106
107    @Test
108    public void testDirectOverlapScoreCalculation() {
109        final BufferedImage anImage = staticImage.generate();
110        final double score = ScreenshotState.getOverlapScore(anImage, anImage);
111        assertThat(score, is(greaterThanOrEqualTo(MAX_SCORE)));
112    }
113
114    @Test
115    public void testScreenshotComparisonUsingStaticMethod() {
116        BufferedImage img1 = randomImageOfStaticSize.generate();
117        // ImageIO.write(img1, "png", new File("img1.png"));
118        BufferedImage img2 = randomImageOfStaticSize.generate();
119        // ImageIO.write(img2, "png", new File("img2.png"));
120        assertThat(ScreenshotState.getOverlapScore(img1, img2), is(lessThan(MAX_SCORE)));
121    }
122    //endregion
123
124    //region Negative Tests
125    @Test(expected = ScreenshotState.ScreenshotComparisonError.class)
126    public void testDifferentSizeOfTemplates() {
127        new ScreenshotState(randomImageOfRandomSize::generate).remember().verifyChanged(ONE_SECOND, MAX_SCORE);
128    }
129
130    @Test(expected = NullPointerException.class)
131    public void testInvalidProvider() {
132        new ScreenshotState(() -> null).remember();
133    }
134
135    @Test(expected = ScreenshotState.ScreenshotComparisonTimeout.class)
136    public void testImagesComparisonExpectationFailed() {
137        new ScreenshotState(randomImageOfStaticSize::generate).remember().verifyNotChanged(ONE_SECOND, MAX_SCORE);
138    }
139
140    @Test(expected = ScreenshotState.ScreenshotComparisonTimeout.class)
141    public void testImagesComparisonExpectationFailed2() {
142        new ScreenshotState(staticImage::generate).remember().verifyChanged(ONE_SECOND, MAX_SCORE);
143    }
144
145    @Test(expected = ScreenshotState.ScreenshotComparisonError.class)
146    public void testScreenshotInitialStateHasNotBeenRemembered() {
147        new ScreenshotState(staticImage::generate).verifyNotChanged(ONE_SECOND, MAX_SCORE);
148    }
149    //endregion
150}
151
Full Screen

ScreenshotState.java

Source: ScreenshotState.java Github

copy
1package utils;
2import io.appium.java_client.ComparesImages;
3
4import static com.google.common.base.Preconditions.checkNotNull;
5import static java.util.Optional.ofNullable;
6
7import java.awt.image.BufferedImage;
8import java.io.ByteArrayOutputStream;
9import java.io.IOException;
10import java.time.Duration;
11import java.time.LocalDateTime;
12import java.util.Base64;
13import java.util.function.Function;
14import java.util.function.Supplier;
15
16import javax.imageio.ImageIO;
17
18public class ScreenshotState {
19    private static final Duration DEFAULT_INTERVAL_MS = Duration.ofMillis(500);
20
21    private BufferedImage previousScreenshot;
22    private final Supplier<BufferedImage> stateProvider;
23    private final ComparesImages comparator;
24
25    private Duration comparisonInterval = DEFAULT_INTERVAL_MS;
26
27    /**
28     * The class constructor accepts two arguments. The first one is image comparator, the second
29     * parameter is lambda function, that provides the screenshot of the necessary
30     * screen area to be verified for similarity.
31     * This lambda method is NOT called upon class creation.
32     * One has to invoke {@link #remember()} method in order to call it.
33     *
34     * <p>Examples of provider function with Appium driver:
35     * <code>
36     * () -&gt; {
37     * final byte[] srcImage = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
38     * return ImageIO.read(new ByteArrayInputStream(srcImage));
39     * }
40     * </code>
41     * or
42     * <code>
43     * () -&gt; {
44     * final byte[] srcImage = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
45     * final BufferedImage screenshot = ImageIO.read(new ByteArrayInputStream(srcImage));
46     * final WebElement element = driver.findElement(locator);
47     * // Can be simplified in Selenium 3.0+ by using getRect method of WebElement interface
48     * final Point elementLocation = element.getLocation();
49     * final Dimension elementSize = element.getSize();
50     * return screenshot.getSubimage(
51     * new Rectangle(elementLocation.x, elementLocation.y, elementSize.width, elementSize.height);
52     * }
53     * </code>
54     *
55     * @param comparator image comparator
56     * @param stateProvider lambda function, which returns a screenshot for further comparison
57     */
58    public ScreenshotState(ComparesImages comparator, Supplier<BufferedImage> stateProvider) {
59        this.comparator = checkNotNull(comparator);
60        this.stateProvider = stateProvider;
61    }
62
63    public ScreenshotState(ComparesImages comparator) {
64        this(comparator, null);
65    }
66
67    /**
68     * Gets the interval value in ms between similarity verification rounds in <em>verify*</em> methods.
69     *
70     * @return current interval value in ms
71     */
72    public Duration getComparisonInterval() {
73        return comparisonInterval;
74    }
75
76    /**
77     * Sets the interval between similarity verification rounds in <em>verify*</em> methods.
78     *
79     * @param comparisonInterval interval value. 500 ms by default
80     * @return self instance for chaining
81     */
82    public ScreenshotState setComparisonInterval(Duration comparisonInterval) {
83        this.comparisonInterval = comparisonInterval;
84        return this;
85    }
86
87    /**
88     * Call this method to save the initial screenshot state.
89     * It is mandatory to call before any <em>verify*</em> method is invoked.
90     *
91     * @return self instance for chaining
92     */
93    public ScreenshotState remember() {
94        this.previousScreenshot = stateProvider.get();
95        return this;
96    }
97
98    /**
99     * This method allows to pass a custom bitmap for further comparison
100     * instead of taking one using screenshot provider function. This might
101     * be useful in some advanced cases.
102     *
103     * @param customInitialState valid bitmap
104     * @return self instance for chaining
105     */
106    public ScreenshotState remember(BufferedImage customInitialState) {
107        this.previousScreenshot = checkNotNull(customInitialState);
108        return this;
109    }
110
111    public static class ScreenshotComparisonError extends RuntimeException {
112        private static final long serialVersionUID = -7011854909939194466L;
113
114        ScreenshotComparisonError(Throwable reason) {
115            super(reason);
116        }
117
118        ScreenshotComparisonError(String message) {
119            super(message);
120        }
121    }
122
123    public static class ScreenshotComparisonTimeout extends RuntimeException {
124        private static final long serialVersionUID = 6336247721154252476L;
125        private final double currentScore;
126
127        ScreenshotComparisonTimeout(String message, double currentScore) {
128            super(message);
129            this.currentScore = currentScore;
130        }
131
132        public double getCurrentScore() {
133            return currentScore;
134        }
135    }
136
137    private ScreenshotState checkState(Function<Double, Boolean> checkerFunc, Duration timeout) {
138        final LocalDateTime started = LocalDateTime.now();
139        double score;
140        do {
141            final BufferedImage currentState = stateProvider.get();
142            score = getOverlapScore(ofNullable(this.previousScreenshot)
143                    .orElseThrow(() -> new ScreenshotComparisonError("Initial screenshot state is not set. "
144                            + "Nothing to compare")), currentState);
145            if (checkerFunc.apply(score)) {
146                return this;
147            }
148            try {
149                Thread.sleep(comparisonInterval.toMillis());
150            } catch (InterruptedException e) {
151                throw new ScreenshotComparisonError(e);
152            }
153        }
154        while (Duration.between(started, LocalDateTime.now()).compareTo(timeout) <= 0);
155        throw new ScreenshotComparisonTimeout(
156                String.format("Screenshot comparison timed out after %s ms. Actual similarity score: %.5f",
157                        timeout.toMillis(), score), score);
158    }
159
160    /**
161     * Verifies whether the state of the screenshot provided by stateProvider lambda function
162     * is changed within the given timeout.
163     *
164     * @param timeout  timeout value
165     * @param minScore the value in range (0.0, 1.0)
166     * @return self instance for chaining
167     * @throws ScreenshotComparisonTimeout if the calculated score is still
168     *                                     greater or equal to the given score after timeout happens
169     * @throws ScreenshotComparisonError   if {@link #remember()} method has not been invoked yet
170     */
171    public ScreenshotState verifyChanged(Duration timeout, double minScore) {
172        return checkState((x) -> x < minScore, timeout);
173    }
174
175    /**
176     * Verifies whether the state of the screenshot provided by stateProvider lambda function
177     * is not changed within the given timeout.
178     *
179     * @param timeout   timeout value
180     * @param minScore  the value in range (0.0, 1.0)
181     * @return self instance for chaining
182     * @throws ScreenshotComparisonTimeout if the calculated score is still
183     *                                     less than the given score after timeout happens
184     * @throws ScreenshotComparisonError   if {@link #remember()} method has not been invoked yet
185     */
186    public ScreenshotState verifyNotChanged(Duration timeout, double minScore) {
187        return checkState((x) -> x >= minScore, timeout);
188    }
189
190    /**
191     * Compares two valid java bitmaps and calculates similarity score between them.
192     * Both images are expected to be of the same size/resolution. The method
193     * implicitly invokes {@link ComparesImages#getImagesSimilarity(byte[], byte[])}.
194     *
195     * @param refImage   reference image
196     * @param tplImage   template
197     * @return similarity score value in range (-1.0, 1.0]. 1.0 is returned if the images are equal
198     * @throws ScreenshotComparisonError if provided images are not valid or have
199     *                                   different resolution
200     */
201    public double getOverlapScore(BufferedImage refImage, BufferedImage tplImage) {
202        try (ByteArrayOutputStream img1 = new ByteArrayOutputStream();
203             ByteArrayOutputStream img2 = new ByteArrayOutputStream()) {
204            ImageIO.write(refImage, "png", img1);
205            ImageIO.write(tplImage, "png", img2);
206            return comparator
207                    .getImagesSimilarity(Base64.getEncoder().encode(img1.toByteArray()),
208                            Base64.getEncoder().encode(img2.toByteArray()))
209                    .getScore();
210        } catch (IOException e) {
211            throw new ScreenshotComparisonError(e);
212        }
213    }
214}
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Most used method in ScreenshotState

Trigger remember code on LambdaTest Cloud Grid

Execute automation tests with remember on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)