RFR: 8328716: [TestBug] Screen capturing utility for failed tests

Kevin Rushforth kcr at openjdk.org
Fri Mar 28 21:31:43 UTC 2025


On Fri, 28 Mar 2025 18:22:56 GMT, Andy Goryachev <angorya at openjdk.org> wrote:

> Introduce a facility, in the form of JUnit5 annotation, to allow for capturing a desktop screenshot of a failed test.
> 
> The primary intent is to be able to debug an intermittent test case, rather than wholesale addition of the new annotation to all the tests.
> 
> A possible improvement could be to output a data URL
> 
> `data:image/png;base64,iVBORw0KGgoAAAANSUhEU...`
> 
> so it can be rendered in Safari (Chrome truncates the image possibly due to following a url length limit)

I haven't tested it yet, but look forward to doing so.

My main comment is that this needs to be 'opt in' on a gradle property. Something like this (probably with a better name) :


gradle ... -PUSE_ROBOT=true -PSCREEN_DUMP=true


Or if we can figure out a good way to limit the number of tests that will be captured:


gradle ... -PUSE_ROBOT=true -PSCREEN_DUMP_LIMIT=10

tests/system/src/test/java/test/robot/javafx/scene/control/behavior/TextAreaBehaviorRobotTest.java line 40:

> 38:  * since the mapped functions require rendered text.
> 39:  */
> 40: @ExtendWith(ScreenCaptureTestWatcher.class)

A JUnit5 annotation seams like an easy way to mark our robot tests for capture. Are there any drawbacks with this approach?

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 44:

> 42: 
> 43: /**
> 44:  * Standard Test Watcher for Headful Tests (JUnit 5 Only).

I think the "JUnit 5 only" comment isn't needed. All of our system tests already use only JUnit 5.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 47:

> 45:  * <p>
> 46:  * This facility takes a screenshot of any failed test, then logs the base64-encoded screenshot
> 47:  * to {@code stderr}.

This should not be on by default, but should be "opt in" on a System property. I recommend defining a gradle property to do this and map it to that System property, much like we do for "UNSTABLE_TEST" and others.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 62:

> 60:  * -ea
> 61:  * }</pre>
> 62:  * <p>

I don't much like IDE-specific documentation in our class files.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 64:

> 62:  * <p>
> 63:  * WARNING: using this utility may significantly increase the size of your logs!
> 64:  * Make sure there is plenty of free disk space.

Given my earlier comment about this needing to be qualified by a system property, this comment should also go in `build.gradle` where the property is defined.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 67:

> 65:  */
> 66: // TODO investigate having a hard-coded or programmable via property limit on the number of
> 67: // captured screenshots.

I had the same thought. Given that each test runs in its own JVM, I can't think of a good way to do it other than recording information in a file in tests/system/build.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 71:

> 69:     @Override
> 70:     public void testAborted(ExtensionContext extensionContext, Throwable err) {
> 71:         err.printStackTrace();

Is this needed or is it just for debugging? We already get a stack trace when a test fails, so it might be redundant.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 76:

> 74:     @Override
> 75:     public void testFailed(ExtensionContext extensionContext, Throwable err) {
> 76:         err.printStackTrace();

Same question as about about printing the stack trace.

tests/system/src/test/java/test/util/ScreenCaptureTestWatcher.java line 77:

> 75:     public void testFailed(ExtensionContext extensionContext, Throwable err) {
> 76:         err.printStackTrace();
> 77:         System.err.println(generateScreenshot("Screenshot:{", "}"));

When does the `testFailed` method run? After a failing `@Test` method that throws the exception? What if there is more than one failing test? Ideally what we want is something that runs after all failing tests, but before the `@AfterEach` method.

-------------

PR Review: https://git.openjdk.org/jfx/pull/1746#pullrequestreview-2726765623
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019373251
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019375500
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019376822
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019377220
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019381676
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019385645
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019386416
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019392578
PR Review Comment: https://git.openjdk.org/jfx/pull/1746#discussion_r2019408150


More information about the openjfx-dev mailing list