diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a785baa692b8bcc3b951e5aeb8fb5bfe05d8ceb9..642033997e2f865976e6e668cae4b04dc4a9a90a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,6 +10,7 @@ variables:
   BUILD_TYPE: Release
   BUILD_TESTS: "true"
   BUILD_CTEST: "true"
+  CTEST_INCLUDE_REGEX: "" # Regex is given via ctest -R [regex]
   CPU_TARGET: ivybridge # envinf1 has oldest cpu
   ARTIFACTS_PAGES_URL: https://$CI_PROJECT_ROOT_NAMESPACE.$CI_PAGES_DOMAIN/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts
 
diff --git a/Applications/Utils/Tests.cmake b/Applications/Utils/Tests.cmake
index 4ef83327c76ccd57341bffb9ff3018884e2385d4..c22e5de1ac1474f494fcc5bb762e722d7b963bd0 100644
--- a/Applications/Utils/Tests.cmake
+++ b/Applications/Utils/Tests.cmake
@@ -911,12 +911,9 @@ AddTest(
     DIFF_DATA
     basin_mesh_fixed.vtu basin_mesh_fixed.vtu head head 0 0
     basin_mesh_fixed.vtu basin_mesh_fixed.vtu MaterialIDs MaterialIDs 0 0
+    # Execute tests in order to prevent race condition
+    PROPERTIES DEPENDS reviseMesh-ReviseMesh_Test-vtkdiff
 )
-# Execute tests in order to prevent race condition
-if(TEST reviseMesh-ReviseMesh_Test_Arrays-vtkdiff)
-    set_tests_properties(reviseMesh-ReviseMesh_Test_Arrays
-        PROPERTIES DEPENDS reviseMesh-ReviseMesh_Test-vtkdiff)
-endif()
 
 AddTest(
     NAME BinaryToPVTU
diff --git a/ProcessLib/LiquidFlow/Tests.cmake b/ProcessLib/LiquidFlow/Tests.cmake
index 4ab4aca3a2d5a7c2c9b42b6f98309b099c8dceb1..222724166c2d5be64d61e317f097531d4b387ad4 100644
--- a/ProcessLib/LiquidFlow/Tests.cmake
+++ b/ProcessLib/LiquidFlow/Tests.cmake
@@ -510,16 +510,9 @@ if(NOT OGS_USE_MPI)
             top_boundary_to_bottom_boundary_cuboid_1x1x1_hex_27_cuboid_1x1x1_hex_27_top_boundary.xdmf
             top_boundary_to_bottom_boundary_cuboid_1x1x1_hex_27_cuboid_1x1x1_hex_27_top_boundary.xdmf
             pressure pressure 1e-7 1e-13
+        PROPERTIES DEPENDS ogs-LiquidFlow_Flux_3D_HEX_MultipleOutputs_vtu-time
     )
 
-    if(TEST ogs-LiquidFlow_Flux_3D_HEX_MultipleOutputs_xdmf-time)
-        set_tests_properties(
-            ogs-LiquidFlow_Flux_3D_HEX_MultipleOutputs_xdmf-time
-            PROPERTIES LABELS "default" DEPENDS
-                       ogs-LiquidFlow_Flux_3D_HEX_MultipleOutputs_vtu-time
-        )
-    endif()
-
     AddTest(
         NAME LiquidFlow_Flux_3D_HEX_MultipleOutputs_SameFiles
         PATH Parabolic/LiquidFlow/Flux/3D/Hex
@@ -527,12 +520,8 @@ if(NOT OGS_USE_MPI)
         EXECUTABLE_ARGS cuboid_1x1x1_hex_27_Dirichlet_Dirichlet_invalid_multiple_outputs.xml
         WRAPPER time
         REQUIREMENTS NOT OGS_USE_MPI
+        PROPERTIES WILL_FAIL TRUE
     )
-    if(TEST ogs-LiquidFlow_Flux_3D_HEX_MultipleOutputs_SameFiles-time)
-        set_tests_properties(
-            ogs-LiquidFlow_Flux_3D_HEX_MultipleOutputs_SameFiles-time
-            PROPERTIES WILL_FAIL TRUE)
-    endif()
 
 endif()
 
diff --git a/ProcessLib/PhaseField/Tests.cmake b/ProcessLib/PhaseField/Tests.cmake
index dbe103f1b4c65cac74ae1ab984b61bfe2c4fec76..3b05a2039f6199c97c20a67cffc0564739b962db 100644
--- a/ProcessLib/PhaseField/Tests.cmake
+++ b/ProcessLib/PhaseField/Tests.cmake
@@ -136,10 +136,6 @@ AddTest(
 )
 
 if(OGS_USE_PETSC)
-    NotebookTest(NOTEBOOKFILE PhaseField/surfing_jupyter_notebook/surfing_pyvista.ipynb RUNTIME 25 RESOURCE_LOCK PYVISTA)
-    NotebookTest(NOTEBOOKFILE PhaseField/beam_jupyter_notebook/beam.ipynb RUNTIME 500 RESOURCE_LOCK PYVISTA)
-endif()
-
-if(TEST nb-PhaseField/beam_jupyter_notebook/beam-LARGE)
-    set_tests_properties(nb-PhaseField/beam_jupyter_notebook/beam-LARGE PROPERTIES PROCESSORS 3)
+    NotebookTest(NOTEBOOKFILE PhaseField/surfing_jupyter_notebook/surfing_pyvista.ipynb RUNTIME 25)
+    NotebookTest(NOTEBOOKFILE PhaseField/beam_jupyter_notebook/beam.ipynb RUNTIME 500 PROPERTIES PROCESSORS 3)
 endif()
diff --git a/ProcessLib/RichardsMechanics/Tests.cmake b/ProcessLib/RichardsMechanics/Tests.cmake
index ea9f7b709dcff36cf46dfe12a23ca4168fe45ead..fc51875d521495d6f0cfac50c04c77bab2cba2ce 100644
--- a/ProcessLib/RichardsMechanics/Tests.cmake
+++ b/ProcessLib/RichardsMechanics/Tests.cmake
@@ -39,6 +39,8 @@ AddTest(
     WRAPPER time
     TESTER vtkdiff
     REQUIREMENTS NOT OGS_USE_MPI
+    # Does not exist?
+    # PROPERTIES DEPENDS ogs-RichardsMechanics_square_1e2_confined_compression-time-vtkdiff
     DIFF_DATA
     confined_compression_fully_saturated_ts_20_t_100.000000.vtu confined_compression_fully_saturated_restart_ts_0_t_100.000000.vtu displacement displacement 1e-16 0
     confined_compression_fully_saturated_ts_120_t_1000.000000.vtu confined_compression_fully_saturated_restart_ts_100_t_1000.000000.vtu displacement displacement 1e-16 0
@@ -64,7 +66,3 @@ AddTest(
     confined_compression_fully_saturated_ts_120_t_1000.000000.vtu confined_compression_fully_saturated_restart_ts_100_t_1000.000000.vtu velocity velocity 1e-16 0
     confined_compression_fully_saturated_ts_420_t_4000.000000.vtu confined_compression_fully_saturated_restart_ts_400_t_4000.000000.vtu velocity velocity 1e-16 0
 )
-if(TEST ogs-RichardsMechanics_square_1e2_confined_compression_restart-time)
-    set_tests_properties(ogs-RichardsMechanics_square_1e2_confined_compression_restart-time PROPERTIES
-        DEPENDS ogs-RichardsMechanics_square_1e2_confined_compression-time-vtkdiff)
-endif()
diff --git a/ProcessLib/SmallDeformation/Tests.cmake b/ProcessLib/SmallDeformation/Tests.cmake
index 18e9b0488c35f1d0ef15834b88778933fed4b619..db3edc67e295d044f6ad04c7fe245066f6b7ce68 100644
--- a/ProcessLib/SmallDeformation/Tests.cmake
+++ b/ProcessLib/SmallDeformation/Tests.cmake
@@ -2,21 +2,16 @@ if (NOT OGS_USE_MPI)
     OgsTest(PROJECTFILE Mechanics/Linear/square_1e0.prj)
     OgsTest(PROJECTFILE Mechanics/Linear/square_1e2.prj)
     if(OGS_USE_EIGEN_UNSUPPORTED)
-        OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_IDRS.xml)
-        if(TEST ogs-Mechanics/Linear/square_1e2_IDRS)
-            set_tests_properties(ogs-Mechanics/Linear/square_1e2_IDRS PROPERTIES
-                DEPENDS ogs-Mechanics/Linear/square_1e2) # Prevent race condition
-        endif()
-        OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_IDRSTABL.xml)
-        if(TEST ogs-Mechanics/Linear/square_1e2_IDRSTABL)
-            set_tests_properties(ogs-Mechanics/Linear/square_1e2_IDRSTABL PROPERTIES
-                DEPENDS ogs-Mechanics/Linear/square_1e2_IDRS) # Prevent race condition
-        endif()
-        OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_BiCGSTABL.xml)
-        if(TEST ogs-Mechanics/Linear/square_1e2_BiCGSTABL)
-            set_tests_properties(ogs-Mechanics/Linear/square_1e2_BiCGSTABL PROPERTIES
-                DEPENDS ogs-Mechanics/Linear/square_1e2_IDRSTABL) # Prevent race condition
-        endif()
+        # DEPENDS for preventing race condition
+        OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_IDRS.xml
+            PROPERTIES DEPENDS ogs-Mechanics/Linear/square_1e2
+        )
+        OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_IDRSTABL.xml
+            PROPERTIES DEPENDS ogs-Mechanics/Linear/square_1e2_IDRS
+        )
+        OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_BiCGSTABL.xml
+            PROPERTIES DEPENDS ogs-Mechanics/Linear/square_1e2_IDRSTABL
+        )
     endif()
     OgsTest(PROJECTFILE Mechanics/Linear/disc_with_hole.prj)
     OgsTest(PROJECTFILE Mechanics/Linear/ElementDeactivation3D/element_deactivation_M_3D.prj)
@@ -24,11 +19,9 @@ if (NOT OGS_USE_MPI)
     OgsTest(PROJECTFILE Mechanics/Linear/square_1e2_quad8_traction_top.prj)
     OgsTest(PROJECTFILE Mechanics/Linear/cube_1e0.prj)
     if(OGS_USE_MKL)
-        OgsTest(PROJECTFILE Mechanics/Linear/cube_1e0_mkl.xml)
-        if(TEST ogs-Mechanics/Linear/cube_1e0_mkl)
-            set_tests_properties(ogs-Mechanics/Linear/cube_1e0_mkl PROPERTIES
-                DEPENDS ogs-Mechanics/Linear/cube_1e0) # Prevent race condition
-        endif()
+        OgsTest(PROJECTFILE Mechanics/Linear/cube_1e0_mkl.xml
+            PROPERTIES DEPENDS ogs-Mechanics/Linear/cube_1e0
+        )
     endif()
     OgsTest(PROJECTFILE Mechanics/Linear/cube_1e0_simple_shear.prj)
     OgsTest(PROJECTFILE Mechanics/Linear/MaterialForces/bar.prj)
@@ -79,10 +72,9 @@ if (OGS_USE_MPI)
 endif()
 
 if (OGS_USE_MFRONT)
-    OgsTest(PROJECTFILE Mechanics/MohrCoulombAbboSloan/slope.prj RUNTIME 50)
-    if(TEST ogs-Mechanics/MohrCoulombAbboSloan/slope)
-        set_tests_properties(ogs-Mechanics/MohrCoulombAbboSloan/slope PROPERTIES WILL_FAIL true)
-    endif()
+    OgsTest(PROJECTFILE Mechanics/MohrCoulombAbboSloan/slope.prj RUNTIME 50
+        PROPERTIES WILL_FAIL true
+    )
     OgsTest(PROJECTFILE Mechanics/MohrCoulombAbboSloan/load_test_mc.prj)
     OgsTest(PROJECTFILE Mechanics/MohrCoulombAbboSloanAnisotropic/triax_1e0_47.prj)
     OgsTest(PROJECTFILE Mechanics/MohrCoulombAbboSloanAnisotropic/triax_ortho_1e0_47.prj)
@@ -270,8 +262,8 @@ AddTest(
 
 if(NOT OGS_USE_PETSC)
     NotebookTest(NOTEBOOKFILE Mechanics/Linear/SimpleMechanics.ipynb RUNTIME 5)
-    NotebookTest(NOTEBOOKFILE Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole.ipynb RUNTIME 15 RESOURCE_LOCK PYVISTA)
+    NotebookTest(NOTEBOOKFILE Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole.ipynb RUNTIME 15)
     if(NOT WIN32)
-        NotebookTest(NOTEBOOKFILE Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole_convergence_analysis.ipynb RUNTIME 40 RESOURCE_LOCK PYVISTA)
+        NotebookTest(NOTEBOOKFILE Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole_convergence_analysis.ipynb RUNTIME 40)
     endif()
 endif()
diff --git a/ProcessLib/TH2M/Tests.cmake b/ProcessLib/TH2M/Tests.cmake
index d4f16408e13a86fb968e67122674f4109b8fd51b..fd95d09e29360e740e31abe4104f62adfe5c1489 100644
--- a/ProcessLib/TH2M/Tests.cmake
+++ b/ProcessLib/TH2M/Tests.cmake
@@ -9,7 +9,7 @@ if (NOT OGS_USE_MPI)
     OgsTest(PROJECTFILE TH2M/THM/Confined_Compression/THM_confined_compression_liquid.prj RUNTIME 55)
     OgsTest(PROJECTFILE TH2M/TH/idealGasLaw/compression_gas.prj RUNTIME 1)
     OgsTest(PROJECTFILE TH2M/H2M/Liakopoulos/liakopoulos_TH2M.prj RUNTIME 15)
-    NotebookTest(NOTEBOOKFILE TH2M/H2M/Liakopoulos/ogs-jupyter-lab-h2m-2d-liakopoulos.ipynb RUNTIME 15 RESOURCE_LOCK PYVISTA)
+    NotebookTest(NOTEBOOKFILE TH2M/H2M/Liakopoulos/ogs-jupyter-lab-h2m-2d-liakopoulos.ipynb RUNTIME 15)
     OgsTest(PROJECTFILE TH2M/H2M/Liakopoulos/liakopoulos_newton.xml RUNTIME 5)
     OgsTest(PROJECTFILE TH2M/H2M/OrthotropicSwelling/square.prj RUNTIME 1)
     OgsTest(PROJECTFILE TH2M/H2/mcWhorter/mcWhorter_h2.prj RUNTIME 55)
diff --git a/ProcessLib/Tests.cmake b/ProcessLib/Tests.cmake
index e1d04e32fe9b7fcdb331c507b87704ed0364b924..8124203e3e1444a8ca2c0aa37e102423d1f9b090 100644
--- a/ProcessLib/Tests.cmake
+++ b/ProcessLib/Tests.cmake
@@ -7,15 +7,7 @@ if(TARGET ThermoHydroMechanics
     NotebookTest(
         NOTEBOOKFILE
         ThermoHydroMechanics/Linear/Point_injection/SaturatedPointheatsource.ipynb
-        RUNTIME
-        1800
+        RUNTIME 1800
+        PROPERTIES PROCESSORS 4
     )
-    if(TEST
-       nb-ThermoHydroMechanics/Linear/Point_injection/SaturatedPointheatsource-LARGE
-    )
-        set_tests_properties(
-            nb-ThermoHydroMechanics/Linear/Point_injection/SaturatedPointheatsource-LARGE
-            PROPERTIES PROCESSORS 4
-        )
-    endif()
 endif()
diff --git a/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole.ipynb b/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole.ipynb
index d46c0c5414a5071c4809568410c63fd67aef4ce6..56d10567b6a112d3558cce04f6702b6c29e29cb7 100644
--- a/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole.ipynb
+++ b/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole.ipynb
@@ -479,9 +479,7 @@
    "source": [
     "import pyvista as pv\n",
     "pv.set_plot_theme(\"document\")\n",
-    "if \"PYVISTA_HEADLESS\" in os.environ:\n",
-    "    pv.start_xvfb()\n",
-    "pv.set_jupyter_backend(\"static\") # comment out for interactive graphics\n"
+    "pv.set_jupyter_backend(\"static\") # comment out for interactive graphics"
    ]
   },
   {
diff --git a/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole_convergence_analysis.ipynb b/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole_convergence_analysis.ipynb
index 1ef8f8aef5ce35399d8c8ce2720762585fdc0ecd..a3043d0c55f3b9ac8f9fefa347fafcfe0dbe494f 100644
--- a/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole_convergence_analysis.ipynb
+++ b/Tests/Data/Mechanics/Linear/DiscWithHole/Linear_Disc_with_hole_convergence_analysis.ipynb
@@ -582,8 +582,6 @@
    "source": [
     "import pyvista as pv\n",
     "pv.set_plot_theme(\"document\")\n",
-    "if \"PYVISTA_HEADLESS\" in os.environ:\n",
-    "    pv.start_xvfb()\n",
     "pv.set_jupyter_backend(\"static\")"
    ]
   },
diff --git a/Tests/Data/PhaseField/surfing_jupyter_notebook/surfing_pyvista.ipynb b/Tests/Data/PhaseField/surfing_jupyter_notebook/surfing_pyvista.ipynb
index c4259c4e8cdb81c4a4c408932e9709370e54118e..3d11e78b07896a343393d62ec43ca45e6cedc198 100644
--- a/Tests/Data/PhaseField/surfing_jupyter_notebook/surfing_pyvista.ipynb
+++ b/Tests/Data/PhaseField/surfing_jupyter_notebook/surfing_pyvista.ipynb
@@ -244,8 +244,6 @@
    "source": [
     "import pyvista as pv\n",
     "pv.set_plot_theme(\"document\")\n",
-    "if \"PYVISTA_HEADLESS\" in os.environ:\n",
-    "    pv.start_xvfb()\n",
     "pv.set_jupyter_backend(\"static\")\n",
     "\n",
     "import numpy as np\n",
diff --git a/Tests/Data/TH2M/H2M/Liakopoulos/ogs-jupyter-lab-h2m-2d-liakopoulos.ipynb b/Tests/Data/TH2M/H2M/Liakopoulos/ogs-jupyter-lab-h2m-2d-liakopoulos.ipynb
index e00e8edeaee69d534c465fb50b77afb8269dc04d..2b4956114bc44adcfc8f425cc24d2c43131ea81e 100644
--- a/Tests/Data/TH2M/H2M/Liakopoulos/ogs-jupyter-lab-h2m-2d-liakopoulos.ipynb
+++ b/Tests/Data/TH2M/H2M/Liakopoulos/ogs-jupyter-lab-h2m-2d-liakopoulos.ipynb
@@ -29,8 +29,6 @@
     "from vtk.util.numpy_support import vtk_to_numpy\n",
     "import os\n",
     "import pyvista as pv\n",
-    "if \"PYVISTA_HEADLESS\" in os.environ:\n",
-    "    pv.start_xvfb()\n",
     "pv.set_jupyter_backend(\"static\")\n",
     "import numpy as np\n",
     "import matplotlib.pyplot as plt\n",
diff --git a/Tests/Data/requirements.txt b/Tests/Data/requirements.txt
index 251df6478600067f0d4a9d088db432a2f86829d1..045513bc478b32f3eb96d8738292ef71c3596907 100644
--- a/Tests/Data/requirements.txt
+++ b/Tests/Data/requirements.txt
@@ -1,4 +1,4 @@
-gmsh==4.10.5 ; sys_platform == 'win32' or sys_platform == 'linux'
+gmsh==4.11.0
 h5py==3.7.0
 -e git+https://github.com/joergbuchwald/heatsource_thm@bbd5bab17fc2ec228c773e087dc847e1ad5f9a4c#egg=heatsource-py
 jupyterlab==3.4.8
diff --git a/ThirdParty/container-maker b/ThirdParty/container-maker
index 496d23a444749ab133ba869a49147ed93e67f920..6e5fee9bd549ad0e64ed635abee101a9fda6d3af 160000
--- a/ThirdParty/container-maker
+++ b/ThirdParty/container-maker
@@ -1 +1 @@
-Subproject commit 496d23a444749ab133ba869a49147ed93e67f920
+Subproject commit 6e5fee9bd549ad0e64ed635abee101a9fda6d3af
diff --git a/scripts/ci/extends/template-build-linux.yml b/scripts/ci/extends/template-build-linux.yml
index 66a24466baeff433320ad356db8dac155c18f517..8ce8e851798ba70af971d1f67ccc15452459c312 100644
--- a/scripts/ci/extends/template-build-linux.yml
+++ b/scripts/ci/extends/template-build-linux.yml
@@ -14,7 +14,7 @@
     - ln -s `$readlink_cmd -f $build_dir_full` build/${CMAKE_PRESET}
     - ([ "${CONAN_USER_HOME}" == "${CI_PROJECT_DIR}/.conan" ]) && conan remove --system-reqs '*'
     - ([[ $BUILD_CTEST_LARGE_ON_MASTER && "${CI_COMMIT_BRANCH}" == "master" && "${CMAKE_ARGS}" == *"USE_PYTHON=ON"* ]]) && export BUILD_CTEST_LARGE=true
-    - cmake --preset=$CMAKE_PRESET -Wno-dev $CMAKE_ARGS
+    - cmake --preset=$CMAKE_PRESET --log-level=VERBOSE -Wno-dev $CMAKE_ARGS
     # Activate .venv
     - test -f $build_dir_full/.venv/bin/activate && source $build_dir_full/.venv/bin/activate
     - |
@@ -38,11 +38,21 @@
             preset_postfix="-large"
           fi
 
-          if [[ "$OSTYPE" == "darwin"* ]]; then alias date=gdate ; fi
+          xvfb_run_cmd=""
+          if [[ "$OSTYPE" == "darwin"* ]]; then
+            alias date=gdate
+          else
+            xvfb_run_cmd="xvfb-run -a"
+          fi
+
+          regex_argument=""
+          if [[ ! -z "$CTEST_INCLUDE_REGEX" ]]; then
+            regex_argument="-R ${CTEST_INCLUDE_REGEX}"
+          fi
 
           # -M Continuous does not run any tests -> -M Experimental --group Continuous
           # --test-dir has to be provided despite using a preset
-          ctest -M Experimental --group Continuous --test-dir ${build_dir_full} -T Test -T Submit --preset=${CMAKE_PRESET}${preset_postfix} --output-junit Tests/ctest.xml --stop-time `date -d "today + ${ctest_timeout} minutes" +'%H:%M:%S'` ${CTEST_ARGS}
+          ${xvfb_run_cmd} ctest -M Experimental ${regex_argument} --group Continuous --test-dir ${build_dir_full} -T Test -T Submit --preset=${CMAKE_PRESET}${preset_postfix} --output-junit Tests/ctest.xml --stop-time `date -d "today + ${ctest_timeout} minutes" +'%H:%M:%S'` ${CTEST_ARGS}
         fi
 
       else
diff --git a/scripts/ci/extends/template-build-win.yml b/scripts/ci/extends/template-build-win.yml
index 60a0f1f4988b76df7ad556de968ffad84148b9f8..74dba2b23115a37245d9bc88f43cfa663456d1f7 100644
--- a/scripts/ci/extends/template-build-win.yml
+++ b/scripts/ci/extends/template-build-win.yml
@@ -15,7 +15,7 @@
     - mkdir build
     # Create symlink https://stackoverflow.com/a/34905638/80480
     - cmd /c mklink /D build\$env:CMAKE_PRESET $env:CI_PROJECT_DIR\$build_directory_full
-    - $cmake_cmd = "cmake --preset=$env:CMAKE_PRESET -Wno-dev $env:CMAKE_ARGS"
+    - $cmake_cmd = "cmake --preset=$env:CMAKE_PRESET --log-level=VERBOSE -Wno-dev $env:CMAKE_ARGS"
     - $cmake_cmd
     - Invoke-Expression $cmake_cmd
     # Activate .venv
diff --git a/scripts/ci/jobs/jupyter.yml b/scripts/ci/jobs/jupyter.yml
index d42b8b028596836c556fc73bc3708551046ff9a8..d53ff673f7ff09c5b72ba0a677f88bfb10d259f2 100644
--- a/scripts/ci/jobs/jupyter.yml
+++ b/scripts/ci/jobs/jupyter.yml
@@ -8,7 +8,10 @@ test notebooks via wheel:
     - pip install -r requirements.txt
     - pip install -r requirements-dev.txt
     - pip install -r requirements-ogs.txt
-    - find . -type f -iname '*.ipynb' | grep -vP '\.ipynb_checkpoints|\.ci-skip.ipynb$|_out|.venv|PhaseField' | PYVISTA_HEADLESS=1 xargs python Notebooks/testrunner.py --out _out
+    # TODO:
+    #  - better timeout
+    #  - run in parallel
+    - find . -type f -iname '*.ipynb' | grep -vP '\.ipynb_checkpoints|\.ci-skip.ipynb$|_out|.venv|PhaseField' | xargs xvfb-run -a python Notebooks/testrunner.py --out _out --timeout 1200
   artifacts:
     when: always
     paths:
diff --git a/scripts/cmake/PythonSetup.cmake b/scripts/cmake/PythonSetup.cmake
index 2eae0cfc73cee21781af7092355abc1de1d174de..8729dcbec891a5cd9944f8df892cd3d66ad10591 100644
--- a/scripts/cmake/PythonSetup.cmake
+++ b/scripts/cmake/PythonSetup.cmake
@@ -130,6 +130,16 @@ function(setup_venv)
             OUTPUT_VARIABLE _out
             ERROR_VARIABLE _err
         )
+        if(DEFINED ENV{CI_JOB_IMAGE})
+            # Install gmsh package without X11 dependencies in Docker CI builds
+            execute_process(
+                COMMAND
+                    ${LOCAL_VIRTUALENV_BIN_DIR}/pip install -i
+                    https://gmsh.info/python-packages-dev-nox --force-reinstall
+                    --no-cache-dir gmsh
+                WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
+            )
+        endif()
         if(${_return_code} EQUAL 0)
             set(_OGS_PYTHON_PACKAGES_SHA1 "${_ogs_python_packages_sha1}"
                 CACHE INTERNAL ""
diff --git a/scripts/cmake/test/AddTest.cmake b/scripts/cmake/test/AddTest.cmake
index 5d085a6cc671a26cace383b9dafc8971b7bfd5cf..5fafb631fa45ce38c21e6b64774a40d76ab25785 100644
--- a/scripts/cmake/test/AddTest.cmake
+++ b/scripts/cmake/test/AddTest.cmake
@@ -22,6 +22,7 @@
 #                          values should be taken from envinf job
 #   WORKING_DIRECTORY # optional, specify the working directory of the test
 #   DISABLED # optional, disables the test
+#   PROPERTIES <test properties> # optional
 # )
 # ~~~
 #
@@ -75,6 +76,7 @@ function(AddTest)
         TESTER_ARGS
         REQUIREMENTS
         PYTHON_PACKAGES
+        PROPERTIES
     )
     cmake_parse_arguments(
         AddTest "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}
@@ -423,7 +425,10 @@ Use six arguments version of AddTest with absolute and relative tolerances"
     )
     if(DEFINED AddTest_DEPENDS)
         if(NOT (TEST ${AddTest_DEPENDS} OR TARGET ${AddTest_DEPENDS}))
-            message(FATAL_ERROR "AddTest ${AddTest_Name}: dependency ${AddTest_DEPENDS} does not exist!")
+            message(
+                FATAL_ERROR
+                    "AddTest ${AddTest_Name}: dependency ${AddTest_DEPENDS} does not exist!"
+            )
         endif()
         set_tests_properties(${TEST_NAME} PROPERTIES DEPENDS ${AddTest_DEPENDS})
     endif()
@@ -461,8 +466,14 @@ Use six arguments version of AddTest with absolute and relative tolerances"
     endif()
 
     set_tests_properties(
-        ${TEST_NAME} PROPERTIES COST ${AddTest_RUNTIME} DISABLED
-                                ${AddTest_DISABLED} LABELS "${labels}"
+        ${TEST_NAME}
+        PROPERTIES ${AddTest_PROPERTIES}
+                   COST
+                   ${AddTest_RUNTIME}
+                   DISABLED
+                   ${AddTest_DISABLED}
+                   LABELS
+                   "${labels}"
     )
     # Disabled for the moment, does not work with CI under load
     # ~~~
diff --git a/scripts/cmake/test/NotebookTest.cmake b/scripts/cmake/test/NotebookTest.cmake
index 1dedb8fca606e677225241f83da604d2a8c9aa4f..06bf0484cb3b154fb9e2a6616fef819cbaa9b0d5 100644
--- a/scripts/cmake/test/NotebookTest.cmake
+++ b/scripts/cmake/test/NotebookTest.cmake
@@ -7,7 +7,7 @@ function(NotebookTest)
 
     set(options DISABLED)
     set(oneValueArgs NOTEBOOKFILE RUNTIME)
-    set(multiValueArgs WRAPPER RESOURCE_LOCK)
+    set(multiValueArgs WRAPPER RESOURCE_LOCK PROPERTIES)
     cmake_parse_arguments(
         NotebookTest "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}
     )
@@ -21,22 +21,6 @@ function(NotebookTest)
         return()
     endif()
 
-    if(UNIX
-       AND NOT APPLE
-       AND (DEFINED ENV{PYVISTA_HEADLESS} OR DEFINED ENV{CI})
-       AND "PYVISTA" IN_LIST NotebookTest_RESOURCE_LOCK
-    )
-        find_program(XVFB_TOOL_PATH Xvfb)
-        if(NOT XVFB_TOOL_PATH)
-            message(
-                "Disabled NotebookTest ${NotebookTest_NOTEBOOKFILE} because of"
-                " missing Xvfb tool which is required for PyVista headless on Linux."
-            )
-            return()
-        endif()
-        set(_pyvista_headless_env -E env PYVISTA_HEADLESS=1)
-    endif()
-
     get_filename_component(
         NotebookTest_DIR "${NotebookTest_NOTEBOOKFILE}" DIRECTORY
     )
@@ -54,6 +38,22 @@ function(NotebookTest)
         )
     endif()
 
+    set(NotebookTest_SOURCE_DIR "${Data_SOURCE_DIR}/${NotebookTest_DIR}")
+    set(_props "")
+
+    # Check for PyVista
+    set(_pyvista_check 0)
+    if(UNIX)
+        execute_process(
+            COMMAND nbdime show -s
+                    ${NotebookTest_SOURCE_DIR}/${NotebookTest_NAME}
+            COMMAND grep "import pyvista"
+            COMMAND wc -l
+            COMMAND tr -d "' '"
+            OUTPUT_VARIABLE _pyvista_check
+        )
+    endif()
+
     set(timeout ${ogs.ctest.large_runtime})
     if(DEFINED NotebookTest_RUNTIME)
         math(EXPR timeout "${NotebookTest_RUNTIME} * 5")
@@ -71,7 +71,6 @@ function(NotebookTest)
         string(APPEND NotebookTest_NAME_WE "-LARGE")
     endif()
 
-    set(NotebookTest_SOURCE_DIR "${Data_SOURCE_DIR}/${NotebookTest_DIR}")
     set(NotebookTest_BINARY_DIR "${Data_BINARY_DIR}/${NotebookTest_DIR}")
     file(MAKE_DIRECTORY ${NotebookTest_BINARY_DIR})
     file(TO_NATIVE_PATH "${NotebookTest_BINARY_DIR}"
@@ -91,7 +90,7 @@ function(NotebookTest)
     add_test(
         NAME ${TEST_NAME}
         COMMAND
-            ${CMAKE_COMMAND} ${_pyvista_headless_env} ${CMAKE_COMMAND}
+            ${CMAKE_COMMAND} ${CMAKE_COMMAND}
             # TODO: only works if notebook is in a leaf directory
             # -DFILES_TO_DELETE=${Data_BINARY_DIR}/${NotebookTest_DIR}
             -DEXECUTABLE=${Python_EXECUTABLE} "-DEXECUTABLE_ARGS=${_exe_args}"
@@ -109,18 +108,14 @@ function(NotebookTest)
         list(APPEND labels large)
     endif()
 
-    set(_prop_env ENVIRONMENT_MODIFICATION
-                  PATH=path_list_prepend:$<TARGET_FILE_DIR:ogs>
+    list(APPEND _props ENVIRONMENT_MODIFICATION
+         PATH=path_list_prepend:$<TARGET_FILE_DIR:ogs>
+         ${NotebookTest_PROPERTIES}
     )
-    if(DEFINED NotebookTest_RESOURCE_LOCK)
-        set_tests_properties(
-            ${TEST_NAME} PROPERTIES RESOURCE_LOCK ${NotebookTest_RESOURCE_LOCK}
-        )
-    endif()
 
     set_tests_properties(
         ${TEST_NAME}
-        PROPERTIES ${_prop_env}
+        PROPERTIES ${_props}
                    COST
                    ${NotebookTest_RUNTIME}
                    DISABLED
diff --git a/scripts/cmake/test/OgsTest.cmake b/scripts/cmake/test/OgsTest.cmake
index 31e766979cb294bf06aab4b5e8e0bc96d2c570f0..b89ac1162edceab89234c6419be8aa01cc13319d 100644
--- a/scripts/cmake/test/OgsTest.cmake
+++ b/scripts/cmake/test/OgsTest.cmake
@@ -10,7 +10,7 @@ function(OgsTest)
 
     set(options DISABLED)
     set(oneValueArgs PROJECTFILE RUNTIME)
-    set(multiValueArgs WRAPPER)
+    set(multiValueArgs WRAPPER PROPERTIES)
     cmake_parse_arguments(
         OgsTest "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}
     )
@@ -97,7 +97,8 @@ function(OgsTest)
 
     set_tests_properties(
         ${TEST_NAME}
-        PROPERTIES ENVIRONMENT
+        PROPERTIES ${OgsTest_PROPERTIES}
+                   ENVIRONMENT
                    VTKDIFF_EXE=$<TARGET_FILE:vtkdiff>
                    COST
                    ${OgsTest_RUNTIME}
diff --git a/scripts/cmake/test/Test.cmake b/scripts/cmake/test/Test.cmake
index ab45dcd593d1a3518e041b2a0d7b0800fe67512c..4b40980451b2406bb5e44e58a748b35a2507e50a 100644
--- a/scripts/cmake/test/Test.cmake
+++ b/scripts/cmake/test/Test.cmake
@@ -51,10 +51,15 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake/test/OgsTest.cmake)
 include(${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake/test/NotebookTest.cmake)
 
 # Check notebook testrunner
-NotebookTest(NOTEBOOKFILE Notebooks/FailingNotebook.ci-skip.ipynb RUNTIME 2)
-if(TEST nb-Notebooks/FailingNotebook)
-    set_tests_properties(nb-Notebooks/FailingNotebook PROPERTIES WILL_FAIL TRUE)
-endif()
+NotebookTest(
+    NOTEBOOKFILE
+    Notebooks/FailingNotebook.ci-skip.ipynb
+    RUNTIME
+    2
+    PROPERTIES
+    WILL_FAIL
+    TRUE
+)
 
 set(_ctest_parameter -T Test --force-new-ctest-process --output-on-failure)
 if(CMAKE_CONFIGURATION_TYPES)
diff --git a/web/content/docs/devguide/testing/gitlab-ci/index.md b/web/content/docs/devguide/testing/gitlab-ci/index.md
index e9f2398a4459cd77e2ea658165b7347157a8b029..8f6b72ac0ddadcdecfea2dd3fde659afd6a13ee3 100644
--- a/web/content/docs/devguide/testing/gitlab-ci/index.md
+++ b/web/content/docs/devguide/testing/gitlab-ci/index.md
@@ -43,3 +43,29 @@ Or add `[ci skip]` to the commit message to skip the pipeline for this commit. E
 ```bash
 git commit -m "Added feature X [ci skip]"
 ```
+
+## (Temporarily) reduce pipeline run time
+
+During work on MR you may want to reduce the pipeline run time to get feedback faster. You can change the pipeline by editing the `.gitlab-ci.yml` and `scripts/ci/jobs/*.yml` files. It is good practice to mark these changes with commits starting with `drop: ...` in the commit message so they can be removed later easily.
+
+### `.gitlab-ci.yml`
+
+These variables modify the pipeline:
+
+- `BUILD_TESTS`: Set this to `false` to disable unit tests.
+- `BUILD_CTEST`: Set this to `false` to disable ctest (benchmark) tests.
+- `CTEST_INCLUDE_REGEX`: Set this to a regex to select benchmarks to run, e.g. `nb` would select all notebook-based tests and would disable all other benchmarks.
+
+All jobs get included in the `include:`-section. You can simple comment out files to disable jobs defined in that files. Please note that some jobs depend on other jobs.
+
+### `scripts/ci/jobs/*.yml`
+
+All jobs are defined in these files. You can disable a single job by prefixing its name with a dot, e.g.:
+
+```yml
+# enabled job:
+build linux arch:
+
+# disabled job:
+.build linux arch:
+```
diff --git a/web/content/docs/devguide/testing/test-data/index.md b/web/content/docs/devguide/testing/test-data/index.md
index a96f63d0f6180ecbdb7d57bea40565bcd9f1e3cc..b115b206ea6ea66cbf31108d264a9a885503b767 100644
--- a/web/content/docs/devguide/testing/test-data/index.md
+++ b/web/content/docs/devguide/testing/test-data/index.md
@@ -107,3 +107,17 @@ Then e.g. run all notebook test (`-R nb`) in parallel with:
 source .venv/bin/activate # May need to be activated
 ctest -R nb -j 4 --output-on-failure
 ```
+
+<div class='note'>
+
+### PyVista notebooks on headless Linux systems
+
+PyVista (or VTK) requires a windowing environment for rendering. You can provide a virtual window with `xvfb-run`:
+
+```bash
+sudo apt install libgl1-mesa-glx xvbf # install xvfb
+
+xvfb-run -a ctest [...] # provide a virtual window to the ctest-run
+```
+
+</div>