{"id":683,"date":"2020-06-24T09:32:47","date_gmt":"2020-06-24T09:32:47","guid":{"rendered":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/?p=683"},"modified":"2020-06-24T19:57:23","modified_gmt":"2020-06-24T19:57:23","slug":"pimp-my-testautomation-part-2","status":"publish","type":"post","link":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/","title":{"rendered":"Pimp my testAUTOmation (Part 2)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Record videos of the test procedure<\/h2>\n\n\n\n<p>With this blog series I want to show how important functions can be built into selenium by using simple means. In the first part I introduced what Selenium 4 brings and how to use screenshots. In the second part we will create a video of the test execution. I try to evaluate the approaches according to their added value (The Good) and their challenges (The Bad) and to give useful hints (&#8230; and the Useful).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Why?<\/strong><\/h2>\n\n\n\n<p>But at the beginning we will briefly ask ourselves the question: Why record a video or screencast of the test performance?<\/p>\n\n\n\n<p>With a video we have a recording of the entire test run. Unlike with a screenshot, we can not only record the test result, but we can also trace the path to it.<\/p>\n\n\n\n<p>Like screenshots, the videos can also be used for debugging and point out problems during the test run. Therefore, as with the screenshot, it makes sense to create videos only when problems occur. Following this approach, the video functionality should be extended by a flexible and global switch that can be set as needed.<\/p>\n\n\n\n<p>But the videos can also be used to document the test results. In some projects a detailed documentation is even mandatory, because here legal or other requirements have to be met.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Recording video made easy<\/h2>\n\n\n\n<p>Since I use Java Selenium, my first approach was to record videos with the &#8220;in-house&#8221; functions of Java or to use a suitable framework. My first choice was the MonteCC framework, because it allowed me to record the screen during the test execution with the help of only two methods. In one method video recording is started before the test and in one method the recording is stopped after the test and the video is stored in the appropriate directory.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private ScreenRecorder screenRecorder;\n \n@BeforeEach\npublic void beforeTest() {\n \n    GraphicsConfiguration gc = GraphicsEnvironment\n            .getLocalGraphicsEnvironment()\n            .getDefaultScreenDevice()\n            .getDefaultConfiguration();\n \n    try {\n        this.screenRecorder = new ScreenRecorder(gc,\n                new Format(MediaTypeKey, MediaType.FILE, MimeTypeKey, MIME_AVI),\n                new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,\n                        CompressorNameKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE,\n                        DepthKey, 24, FrameRateKey, Rational.valueOf(15),\n                        QualityKey, 1.0f,\n                        KeyFrameIntervalKey, 15 * 60),\n                new Format(MediaTypeKey, MediaType.VIDEO, EncodingKey,\"black\",\n                        FrameRateKey, Rational.valueOf(30)),\n                null);\n        this.screenRecorder.start();\n \n    } catch (Exception e) {\n        System.out.println(\"screenRecorder.start \" + e.getMessage());\n    }\n}\n \n@AfterEach\npublic void afterTest()  {\n \n    try {\n        this.screenRecorder.stop();\n        List createdMovieFiles = screenRecorder.getCreatedMovieFiles();\n        for (Object movie: createdMovieFiles) {\n            File m = (File)movie;\n            System.out.println(\"New movie created: \" + m.getAbsolutePath());\n        }\n \n    } catch (IOException ioe) {\n        System.out.println(\"screenRecorder.stop \" + ioe.getMessage());\n    }\n}<\/code><\/pre>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>To make sure this happens before each test, we use the annotations of JUnit:<\/p>\n\n\n\n<p><em><strong>@Test<\/strong><\/em><\/p>\n\n\n\n<p><em>The method with the annotation @Test is a test case and is started during test execution and the result is recorded in the test log.<\/em><\/p>\n\n\n\n<p><em><strong>@BeforeEach<\/strong><\/em><\/p>\n\n\n\n<p><em>This method is called before each test execution (see @Test).<\/em><\/p>\n\n\n\n<p><em><strong>@AfterEach<\/strong><\/em><\/p>\n\n\n\n<p><em>This method is called after each test execution (see @Test).<\/em><\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>If you need a complete record of all test cases, you can also use the annotations @Before and @After, which are called before all or after all tests of an execution definition (test class).<\/p>\n\n\n\n<p>Major disadvantages of MonteCC are that the last release was more than six years ago and that the videos are in QuickTime format.<\/p>\n\n\n\n<p>JavaCV (<a href=\"https:\/\/github.com\/bytedeco\/javacv\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/bytedeco\/javacv<\/a>) offered itself as an alternative. The library is actively maintained in GitHub and stores videos in MPEG format. Again, there are two methods of video creation that can be called before and after the test. But JavaCV requires additional methods because screenshots are taken at short intervals parallel to the test run and then assembled into a video after the test. A detailed instruction can be found under the following link: <a href=\"https:\/\/cooltrickshome.blogspot.com\/2016\/12\/create-your-own-free-screen-recorder.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/cooltrickshome.blogspot.com\/2016\/12\/create-your-own-free-screen-recorder.html<\/a>.<\/p>\n\n\n\n<p>I have made the following changes for use in automated testing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/**\n *\n * https:\/\/github.com\/bytedeco\/javacv\n * https:\/\/cooltrickshome.blogspot.com\/2016\/12\/create-your-own-free-screen-recorder.html\n *\/\npublic class RecordSeleniumJavaCV {\n \n    \/\/ The WebDriver is a tool for writing automated tests of websites.\n    FirefoxDriver driver;\n \n    public static boolean videoComplete=false;\n    public static String inputImageDir= \"videos\" + File.separator + \"inputImgFolder\"+File.separator;\n    public static String inputImgExt=\"png\";\n    public static String outputVideoDir= \"videos\" + File.separator;\n    public static String outputVideo;\n    public static int counter=0;\n    public static int imgProcessed=0;\n    public static FFmpegFrameRecorder recorder=null;\n    public static int videoWidth=1920;\n    public static int videoHeight=1080;\n    public static int videoFrameRate=3;\n    public static int videoQuality=0; \/\/ 0 is the max quality\n    public static int videoBitRate=9000;\n    public static String videoFormat=\"mp4\";\n    public static int videoCodec=avcodec.AV_CODEC_ID_MPEG4;\n    public static Thread t1=null;\n    public static Thread t2=null;\n    public static boolean isRegionSelected=false;\n    public static int c1=0;\n    public static int c2=0;\n    public static int c3=0;\n    public static int c4=0;\n \n    \/**\n     * Explanation:\n     * 1) videoComplete variables tells if user has stopped the recording or not.\n     * 2) inputImageDir defines the input directory where screenshots will be stored which would be utilized by the video thread\n     * 3) inputImgExt denotes the extension of the image taken for screenshot.\n     * 4) outputVideo is the name of the recorded video file\n     * 5) counter is used for numbering the screenshots when stored in input directory.\n     * 6) recorder is used for starting and stopping the video recording\n     * 7) videoWidth, videoFrameRate etc define output video param\n     * 8) If user wants to record only a selected region then c1,c2,c3,c4 denotes the coordinate\n     *\n     * @return\n     * @throws Exception\n     *\/\n    public static FFmpegFrameRecorder getRecorder() throws Exception\n    {\n        if(recorder!=null)\n        {\n            return recorder;\n        }\n        recorder = new FFmpegFrameRecorder(outputVideo,videoWidth,videoHeight);\n        try\n        {\n            recorder.setFrameRate(videoFrameRate);\n            recorder.setVideoCodec(videoCodec);\n            recorder.setVideoBitrate(videoBitRate);\n            recorder.setFormat(videoFormat);\n            recorder.setVideoQuality(videoQuality); \/\/ maximum quality\n            recorder.start();\n        }\n        catch(Exception e)\n        {\n            System.out.println(\"Exception while starting the recorder object \"+e.getMessage());\n            throw new Exception(\"Unable to start recorder\");\n        }\n        return recorder;\n    }\n \n    \/**\n     * Explanation:\n     * 1) This method is used to get the Recorder object.\n     * 2) We create an object of FFmpegFrameRecorder named \"Recorder\" and then set all its video parameters.\n     * 3) Lastly we start the recorder and then return the object.\n     *\n     * @return\n     * @throws Exception\n     *\/\n    public static Robot getRobot() throws Exception\n    {\n        Robot r=null;\n        try {\n            r = new Robot();\n            return r;\n        } catch (AWTException e) {\n            System.out.println(\"Issue while initiating Robot object \"+e.getMessage());\n            throw new Exception(\"Issue while initiating Robot object\");\n        }\n    }\n \n    \/**\n     * Explanation:\n     * 1) Two threads are started in this module when user starts the recording\n     * 2) First thread calls the takeScreenshot module which keeps on taking screenshot of user screen and saves them on local disk.\n     * 3) Second thread calls the prepareVideo which monitors the screenshot created in step 2 and add them continuously on the video.\n     *\n     * @param r\n     *\/\n    public static void takeScreenshot(Robot r)\n    {\n        Dimension size = Toolkit.getDefaultToolkit().getScreenSize();\n        Rectangle rec=new Rectangle(size);\n        if(isRegionSelected)\n        {\n            rec=new Rectangle(c1, c2, c3-c1, c4-c2);\n        }\n        while(!videoComplete)\n        {\n            counter++;\n            BufferedImage img = r.createScreenCapture(rec);\n            try {\n                ImageIO.write(img, inputImgExt, new File(inputImageDir+counter+\".\"+inputImgExt));\n            } catch (IOException e) {\n                System.out.println(\"Got an issue while writing the screenshot to disk \"+e.getMessage());\n                counter--;\n            }\n        }\n    }\n \n    \/**\n     * Explanation:\n     * 1) If user has selected a region for recording then we set the rectangle with the coordinate value of c1,c2,c3,c4. Otherwise we set the rectangle to be full screen\n     * 2) Now we run a loop until videoComplete is false (remains false until user press stop recording.\n     * 3) Now we capture the region and write the same to the input image directory.\n     * 4) So when user starts the recording this method keeps on taking screenshot and saves them into disk.\n     *\n     *\/\n    public static void prepareVideo()\n    {\n        File scanFolder=new File(inputImageDir);\n        while(!videoComplete)\n        {\n            File&#91;] inputFiles=scanFolder.listFiles();\n            try {\n                getRobot().delay(500);\n            } catch (Exception e) {\n            }\n            \/\/for(int i=0;i&lt;scanFolder.list().length;i++)\n            for(int i=0;i&lt;inputFiles.length;i++)\n            {\n                \/\/imgProcessed++;\n                addImageToVideo(inputFiles&#91;i].getAbsolutePath());\n                \/\/String imgToAdd=scanFolder.getAbsolutePath()+File.separator+imgProcessed+\".\"+inputImgExt;\n                \/\/addImageToVideo(imgToAdd);\n                \/\/new File(imgToAdd).delete();\n                inputFiles&#91;i].delete();\n            }\n        }\n        File&#91;] inputFiles=scanFolder.listFiles();\n        for(int i=0;i&lt;inputFiles.length;i++)\n        {\n            addImageToVideo(inputFiles&#91;i].getAbsolutePath());\n            inputFiles&#91;i].delete();\n        }\n    }\n \n    \/**\n     * Explanation:\n     * 1) cvLoadImage is used to load the image passed as argument\n     * 2) We call the convert method to convert the image to frame which could be used by the recorder\n     * 3) We pass the frame obtained in step 2 and add the same in the recorder by calling the record method.\n     *\n     * @return\n     *\/\n    public static OpenCVFrameConverter.ToIplImage getFrameConverter()\n    {\n        OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();\n        return grabberConverter;\n    }\n \n    \/**\n     * Explanation:\n     * 1) We start a loop which will run until video complete is set true (done only when user press stop recording)\n     * 2) We keep on monitoring the input  Image directory\n     * 3) We traverse each file found in the input image directory and add those images to video using the addImageToVideo method. After the image has been added we delete the image\n     * 4) Using the loop in step1 we keep on repeating step 2 and 3 so that each image gets added to video. We added a delay of 500ms so that this module does not picks a half created image from the takeScreenshot module\n     * 5) When user press stop recording the loop gets broken. Now we finally traverse the input image directory and add the remaining images to video.\n     *\n     * @param imgPath\n     *\/\n    public static void addImageToVideo(String imgPath)\n    {\n        try {\n            getRecorder().record(getFrameConverter().convert(cvLoadImage(imgPath)));\n        } catch (Exception e) {\n            System.out.println(\"Exception while adding image to video \"+e.getMessage());\n        }\n    }\n \n    \/**\n     * Explanation:\n     * 1) We make a JFrame with the button for staring and stopping the recording. One more button is added for allowing user to record only a selected portion of screen\n     * 2) If user clicks to select only certain region then we call a class CropRegion method getImage which helps in retrieving the coordinate of the region selected by user and update the same in variable c1,c2,c3,c4\n     * 3) If user clicks on start recording then startRecording method is called\n     * 4) If user clicks on stoprecording then stopRecording method is called\n     *\/\n    @BeforeEach\n    public void beforeTest() {\n \n        System.out.println(\"this.screenRecorder.start()\");\n \n        SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyyMMdd_HHmmss\");\n        String timestamp  = dateFormat.format(new Date());\n \n        outputVideo= outputVideoDir + \"recording_\" + timestamp + \".mp4\";\n \n        try {\n            t1=new Thread()\n            {\n                public void run() {\n                    try {\n                        takeScreenshot(getRobot());\n                    } catch (Exception e) {\n                        System.out.println(\"Cannot make robot object, Exiting program \"+e.getMessage());\n                        System.exit(0);\n                    }\n                }\n            };\n            t2=new Thread()\n            {\n                public void run() {\n                    prepareVideo();\n                }\n            };\n            t1.start();\n            t2.start();\n            System.out.println(\"Started recording at \"+new Date());\n \n \n        } catch (Exception e) {\n            System.out.println(\"screenRecorder.start \" + e.getMessage());\n        }\n    }\n \n    @AfterEach\n    public void afterTest()  {\n \n        System.out.println(\"this.screenRecorder.stop()\");\n \n        try {\n            videoComplete=true;\n            System.out.println(\"Stopping recording at \"+new Date());\n            t1.join();\n            System.out.println(\"Screenshot thread complete\");\n            t2.join();\n            System.out.println(\"Video maker thread complete\");\n            getRecorder().stop();\n            System.out.println(\"Recording has been saved successfully at \"+new File(outputVideo).getAbsolutePath());\n \n        } catch (Exception e) {\n            System.out.println(\"screenRecorder.stop \" + e.getMessage());\n        }\n    }\n \n    @Test\n    public void testMe() {\n         \n        \/\/toDo\n \n    }\n \n}<\/code><\/pre>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Is there a catch?<\/h2>\n\n\n\n<p>So, we now have several possibilities to record the automatic test run in a video in order to be able to reproduce it in case of problems or to fulfil the documentation obligations.<\/p>\n\n\n\n<p>But recording during the test run is associated with a risk that the tester \/ test automator should keep in mind: It is an interference with the normal test run, because we might change the timing. Our modified test run with video recording may behave differently than a test run without video recording.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-text-align-center\"><strong>Videos of the test procedure<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table is-style-regular\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>The Good<\/strong><\/td><td><strong>The Bad<\/strong><\/td><td><strong>&#8230; and the Useful<\/strong><\/td><\/tr><tr><td>\u2022 Recording the entire test run<br>\u2022 In addition to the test result, the path to it can also be traced<br><br><br><\/td><td>\u2022 The test run is influenced<br>\u2022 Various old and paid frameworks for video recording<br>\u2022 Codec problems (QuicktimeView only)<\/td><td>\u2022 JavaCV \u2192<br><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/bytedeco\/javacv\" target=\"_blank\">github.com\/bytedeco\/javacv<\/a><br><br><br><br><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the second part of the blog series on Selenium we will create a video of the test execution. <\/p>\n","protected":false},"author":65,"featured_media":613,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","footnotes":""},"categories":[7],"tags":[131,215,301,338,339,340,341],"topics":[82],"class_list":["post-683","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-quality-assurance","tag-test-automation","tag-selenium","tag-selenium-4","tag-debugging","tag-montecc","tag-junit-annotations","tag-javacv","topics-test-automation"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Pimp my testAUTOmation (Part 2) - ZEISS Digital Innovation Blog<\/title>\n<meta name=\"description\" content=\"In the second part of the blog series about the extension of functions in Selenium 4 we create a video of the test execution.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Pimp my testAUTOmation (Part 2) - ZEISS Digital Innovation Blog\" \/>\n<meta property=\"og:description\" content=\"In the second part of the blog series about the extension of functions in Selenium 4 we create a video of the test execution.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Digital Innovation Blog\" \/>\n<meta property=\"article:published_time\" content=\"2020-06-24T09:32:47+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-06-24T19:57:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"806\" \/>\n\t<meta property=\"og:image:height\" content=\"439\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Kay Grebenstein\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kay Grebenstein\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/\",\"name\":\"Pimp my testAUTOmation (Part 2) - ZEISS Digital Innovation Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg\",\"datePublished\":\"2020-06-24T09:32:47+00:00\",\"dateModified\":\"2020-06-24T19:57:23+00:00\",\"author\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#\/schema\/person\/6dc424ee6360e5a9547865996d0aca1d\"},\"description\":\"In the second part of the blog series about the extension of functions in Selenium 4 we create a video of the test execution.\",\"breadcrumb\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#primaryimage\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg\",\"width\":806,\"height\":439},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Pimp my testAUTOmation (Part 2)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#website\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/\",\"name\":\"Digital Innovation Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#\/schema\/person\/6dc424ee6360e5a9547865996d0aca1d\",\"name\":\"Kay Grebenstein\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-content\/uploads\/sites\/3\/2020\/05\/grebenstein_kay-1-150x150.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-content\/uploads\/sites\/3\/2020\/05\/grebenstein_kay-1-150x150.jpg\",\"caption\":\"Kay Grebenstein\"},\"description\":\"Kay Grebenstein worked as a tester and agile QA coach for ZEISS Digital Innovation, Dresden. He ensured quality and tested software in projects in various specialist domains (telecommunications, industry, mail order, energy, ...). He still shares his experiences at conferences, meetups and in publications of various kinds.\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/author\/enkaygrebenstein\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Pimp my testAUTOmation (Part 2) - ZEISS Digital Innovation Blog","description":"In the second part of the blog series about the extension of functions in Selenium 4 we create a video of the test execution.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/","og_locale":"en_US","og_type":"article","og_title":"Pimp my testAUTOmation (Part 2) - ZEISS Digital Innovation Blog","og_description":"In the second part of the blog series about the extension of functions in Selenium 4 we create a video of the test execution.","og_url":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/","og_site_name":"Digital Innovation Blog","article_published_time":"2020-06-24T09:32:47+00:00","article_modified_time":"2020-06-24T19:57:23+00:00","og_image":[{"width":806,"height":439,"url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg","type":"image\/jpeg"}],"author":"Kay Grebenstein","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kay Grebenstein","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/","name":"Pimp my testAUTOmation (Part 2) - ZEISS Digital Innovation Blog","isPartOf":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#primaryimage"},"image":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg","datePublished":"2020-06-24T09:32:47+00:00","dateModified":"2020-06-24T19:57:23+00:00","author":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#\/schema\/person\/6dc424ee6360e5a9547865996d0aca1d"},"description":"In the second part of the blog series about the extension of functions in Selenium 4 we create a video of the test execution.","breadcrumb":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#primaryimage","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation.jpg","width":806,"height":439},{"@type":"BreadcrumbList","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/pimp-my-testautomation-part-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/"},{"@type":"ListItem","position":2,"name":"Pimp my testAUTOmation (Part 2)"}]},{"@type":"WebSite","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#website","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/","name":"Digital Innovation Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#\/schema\/person\/6dc424ee6360e5a9547865996d0aca1d","name":"Kay Grebenstein","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/#\/schema\/person\/image\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-content\/uploads\/sites\/3\/2020\/05\/grebenstein_kay-1-150x150.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-content\/uploads\/sites\/3\/2020\/05\/grebenstein_kay-1-150x150.jpg","caption":"Kay Grebenstein"},"description":"Kay Grebenstein worked as a tester and agile QA coach for ZEISS Digital Innovation, Dresden. He ensured quality and tested software in projects in various specialist domains (telecommunications, industry, mail order, energy, ...). He still shares his experiences at conferences, meetups and in publications of various kinds.","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/author\/enkaygrebenstein\/"}]}},"author_meta":{"display_name":"Kay Grebenstein","author_link":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/author\/enkaygrebenstein\/"},"featured_img":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/06\/202006_pimp_my_testautomation-600x327.jpg","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">Quality Assurance<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Quality Assurance<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">test automation<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">Selenium<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">Selenium 4<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">Debugging<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">MonteCC<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">JUnit Annotations<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/category\/quality-assurance\/\" class=\"advgb-post-tax-term\">JavaCV<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">test automation<\/span>","<span class=\"advgb-post-tax-term\">Selenium<\/span>","<span class=\"advgb-post-tax-term\">Selenium 4<\/span>","<span class=\"advgb-post-tax-term\">Debugging<\/span>","<span class=\"advgb-post-tax-term\">MonteCC<\/span>","<span class=\"advgb-post-tax-term\">JUnit Annotations<\/span>","<span class=\"advgb-post-tax-term\">JavaCV<\/span>"]}},"comment_count":"0","relative_dates":{"created":"Posted 6 years ago","modified":"Updated 6 years ago"},"absolute_dates":{"created":"Posted on June 24, 2020","modified":"Updated on June 24, 2020"},"absolute_dates_time":{"created":"Posted on June 24, 2020 9:32 am","modified":"Updated on June 24, 2020 7:57 pm"},"featured_img_caption":"","series_order":"","_links":{"self":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/posts\/683","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/comments?post=683"}],"version-history":[{"count":9,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/posts\/683\/revisions"}],"predecessor-version":[{"id":693,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/posts\/683\/revisions\/693"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/media\/613"}],"wp:attachment":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/media?parent=683"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/categories?post=683"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/tags?post=683"},{"taxonomy":"topics","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/en\/wp-json\/wp\/v2\/topics?post=683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}