MPP: Support Mocha/Protractor run configuration for common modules
This is useful when they are implemented by JavaScript modules
This commit is contained in:
+7
-5
@@ -23,7 +23,6 @@ import com.intellij.execution.lineMarker.RunLineMarkerContributor
|
||||
import com.intellij.execution.testframework.TestIconMapper
|
||||
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -34,8 +33,10 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.js.getJsOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
|
||||
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.idea.util.string.joinWithEscape
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -45,6 +46,7 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform.Common
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
import javax.swing.Icon
|
||||
|
||||
@@ -108,8 +110,8 @@ class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
|
||||
private fun getJavaScriptTestIcon(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor): Icon? {
|
||||
if (!descriptor.isTest()) return null
|
||||
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(declaration) ?: return null
|
||||
val testFilePath = getJsOutputFilePath(module, true, false) ?: return null
|
||||
val module = declaration.module?.jsOrJsImpl() ?: return null
|
||||
val testFilePath = module.jsTestOutputFilePath ?: return null
|
||||
|
||||
val locations = ArrayList<String>()
|
||||
|
||||
@@ -146,7 +148,7 @@ class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
|
||||
val platform = TargetPlatformDetector.getPlatform(declaration.containingKtFile)
|
||||
val icon = when (platform) {
|
||||
is JvmPlatform -> getJavaTestIcon(declaration)
|
||||
is JsPlatform -> getJavaScriptTestIcon(declaration, descriptor)
|
||||
is JsPlatform, is Common -> getJavaScriptTestIcon(declaration, descriptor)
|
||||
else -> return null
|
||||
} ?: return null
|
||||
return RunLineMarkerContributor.Info(icon, { "Run Test" }, ExecutorAction.getActions())
|
||||
|
||||
@@ -19,14 +19,23 @@ package org.jetbrains.kotlin.idea.js
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.CompilerModuleExtension
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.idea.facet.implementingModules
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
|
||||
fun getJsOutputFilePath(module: Module, isTests: Boolean, isMeta: Boolean): String? {
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(module)
|
||||
val outputDir = (if (isTests) compilerExtension?.compilerOutputUrlForTests else compilerExtension?.compilerOutputUrl)
|
||||
?: return null
|
||||
val extension = if (isMeta) KotlinJavascriptMetadataUtils.META_JS_SUFFIX else KotlinJavascriptMetadataUtils.JS_EXT
|
||||
return JpsPathUtil.urlToPath("$outputDir/${module.name}${suffix(isTests)}$extension")
|
||||
}
|
||||
val Module.jsTestOutputFilePath: String?
|
||||
get() {
|
||||
(KotlinFacet.get(this)?.configuration?.settings?.testOutputPath)?.let { return it }
|
||||
|
||||
private fun suffix(isTests: Boolean) = if (isTests) "_test" else ""
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(this)
|
||||
val outputDir = compilerExtension?.compilerOutputUrlForTests ?: return null
|
||||
return JpsPathUtil.urlToPath("$outputDir/${name}_test.js")
|
||||
}
|
||||
|
||||
fun Module.jsOrJsImpl() = when (TargetPlatformDetector.getPlatform(this)) {
|
||||
is TargetPlatform.Common -> implementingModules.firstOrNull { TargetPlatformDetector.getPlatform(it) is JsPlatform }
|
||||
is JsPlatform -> this
|
||||
else -> null
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.js
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.CompilerModuleExtension
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
private fun addSingleModulePaths(target: Module, result: MutableList<String>) {
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(target) ?: return
|
||||
result.addIfNotNull(compilerExtension.compilerOutputPath?.path)
|
||||
result.addIfNotNull(compilerExtension.compilerOutputPathForTests?.let { "${it.path}/lib" })
|
||||
}
|
||||
|
||||
fun getJsClasspath(module: Module): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
ModuleRootManager.getInstance(module).orderEntries().recursively().forEachModule {
|
||||
addSingleModulePaths(it, result)
|
||||
true
|
||||
}
|
||||
return result
|
||||
}
|
||||
+17
-7
@@ -33,10 +33,12 @@ import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.SmartHashSet
|
||||
import com.jetbrains.nodejs.mocha.MochaUtil
|
||||
import com.jetbrains.nodejs.mocha.execution.*
|
||||
import org.jetbrains.kotlin.idea.js.getJsOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
|
||||
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.nodejs.getNodeJsEnvironmentVars
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.getModuleDir
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.module
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
@@ -74,12 +76,21 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
|
||||
// Copied from MochaRunConfigurationProducer.isActiveFor()
|
||||
private fun isActiveFor(element: PsiElement, context: ConfigurationContext): Boolean {
|
||||
val file = PsiUtilCore.getVirtualFile(element) ?: return false
|
||||
if (isTestRunnerPackageAvailableFor(element.project, file)) return true
|
||||
val module = element.module
|
||||
val jsModule = module?.jsOrJsImpl() ?: return false
|
||||
val file = if (jsModule != module) {
|
||||
jsModule.moduleFile
|
||||
}
|
||||
else {
|
||||
PsiUtilCore.getVirtualFile(element)
|
||||
} ?: return false
|
||||
val project = module.project
|
||||
|
||||
if (isTestRunnerPackageAvailableFor(project, file)) return true
|
||||
|
||||
if (context.getOriginalConfiguration(MochaConfigurationType.getInstance()) is MochaRunConfiguration) return true
|
||||
|
||||
val roots = collectMochaTestRoots(element.project)
|
||||
val roots = collectMochaTestRoots(project)
|
||||
if (roots.isEmpty()) return false
|
||||
|
||||
val dirs = SmartHashSet<VirtualFile>()
|
||||
@@ -113,10 +124,9 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
}
|
||||
|
||||
private fun createTestElementRunInfo(element: PsiElement, originalSettings: MochaRunSettings): TestElementInfo? {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null
|
||||
if (TargetPlatformDetector.getPlatform(module) !is JsPlatform) return null
|
||||
val module = element.module?.jsOrJsImpl() ?: return null
|
||||
val project = module.project
|
||||
val testFilePath = getJsOutputFilePath(module, true, false) ?: return null
|
||||
val testFilePath = module.jsTestOutputFilePath ?: return null
|
||||
val settings = if (originalSettings.workingDir.isBlank()) {
|
||||
val workingDir = FileUtil.toSystemDependentName(project.baseDir.path)
|
||||
originalSettings.builder().setWorkingDir(workingDir).build()
|
||||
|
||||
@@ -17,17 +17,59 @@
|
||||
package org.jetbrains.kotlin.idea.nodejs
|
||||
|
||||
import com.intellij.execution.configuration.EnvironmentVariablesData
|
||||
import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.CompilerModuleExtension
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.idea.js.getJsClasspath
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.plugins.gradle.model.ExternalProject
|
||||
import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataCache
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
const val NODE_PATH_VAR = "NODE_PATH"
|
||||
|
||||
fun Module.getNodeJsEnvironmentVars(): EnvironmentVariablesData {
|
||||
val nodeJsClasspath = getJsClasspath(this).joinToString(File.pathSeparator) {
|
||||
val nodeJsClasspath = getNodeJsClasspath(this).joinToString(File.pathSeparator) {
|
||||
val basePath = project.basePath ?: return@joinToString it
|
||||
FileUtil.getRelativePath(basePath, it, '/') ?: it
|
||||
}
|
||||
return EnvironmentVariablesData.create(mapOf(NODE_PATH_VAR to nodeJsClasspath), true)
|
||||
}
|
||||
|
||||
private fun addSingleModulePaths(target: Module, result: MutableList<String>) {
|
||||
val compilerExtension = CompilerModuleExtension.getInstance(target) ?: return
|
||||
result.addIfNotNull(compilerExtension.compilerOutputPath?.path)
|
||||
result.addIfNotNull(compilerExtension.compilerOutputPathForTests?.let { "${it.path}/lib" })
|
||||
}
|
||||
|
||||
private fun ExternalProject.findProjectById(id: String): ExternalProject? {
|
||||
if (this.id == id) return this
|
||||
for (childProject in childProjects.values) {
|
||||
childProject.findProjectById(id)?.let { return it }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getNodeJsClasspath(module: Module): List<String> {
|
||||
if (KotlinPluginUtil.isGradleModule(module)) {
|
||||
val gradleProjectPath = ExternalSystemModulePropertyManager.getInstance(module).getRootProjectPath()
|
||||
val projectCache = ExternalProjectDataCache.getInstance(module.project)
|
||||
val rootProject = projectCache.getRootExternalProject(GradleConstants.SYSTEM_ID, File(gradleProjectPath)) ?: return listOf()
|
||||
val externalProjectId = ExternalSystemApiUtil.getExternalProjectId(module) ?: return listOf()
|
||||
val buildDir = rootProject.findProjectById(externalProjectId)?.buildDir ?: return listOf()
|
||||
return listOfNotNull(PathUtil.toSystemIndependentName(buildDir.absolutePath) + "/nodejs_modules")
|
||||
}
|
||||
|
||||
val result = ArrayList<String>()
|
||||
ModuleRootManager.getInstance(module).orderEntries().recursively().forEachModule {
|
||||
addSingleModulePaths(it, result)
|
||||
true
|
||||
}
|
||||
return result
|
||||
}
|
||||
+9
-6
@@ -23,9 +23,12 @@ import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.js.getJsOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.facet.implementingModules
|
||||
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
|
||||
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.nodejs.getNodeJsEnvironmentVars
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform.Common
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.getModuleDir
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.module
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
@@ -37,8 +40,8 @@ class KotlinProtractorRunConfigurationProducer :
|
||||
context: ConfigurationContext
|
||||
): Boolean {
|
||||
val contextPsi = context.psiLocation ?: return false
|
||||
val module = contextPsi.module ?: return false
|
||||
val testFilePath = getJsOutputFilePath(module, isTests = true, isMeta = false) ?: return false
|
||||
val jsModule = contextPsi.module?.jsOrJsImpl() ?: return false
|
||||
val testFilePath = jsModule.jsTestOutputFilePath ?: return false
|
||||
return configuration.runSettings.testFileSystemDependentPath == FileUtil.toSystemDependentName(testFilePath)
|
||||
}
|
||||
|
||||
@@ -50,13 +53,13 @@ class KotlinProtractorRunConfigurationProducer :
|
||||
val element = context.psiLocation ?: return false
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return false
|
||||
if (element !is PsiDirectory || module.getModuleDir() != element.virtualFile.path) return false
|
||||
if (TargetPlatformDetector.getPlatform(module) !is JsPlatform) return false
|
||||
val testFilePath = getJsOutputFilePath(module, true, false) ?: return false
|
||||
val jsModule = module.jsOrJsImpl() ?: return false
|
||||
val testFilePath = jsModule.jsTestOutputFilePath ?: return false
|
||||
|
||||
sourceElement.set(element)
|
||||
configuration.runSettings = configuration.runSettings.copy(
|
||||
testFilePath = testFilePath,
|
||||
envData = module.getNodeJsEnvironmentVars()
|
||||
envData = jsModule.getNodeJsEnvironmentVars()
|
||||
)
|
||||
configuration.name = configuration.suggestedName()
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user