MPP: Support Mocha/Protractor run configuration for common modules

This is useful when they are implemented by JavaScript modules
This commit is contained in:
Alexey Sedunov
2017-10-26 15:08:00 +03:00
parent 3319fdba6d
commit 97332aaeea
6 changed files with 95 additions and 67 deletions
@@ -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
}
@@ -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
}
@@ -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