ci: give each screenshot test class its own JVM

There are five screenshot test classes (PreviewShard1..4Test plus
PreviewA11yTest) and each shard renders roughly 770 previews in a single
process. Gradle reuses a forked JVM for the next test class once
maxParallelForks is exhausted, so on the current six-core runners
(forks = 3) two classes run second, inside a process that has already
rendered a full shard.

That matches the observed failure exactly: PreviewShard2Test and
PreviewShard4Test fail 100% while shards 1 and 3 pass 100%, and the split
holds even for byte-identical preview states. The previous eight-core
runners computed forks = 4, reused only one JVM, and were green on this
same tree.

forkEvery = 1 restarts the JVM after every test class. It costs five JVM
startups and no extra peak memory, unlike raising maxParallelForks to 5,
which would need 10 GB of test heap on a 19 GiB runner with no swap.

Claude-Session: https://claude.ai/code/session_01MQbp1EPM4TSXq8P8Pyq44F
This commit is contained in:
2026-08-06 10:15:50 +02:00
parent ce180ef25b
commit 081904345a
+11
View File
@@ -156,6 +156,17 @@ allprojects {
if (isScreenshotTest) {
// Increase heap size for screenshot tests
maxHeapSize = "2g"
// Give every screenshot test class its own JVM.
//
// There are 5 screenshot classes (PreviewShard1..4Test + PreviewA11yTest) and each
// shard renders ~770 previews in a single process. Gradle reuses a forked JVM for the
// next class once maxParallelForks is exhausted, so on a 6-core runner (forks = 3) two
// classes run second, in a process that has already rendered a full shard — and they
// render differently from how the goldens were recorded. That is exactly the observed
// failure: shards 2 and 4 fail 100% while 1 and 3 pass 100%, deterministically, for
// byte-identical states. The 8-core runner (forks = 4) reused only one JVM and was green
// on the same tree. Restarting per class costs 5 JVM startups and no extra peak memory.
forkEvery = 1L
// Record all the languages?
if (project.hasProperty("allLanguagesNoEnglish")) {
// Do not record English language