diff --git a/doc/dev/containerTest.md b/doc/dev/containerTest.md
index d123174..cb42131 100644
--- a/doc/dev/containerTest.md
+++ b/doc/dev/containerTest.md
@@ -1,11 +1,15 @@
-Should be added in dev_circumstances for single unit tests to get repeatable results ('fresh container'): 
-ContainerStartMode.CREATE_NEW_KILL_EXISTING
+# Container Tests
 
-like this way:
-+import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
+The method `defaultTestContainer()` provides a prov instance in a container for integration-tests.  
 
-//annotate to ContainerTest
-+@ContainerTest
+Container-tests should be annotated by tag: `@ContainerTest` and if long-lasting (ca. > 10 - 20 sec) with @ExtensiveContainerTest 
+
+
+For performance reasons the test container is re-used among the tests.
+
+In case you want a fresh container for your test, add the following option: 
+
+`ContainerStartMode.CREATE_NEW_KILL_EXISTING` 
+
+example: `val container = defaultTestContainer(ContainerStartMode.CREATE_NEW_KILL_EXISTING)`
 
-//and configured Testcontainer
-+val container = defaultTestContainer(ContainerStartMode.CREATE_NEW_KILL_EXISTING)
\ No newline at end of file
diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt
index c6d9d79..657871c 100644
--- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt
+++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt
@@ -2,14 +2,17 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure
 
 import org.domaindrivenarchitecture.provs.framework.core.Prov
 import org.domaindrivenarchitecture.provs.framework.core.ProvResult
-import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackageInstalled
 
+/**
+ * Installs ShadowCljs. Prerequisite: NVM and NPM are installed, otherwise fails.
+ */
 fun Prov.installShadowCljs(): ProvResult = task {
 
-    if (!isPackageInstalled("shadow-cljs")) {
-        cmd(". .nvm/nvm.sh && npm install -g shadow-cljs")
-        cmd(". .nvm/nvm.sh && shadow-cljs --help")
+    if (!chk(". .nvm/nvm.sh")) {
+        addProvResult(false, err = "nvm not installed!")
     } else {
-        ProvResult(true, out = "shadow-cljs already installed")
+        if (!chk("npm list -g --depth=0 | grep shadow-cljs")) {
+            cmd(". .nvm/nvm.sh && npm install -g shadow-cljs")
+        }
     }
 }
diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt
index c46fb75..b3b37dc 100644
--- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt
+++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt
@@ -3,16 +3,16 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure
 import org.domaindrivenarchitecture.provs.framework.core.Prov
 import org.domaindrivenarchitecture.provs.framework.core.ProvResult
 import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.*
-import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackageInstalledCheckCommand
+import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.checkCommand
 import org.domaindrivenarchitecture.provs.framework.ubuntu.web.base.downloadFromURL
 
+//from https://go.dev/dl/
 fun Prov.installGo(
-    //from https://go.dev/dl/
     version: String = "1.23.5",
     enforceVersion: Boolean = false,
     sha256sum: String = "cbcad4a6482107c7c7926df1608106c189417163428200ce357695cc7e01d091"
 ) = taskWithResult {
-    if (isPackageInstalledCheckCommand("go") && !enforceVersion) {
+    if (checkCommand("go") && !enforceVersion) {
         return@taskWithResult ProvResult(true)
     }
 
diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt
index 344f8c2..0bcf674 100644
--- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt
+++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt
@@ -2,39 +2,34 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure
 
 import org.domaindrivenarchitecture.provs.framework.core.Prov
 import org.domaindrivenarchitecture.provs.framework.core.ProvResult
+import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile
 import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile
 import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.userHome
-import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackageInstalledCheckCommand
 
-fun Prov.installNpmByNvm(): ProvResult = task {
+/**
+ * Installs Node.js and NPM (Node Package Manager) by using NVM (Node Version Manager), if NVM not already installed
+ */
+fun Prov.installNpmByNvm(version: String = "0.40.1"): ProvResult = task {
 
-    if (!isPackageInstalledCheckCommand("npm")) {
-        //Node-Version-Manager from https://github.com/nvm-sh/nvm
-        val version = "0.40.1"
+    //see Node-Version-Manager at https://github.com/nvm-sh/nvm
+
+    val bashConfigFile = "~/.bashrc.d/npmbynvm.sh"
+    if (!checkFile(".nvm/nvm.sh") && !checkFile(bashConfigFile)) {
+
+        // install NVM
         cmd("sudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v$version/install.sh | bash")
-
         cmd("chmod 755 .nvm/nvm.sh")
 
+        // configure bash - create file ".bashrc.d/npmbynvm.sh" with settings
         configureBashForUser()
-        createFile("~/.bashrc.d/npmbynvm.sh", """export NVM_DIR="${userHome()}.nvm" """ + "\n"
-        + """[ -s "${"\$NVM_DIR/nvm.sh"}" ] && \. "${"\$NVM_DIR/nvm.sh"}" """ + "\n")
 
+        val content = """
+            export NVM_DIR="${userHome()}.nvm"
+            [ -s "${"\$NVM_DIR/nvm.sh"}" ] && \. "${"\$NVM_DIR/nvm.sh"}"
+            """.trimIndent()
+        createFile(bashConfigFile, content)
+
+        // install Node.js and NPM
         cmd(". .nvm/nvm.sh && nvm install --lts")
-
-        val nvmRes = cmd(". .nvm/nvm.sh && nvm --version").toString()
-        if (version == nvmRes) {
-            println("NVM version $version")
-            addResultToEval(ProvResult(true, out = "SUCCESS: NVM version $version installed !!"))
-        } else {
-            println("FAIL: NVM version $version is not installed !!")
-            addResultToEval(ProvResult(true, out = "FAIL: NVM version $version is not installed !!"))
-        }
-        cmd(". .nvm/nvm.sh && node -v")
-        cmd(". .nvm/nvm.sh && npm --version")
-
-    } else {
-        addResultToEval(ProvResult(true, out = "npm already installed"))
     }
-
-
 }
\ No newline at end of file
diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt
index 2b059c8..8ad433a 100644
--- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt
+++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt
@@ -217,11 +217,12 @@ open class Prov protected constructor(
     fun getSecret(command: String, removeNewlineSuffix: Boolean = false): Secret? {
         val result = cmdNoLog(command)
         return if (result.success && result.out != null) {
-            addResultToEval(ProvResult(true, getCallingMethodName()))
-            val plainSecret = if (removeNewlineSuffix && result.out.takeLast(1) == "\n") result.out.dropLast(1) else result.out
+            addProvResult(true, getCallingMethodName())
+            val plainSecret =
+                if (removeNewlineSuffix && result.out.takeLast(1) == "\n") result.out.dropLast(1) else result.out
             Secret(plainSecret)
         } else {
-            addResultToEval(ProvResult(false, getCallingMethodName(), err = result.err, exception = result.exception))
+            addProvResult(false, getCallingMethodName(), err = result.err, exception = result.exception)
             null
         }
     }
@@ -231,10 +232,26 @@ open class Prov protected constructor(
      * Adds a ProvResult to the overall success evaluation.
      * Intended for use in methods which do not automatically add results.
      */
+    @Deprecated("since 0.39.7", replaceWith = ReplaceWith("addProvResult", ))
     fun addResultToEval(result: ProvResult) = taskWithResult {
         result
     }
 
+    /**
+     * Adds a ProvResult to the overall success evaluation.
+     * Intended for use in methods which do not automatically add results.
+     */
+    fun addProvResult(
+        success: Boolean,
+        cmd: String? = null,
+        out: String? = null,
+        err: String? = null,
+        exception: Exception? = null,
+        exit: String? = null
+    ) = taskWithResult {
+        ProvResult(success, cmd, out, err, exception, exit)
+    }
+
     /**
      * Executes multiple shell commands. Each command must be in its own line.
      * Multi-line commands within the script are not supported.
diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt
index 10db980..5eb86eb 100644
--- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt
+++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt
@@ -16,9 +16,9 @@ private var aptInit = false
 @Suppress("UNUSED_PARAMETER")  // ignoreAlreadyInstalled is added for external usage
 fun Prov.aptInstall(packages: String, ignoreAlreadyInstalled: Boolean = true): ProvResult = taskWithResult {
     val packageList = packages.split(" ")
-    val allInstalled: Boolean = packageList.map { isPackageInstalled(it) }.fold(true, { a, b -> a && b })
+    val allInstalled: Boolean = packageList.map { checkPackage(it) }.fold(true, { a, b -> a && b })
     if (!allInstalled) {
-        if (!isPackageInstalled(packages)) {
+        if (!checkPackage(packages)) {
             if (!aptInit) {
                 optional {
                     // may fail for some packages, but this should in general not be an issue
@@ -31,8 +31,7 @@ fun Prov.aptInstall(packages: String, ignoreAlreadyInstalled: Boolean = true): P
 
         for (packg in packageList) {
             // see https://superuser.com/questions/164553/automatically-answer-yes-when-using-apt-get-install
-            cmd("sudo apt-get install -q=2 $packg")
-            //DEBIAN_FRONTEND=noninteractive
+            cmd("sudo DEBIAN_FRONTEND=noninteractive apt-get install -q=2 $packg")
         }
         ProvResult(true) // dummy
     } else {
@@ -71,20 +70,36 @@ fun Prov.aptInstallFromPpa(launchPadUser: String, ppaName: String, packageName:
 /**
  * Returns true if a package is installed else false
  */
+@Deprecated("since 0.39.7", replaceWith = ReplaceWith("checkPackage"))
 fun Prov.isPackageInstalled(packageName: String): Boolean {
     return chk("dpkg -s $packageName")
 }
 
+/**
+ * Returns true if a package is installed else false
+ */
+fun Prov.checkPackage(packageName: String): Boolean {
+    return chk("dpkg -s $packageName")
+}
+
 
 /**
  * Returns true if a package is installed else false
  */
+@Deprecated("since 0.39.7", replaceWith = ReplaceWith("checkPackage"))
 fun Prov.checkPackageInstalled(packageName: String): ProvResult = taskWithResult {
     cmd("dpkg -s $packageName")
 }
 
-fun Prov.isPackageInstalledCheckCommand(packageName: String): Boolean {
-    return chk("command -v $packageName")
+/**
+ * Returns true if a command is available else false.
+ * Can be used e.g. to check if software is installed in case it is not installed as debian package.
+ * ATTENTION:
+ * * checks only commands which are available in the shell
+ * * does NOT find commands which are defined in .bashrc when running in a non-interactive shell (which is the case with: `bash -c "command -v mycommand"`),
+ */
+fun Prov.checkCommand(commandName: String): Boolean {
+    return chk("command -v $commandName")
 }
 
 /**
diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt
index 4fa402f..2a3d042 100644
--- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt
+++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt
@@ -1,7 +1,11 @@
 package org.domaindrivenarchitecture.provs.desktop.infrastructure
 
+import org.domaindrivenarchitecture.provs.framework.core.processors.ContainerStartMode
+import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
 import org.domaindrivenarchitecture.provs.test.defaultTestContainer
 import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
+import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest
+import org.junit.jupiter.api.Assertions.assertFalse
 import org.junit.jupiter.api.Assertions.assertTrue
 
 internal class ClojureScriptKtTest {
@@ -10,19 +14,30 @@ internal class ClojureScriptKtTest {
     fun installShadowCljs() {
         // given
         val prov = defaultTestContainer()
-
-        //Todo:
-        // To be discussed, should init container, but not available for prov.installShadowCljs() !!
-        // Howto work in addition prov.a() + prov.b()?
-        prov.installNpmByNvm()
+        prov.task {
+            aptInstall("curl")
+            installNpmByNvm()
+        }
 
         // when
-        // check if it can be run twice successfully
-        val res01 = prov.installShadowCljs()
-        val res02 = prov.installShadowCljs()
+        val res = prov.task {
+            installShadowCljs()
+            installShadowCljs()  // check repeatability
+        }
 
         // then
-        assertTrue(res01.success)
-        assertTrue(res02.success)
+        assertTrue(res.success)
+    }
+
+    @ExtensiveContainerTest  // extensive test, as it kills the existing container and creates a new one
+    fun installShadowCljs_fails_if_nvm_missing() {
+        // given
+        val prov = defaultTestContainer(ContainerStartMode.CREATE_NEW_KILL_EXISTING)
+
+        // when
+        val res = prov.installShadowCljs()
+
+        // then
+        assertFalse(res.success)
     }
 }
\ No newline at end of file
diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt
index 3d8866a..3dacbf3 100644
--- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt
+++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt
@@ -7,16 +7,22 @@ import org.junit.jupiter.api.Assertions.assertTrue
 
 internal class NpmByNvmKtTest {
 
- @ContainerTest
-  fun installNVMnpm() {
-     // given
-     val container = defaultTestContainer()
-     container.aptInstall("curl")
-     // when
-     val res01 = container.installNpmByNvm()
-     val res02 = container.installNpmByNvm()
-     // then
-     assertTrue(res01.success)
-     assertTrue(res02.success)
-  }
+    @ContainerTest
+    fun installNVMnpm() {
+        // given
+        val prov = defaultTestContainer()
+        prov.aptInstall("curl")
+
+        // when
+        val res = prov.task {
+            installNpmByNvm()
+            installNpmByNvm()  // check repeatability
+            // check if node and npm are installed and can be called in a shell (with sourcing nvm.sh)
+            cmd(". .nvm/nvm.sh && node -v")
+            cmd(". .nvm/nvm.sh && npm --version")
+        }
+
+        // then
+        assertTrue(res.success)
+    }
 }
\ No newline at end of file