Subversion Repositories SmartDukaan

Rev

Rev 36583 | Rev 37424 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36583 Rev 37423
Line 6... Line 6...
6
import org.apache.logging.log4j.Logger;
6
import org.apache.logging.log4j.Logger;
7
import org.opencv.core.Mat;
7
import org.opencv.core.Mat;
8
import org.opencv.core.Size;
8
import org.opencv.core.Size;
9
import org.opencv.imgcodecs.Imgcodecs;
9
import org.opencv.imgcodecs.Imgcodecs;
10
import org.opencv.imgproc.Imgproc;
10
import org.opencv.imgproc.Imgproc;
-
 
11
import org.json.JSONObject;
11
import org.openqa.selenium.*;
12
import org.openqa.selenium.*;
12
import org.openqa.selenium.chrome.ChromeDriver;
13
import org.openqa.selenium.chrome.ChromeDriver;
13
import org.openqa.selenium.chrome.ChromeOptions;
14
import org.openqa.selenium.chrome.ChromeOptions;
14
import org.openqa.selenium.interactions.Actions;
15
import org.openqa.selenium.interactions.Actions;
15
import org.openqa.selenium.support.ui.ExpectedConditions;
16
import org.openqa.selenium.support.ui.ExpectedConditions;
Line 91... Line 92...
91
            WebDriverWait wait5Sec = new WebDriverWait(driver, 4);
92
            WebDriverWait wait5Sec = new WebDriverWait(driver, 4);
92
            WebElement slideButton;
93
            WebElement slideButton;
93
            Actions actionProvider = new Actions(driver);
94
            Actions actionProvider = new Actions(driver);
94
            do {
95
            do {
95
                driver.get("https://www.realme.com/in/support/phonecheck");
96
                driver.get("https://www.realme.com/in/support/phonecheck");
-
 
97
                installResponseCapture(driver);
96
            /*try {
98
            /*try {
97
                driver.findElement(By.cssSelector(".cp-cookie-tip a.close")).click();
99
                driver.findElement(By.cssSelector(".cp-cookie-tip a.close")).click();
98
            } catch (Exception e) {
100
            } catch (Exception e) {
99
                try {
101
                try {
100
                    System.out.println("Cookie not found");
102
                    LOGGER.info("Cookie not found");
101
                } catch (Exception e1) {
103
                } catch (Exception e1) {
102
                }
104
                }
103
            }*/
105
            }*/
104
 
106
 
105
                for (int i = 0; i < remainingImeis.size(); i++) {
107
                for (int i = 0; i < remainingImeis.size(); i++) {
106
                    String imei = remainingImeis.get(i);
108
                    String imei = remainingImeis.get(i);
107
                    try {
109
                    try {
108
                        System.out.println("Starting fresh with new IMEI " + imei);
110
                        LOGGER.info("Starting fresh with new IMEI " + imei);
-
 
111
                        // realme rebuilt this page: the field is no longer .sn-input and the
-
 
112
                        // submit is no longer div.check-btn but an icon inside the same box.
109
                        if (driver.findElement(By.className("sn-input")).getAttribute("value").length() > 0) {
113
                        if (driver.findElement(By.cssSelector(IMEI_INPUT)).getAttribute("value").length() > 0) {
110
                            //System.out.println("Darn.. leaving" + driver.findElement(By.className("el-input__inner")).getAttribute("value"));
114
                            //System.out.println("Darn.. leaving" + driver.findElement(By.className("el-input__inner")).getAttribute("value"));
111
                            driver.get("https://www.realme.com/in/support/phonecheck");
115
                            driver.get("https://www.realme.com/in/support/phonecheck");
-
 
116
                installResponseCapture(driver);
112
                            break;
117
                            break;
113
                        }
118
                        }
114
                        driver.findElement(By.className("sn-input")).sendKeys(imei);
119
                        driver.findElement(By.cssSelector(IMEI_INPUT)).sendKeys(imei);
115
 
120
 
116
                        //driver.findElement(By.className("el-button--primary")).click();
121
                        //driver.findElement(By.className("el-button--primary")).click();
117
                        driver.findElement(By.cssSelector("div.check-btn")).click();
122
                        driver.findElement(By.cssSelector(SUBMIT_ICON)).click();
118
 
123
 
119
                        // Perform click-and-hold action on the element
124
                        // Perform click-and-hold action on the element
120
                        int counter = 1;
125
                        int counter = 1;
121
                        boolean captchaNotBroken = true;
126
                        boolean captchaNotBroken = true;
122
                        do {
127
                        do {
123
                            String fileName = "/tmp/oppo-simple-i-" + counter + " " + System.currentTimeMillis() + ".png";
128
                            String fileName = "/tmp/oppo-simple-i-" + counter + " " + System.currentTimeMillis() + ".png";
124
                            try {
129
                            try {
125
                                System.out.println("Starting Do");
130
                                LOGGER.info("Starting Do");
126
                                //Thread.sleep(5000);
131
                                //Thread.sleep(5000);
127
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.tagName("canvas")));
132
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.tagName("canvas")));
128
 
133
 
129
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_bg_')]")));
134
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_bg_')]")));
130
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_wrapper_')]")));
135
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_wrapper_')]")));
131
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]")));
136
                                wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]")));
132
                                slideButton = driver.findElement(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]"));
137
                                slideButton = driver.findElement(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]"));
133
                                //System.out.println("Slide button - " + slideButton);
138
                                //System.out.println("Slide button - " + slideButton);
134
                                System.out.println("Margin Left before- " + slideButton.getCssValue("margin-left"));
139
                                LOGGER.info("Margin Left before- " + slideButton.getCssValue("margin-left"));
135
                                actionProvider.moveToElement(slideButton).clickAndHold()
140
                                actionProvider.moveToElement(slideButton).clickAndHold()
136
                                        .moveByOffset(1, 0)//.pause(2000)
141
                                        .moveByOffset(1, 0)//.pause(2000)
137
                                        .perform();
142
                                        .perform();
138
 
143
 
139
                                //actionProvider.moveByOffset(-1,0).pause(2000).perform();
144
                                //actionProvider.moveByOffset(-1,0).pause(2000).perform();
140
                                System.out.println("Margin Left after - " + slideButton.getCssValue("margin-left"));
145
                                LOGGER.info("Margin Left after - " + slideButton.getCssValue("margin-left"));
141
                                //Thread.sleep(5000);
146
                                //Thread.sleep(5000);
142
                            } catch (Exception e) {
147
                            } catch (Exception e) {
143
                                System.out.println(e.getMessage());
148
                                LOGGER.info(e.getMessage());
144
                                driver.get("https://www.realme.com/in/support/phonecheck");
149
                                driver.get("https://www.realme.com/in/support/phonecheck");
-
 
150
                installResponseCapture(driver);
145
                                break;
151
                                break;
146
                            }
152
                            }
147
                            double[] circles = getMatCircles2(driver, fileName);
153
                            double[] circles = getMatCircles2(driver, fileName);
148
                            if (circles != null) {
154
                            if (circles != null) {
149
                                double firstCircleX = circles[0];
155
                                double firstCircleX = circles[0];
150
                                double secondCircleX = circles[1];
156
                                double secondCircleX = circles[1];
151
                                double distance = Math.abs(firstCircleX - secondCircleX);
157
                                double distance = Math.abs(firstCircleX - secondCircleX);
152
                                System.out.println("Distance is " + distance);
158
                                LOGGER.info("Distance is " + distance);
153
 
159
 
154
                                System.out.println("Starting Checkdistance method");
160
                                double[] cal = calibrate(driver, actionProvider, distance);
155
                                int moveByOffset = checkDistance(driver, wait10Sec, actionProvider, distance, slideButton);
161
                                int moveByOffset = cal == null ? 0 : (int) cal[0];
156
                                if (moveByOffset > 0) {
162
                                if (moveByOffset > 0) {
157
                                    System.out.println("Margin Offset - " + slideButton.getCssValue("margin-left"));
163
                                    // Move, measure again, close the remainder, THEN release.
158
                                    System.out.println("Ending Checkdistance method " + moveByOffset);
164
                                    actionProvider.moveByOffset(moveByOffset, 0).perform();
-
 
165
                                    refine(driver, actionProvider, cal[1]);
159
                                    actionProvider.moveByOffset(moveByOffset, 0).release().perform();
166
                                    actionProvider.release().perform();
160
                                    System.out.println("Move click performed");
167
                                    LOGGER.info("Move click performed (main {}px)", moveByOffset);
161
                                    try {
168
                                    try {
162
                                        try {
169
                                        try {
163
                                            wait5Sec.until(ExpectedConditions.visibilityOfElementLocated(By.className("dx_captcha_basic_bar-inform")));
170
                                            wait5Sec.until(ExpectedConditions.visibilityOfElementLocated(By.className("dx_captcha_basic_bar-inform")));
164
                                            System.out.println("Failed = " + counter);
171
                                            LOGGER.warn("Failed = " + counter);
165
                                        } catch (Exception notFailedException) {
172
                                        } catch (Exception notFailedException) {
166
                                            System.out.println("Success  at attempt " + counter);
173
                                            LOGGER.info("Success  at attempt " + counter);
167
                                            //List<WebElement> warrantyDateElements = driver.findElements(By.className("warranty-service--result_info__dateValue"));
174
                                            //List<WebElement> warrantyDateElements = driver.findElements(By.className("warranty-service--result_info__dateValue"));
168
                                            //WebElement activationTimeElement = driver.findElement(By.xpath("//*[contains(text(), 'UTC+5.5')  or contains(text(), 'Non-Activate')]"));
175
                                            //WebElement activationTimeElement = driver.findElement(By.xpath("//*[contains(text(), 'UTC+5.5')  or contains(text(), 'Non-Activate')]"));
169
                                            WebElement warrantyStatus = driver.findElement(By.xpath(
176
                                            // Read the JSON the page already received. The old locator
-
 
177
                                            // keyed off a label that no longer exists, and its "| //h1" branch
170
                                                    "//label[text()='Estimated Warranty Expiration Date']/following-sibling::div/span | //h1[contains(@class, 'title')]"));
178
                                            // would silently grab a page heading and try to parse it as a date.
-
 
179
                                            // The API is explicit: expiryDate (yyyy.MM.dd) plus an isActivation
-
 
180
                                            // flag, so nothing has to be inferred from message text.
-
 
181
                                            String json = capturedResponse(driver);
-
 
182
                                            LocalDate activationDate = activationFrom(json);
171
 
183
 
172
                                            //TODO: IF not found activationElement
-
 
173
                                            if (warrantyStatus != null) {
184
                                            if (json == null) {
174
                                                String activationDateString = warrantyStatus.getText().trim();
-
 
175
                                                System.out.println("Date --  " + activationDateString);
185
                                                LOGGER.warn("Result shown but no active/check response captured for imei {}", imei);
176
                                                try {
-
 
177
                                                    dateMap.put(imei, LocalDate.parse(activationDateString.split(" ")[0], DateTimeFormatter.ofPattern("yyyy.MM.dd")).minusYears(1));
-
 
178
                                                    System.out.println("Date --  " + activationDateString);
-
 
179
                                                } catch (Exception e) {
-
 
180
                                                    dateMap.put(imei, null);
-
 
181
                                                }
-
 
182
                                            } else {
186
                                            } else {
183
                                                System.out.println("Could not capture date");
187
                                                LOGGER.info("Activation lookup for {} -> {}", imei,
184
                                                dateMap.put(imei, null);
188
                                                        activationDate != null ? activationDate : "not activated");
185
                                            }
189
                                            }
-
 
190
                                            // Always record, even with a null date. findElement used to THROW
-
 
191
                                            // when the element was missing, so nothing was written and the imei
-
 
192
                                            // came back on every run indefinitely.
-
 
193
                                            dateMap.put(imei, activationDate);
-
 
194
                                            clearCapture(driver);
-
 
195
 
186
                                            if (dateMap.size() == imeis.size()) {
196
                                            if (dateMap.size() == imeis.size()) {
187
                                                return dateMap;
197
                                                return dateMap;
188
                                            }
198
                                            }
189
                                            WebElement checkAgainButton = driver.findElement(By.className("recheck-btn"));
199
                                            WebElement checkAgainButton = driver.findElement(By.className("recheck-btn"));
190
                                            captchaNotBroken = false;
200
                                            captchaNotBroken = false;
191
                                            checkAgainButton.click();
201
                                            checkAgainButton.click();
192
                                            break;
202
                                            break;
193
                                        }
203
                                        }
194
                                    } catch (Throwable e) {
204
                                    } catch (Throwable e) {
195
                                        System.out.println("Failed = " + counter + " ----------" + e.getMessage());
205
                                        LOGGER.warn("Failed = " + counter + " ----------" + e.getMessage());
196
                                    }
206
                                    }
197
                                }
207
                                }
198
                            }
208
                            }
199
                            System.out.println("After circles conditions");
209
                            LOGGER.info("After circles conditions");
200
                            wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_wrapper_')]")));
210
                            wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_wrapper_')]")));
201
                            wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]")));
211
                            wait10Sec.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]")));
202
                            slideButton = driver.findElement(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]"));
212
                            slideButton = driver.findElement(By.xpath("//*[starts-with(@id, 'dx_captcha_basic_slider_')]"));
203
                            actionProvider.moveToElement(slideButton).doubleClick().perform();
213
                            actionProvider.moveToElement(slideButton).doubleClick().perform();
204
                            System.out.println("Ending Do" + counter++);
214
                            LOGGER.info("Ending Do" + counter++);
205
 
215
 
206
                        } while (captchaNotBroken && counter <= 20);
216
                        } while (captchaNotBroken && counter <= 20);
207
                        System.out.println("Counter reached upto 20");
217
                        LOGGER.warn("Counter reached upto 20");
208
                    } catch (Exception e) {
218
                    } catch (Exception e) {
209
                        System.out.println("Caught unknown - for imei " + imei);
219
                        LOGGER.info("Caught unknown - for imei " + imei);
210
                        e.printStackTrace();
220
                        LOGGER.error("Realme warranty check failed for imei " + imei, e);
211
                    }
221
                    }
212
                    driver.get("https://www.realme.com/in/support/phonecheck");
222
                    driver.get("https://www.realme.com/in/support/phonecheck");
-
 
223
                installResponseCapture(driver);
213
                }
224
                }
214
                mainCount++;
225
                mainCount++;
215
                remainingImeis = imeis.stream().filter(x -> !dateMap.containsKey(x)).collect(Collectors.toList());
226
                remainingImeis = imeis.stream().filter(x -> !dateMap.containsKey(x)).collect(Collectors.toList());
216
                if (remainingImeis.isEmpty()) break;
227
                if (remainingImeis.isEmpty()) break;
217
            } while (mainCount < 5);
228
            } while (mainCount < 5);
218
        } finally {
229
        } finally {
219
            if (driver != null) {
230
            if (driver != null) {
220
                try {
231
                try {
221
                    driver.quit();  // Always shuts everything down
232
                    driver.quit();  // Always shuts everything down
222
                } catch (Exception e) {
233
                } catch (Exception e) {
223
                    System.out.println("Error closing driver: " + e.getMessage());
234
                    LOGGER.warn("Error closing driver: " + e.getMessage());
224
                }
235
                }
225
            }
236
            }
226
        }
237
        }
227
 
238
 
228
        return dateMap;
239
        return dateMap;
229
    }
240
    }
230
 
241
 
231
 
242
 
-
 
243
    /** realme rebuilt the page; the old .sn-input / div.check-btn no longer render. */
-
 
244
    private static final String IMEI_INPUT  = ".imei-input input";
-
 
245
    private static final String SUBMIT_ICON = ".imei-input .search-icon";
-
 
246
 
-
 
247
    /**
-
 
248
     * Slider px to nudge while working out how far the puzzle piece travels per slider px.
-
 
249
     * Was 15, which is why the captcha solved so rarely: the piece moves ~1.7px per slider
-
 
250
     * px, so 15px closed the gap by only ~25px, and Hough detection is worth +/-2-3px per
-
 
251
     * circle -- a ratio derived from a measurement ~20% wrong, then multiplied across the
-
 
252
     * whole remaining travel. 60px closes ~100px, so the same noise is ~5%.
-
 
253
     */
-
 
254
    private static final int CALIBRATION_NUDGE = 60;
-
 
255
    private static final double ALIGNED_PX = 2.0;
-
 
256
 
-
 
257
    /** Stash the active/check response on window as the page receives it. */
-
 
258
    private void installResponseCapture(WebDriver driver) {
-
 
259
        try {
-
 
260
            ((JavascriptExecutor) driver).executeScript(
-
 
261
                "if (!window.__rmCapInstalled) {"
-
 
262
              + "  window.__rmCapInstalled = true; window.__rmResp = null;"
-
 
263
              + "  var O = XMLHttpRequest.prototype.open;"
-
 
264
              + "  XMLHttpRequest.prototype.open = function(m,u){"
-
 
265
              + "    this.addEventListener('load', function(){"
-
 
266
              + "      try { if (String(u).indexOf('active/check') !== -1) window.__rmResp = this.responseText; } catch(e){}"
-
 
267
              + "    });"
-
 
268
              + "    return O.apply(this, arguments);"
-
 
269
              + "  };"
-
 
270
              + "}");
-
 
271
        } catch (Exception e) {
-
 
272
            LOGGER.warn("Could not install the response capture hook: " + e.getMessage());
-
 
273
        }
-
 
274
    }
-
 
275
 
-
 
276
    private String capturedResponse(WebDriver driver) {
-
 
277
        try {
-
 
278
            Object v = ((JavascriptExecutor) driver).executeScript("return window.__rmResp || null;");
-
 
279
            return v == null ? null : v.toString();
-
 
280
        } catch (Exception e) {
-
 
281
            return null;
-
 
282
        }
-
 
283
    }
-
 
284
 
-
 
285
    private void clearCapture(WebDriver driver) {
-
 
286
        try {
-
 
287
            ((JavascriptExecutor) driver).executeScript("window.__rmResp = null;");
-
 
288
        } catch (Exception ignored) {
-
 
289
        }
-
 
290
    }
-
 
291
 
-
 
292
    /**
-
 
293
     * realme returns the WARRANTY EXPIRY, not the activation date, so a year is
-
 
294
     * subtracted -- warranty is 12 months as standard. Verified against our own
-
 
295
     * records: 41,267 of 41,289 stored Realme activation dates precede the date we
-
 
296
     * checked them, averaging 13 days before, which is only consistent with the
-
 
297
     * subtraction being applied. isActivation false means the device is not
-
 
298
     * activated yet and there is no date to derive.
-
 
299
     */
-
 
300
    private LocalDate activationFrom(String json) {
-
 
301
        if (json == null) return null;
-
 
302
        try {
-
 
303
            JSONObject root = new JSONObject(json);
-
 
304
            JSONObject data = root.optJSONObject("data");
-
 
305
            if (data == null) return null;
-
 
306
            if (!data.optBoolean("isActivation", false)) return null;
-
 
307
 
-
 
308
            String expiry = data.optString("expiryDate", "");
-
 
309
            if (expiry == null || expiry.trim().isEmpty() || "null".equals(expiry)) return null;
-
 
310
 
-
 
311
            return LocalDate.parse(expiry.trim().split(" ")[0],
-
 
312
                    DateTimeFormatter.ofPattern("yyyy.MM.dd")).minusYears(1);
-
 
313
        } catch (Exception e) {
-
 
314
            LOGGER.warn("Could not read expiryDate from the realme response: " + e.getMessage());
-
 
315
            return null;
-
 
316
        }
-
 
317
    }
-
 
318
 
-
 
319
    /** @return {sliderPxToMove, sliderPxPerCirclePx}, or null if the circles were unreadable. */
232
    private int checkDistance(WebDriver driver, WebDriverWait wait3Sec, Actions actionProvider, double distance, WebElement slideButton) throws Exception {
320
    private double[] calibrate(WebDriver driver, Actions actionProvider, double distance) throws Exception {
-
 
321
        actionProvider.moveByOffset(CALIBRATION_NUDGE, 0).perform();
233
 
322
 
234
        //actionProvider.moveToElement(slideButton).clickAndHold().moveByOffset(1, 0).perform();
-
 
235
        actionProvider.moveByOffset(15, 0).perform();
-
 
236
        String fileName2 = "/tmp/" + Thread.currentThread().getName() + "-moved.png";
323
        String fileName2 = "/tmp/" + Thread.currentThread().getName() + "-moved.png";
237
        double[] movedCircles = getMatCircles2(driver, fileName2);
324
        double[] movedCircles = getMatCircles2(driver, fileName2);
238
        if (movedCircles == null) return 0;
325
        if (movedCircles == null) return null;
-
 
326
 
239
        double movedFirst = movedCircles[0];
327
        double movedDistance = Math.abs(movedCircles[0] - movedCircles[1]);
240
        double movedSecond = movedCircles[1];
328
        double closed = distance - movedDistance;
241
        //System.out.println("Test Offset Move " + testMove);
329
        LOGGER.info("Calibration: gap {} -> {} after {}px, closed {}",
242
        System.out.println("Found Moved " + movedFirst + " ," + movedSecond);
330
                distance, movedDistance, CALIBRATION_NUDGE, closed);
-
 
331
        if (closed <= 0) return null;
-
 
332
 
243
        double movedDistance = Math.abs(movedFirst - movedSecond);
333
        double sliderPerCircle = CALIBRATION_NUDGE / closed;
244
        double moved = distance - movedDistance;
334
        return new double[]{Math.round(movedDistance * sliderPerCircle), sliderPerCircle};
-
 
335
    }
-
 
336
 
245
		/*System.out.println("Original distance " + distance);
337
    /** Measure again after the main move and close the remainder before releasing. */
-
 
338
    private int refine(WebDriver driver, Actions actionProvider, double sliderPerCircle) throws Exception {
-
 
339
        String fileName = "/tmp/" + Thread.currentThread().getName() + "-refine.png";
246
		System.out.println("Moved Distance " + movedDistance);
340
        double[] circles = getMatCircles2(driver, fileName);
247
		System.out.println("Moved " + moved);*/
341
        if (circles == null) return 0;
-
 
342
 
-
 
343
        double remaining = Math.abs(circles[0] - circles[1]);
248
        if (moved == 0) return 0;
344
        if (remaining <= ALIGNED_PX) return 0;
-
 
345
 
249
        int moveBy = (int) ((movedDistance) * (15 / moved));
346
        int correction = (int) Math.round(remaining * sliderPerCircle);
250
        //int moveBy = (int) distance - 21;
347
        if (correction == 0) return 0;
-
 
348
        LOGGER.info("Refine: {}px of gap left -> nudging {}px", remaining, correction);
-
 
349
        actionProvider.moveByOffset(correction, 0).perform();
251
        return moveBy;
350
        return correction;
252
    }
351
    }
253
 
352
 
254
    private Mat getMatCircles(WebDriver driver, String fileName) throws Exception {
353
    private Mat getMatCircles(WebDriver driver, String fileName) throws Exception {
255
 
354
 
256
        File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
355
        File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);