Kotlin Ultimate: Support Jest run configurations for Kotlin sources
#KT-21531 Fixed
This commit is contained in:
@@ -4,5 +4,6 @@
|
||||
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.nodejs.mocha.KotlinMochaRunConfigurationProducer"/>
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.nodejs.protractor.KotlinProtractorRunConfigurationProducer"/>
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.nodejs.jest.KotlinJestRunConfigurationProducer"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.nodejs.jest
|
||||
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.javascript.jest.JestRunConfiguration
|
||||
import com.intellij.javascript.jest.JestRunConfigurationProducer
|
||||
import com.intellij.javascript.jest.JestRunSettings
|
||||
import com.intellij.javascript.jest.scope.JestScopeKind
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
|
||||
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.nodejs.TestElementInfo
|
||||
import org.jetbrains.kotlin.idea.nodejs.TestElementPath
|
||||
import org.jetbrains.kotlin.idea.nodejs.getNodeJsEnvironmentVars
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.module
|
||||
|
||||
private typealias JestTestElementInfo = TestElementInfo<JestRunSettings>
|
||||
|
||||
class KotlinJestRunConfigurationProducer : JestRunConfigurationProducer() {
|
||||
private fun createTestElementRunInfo(element: PsiElement, originalSettings: JestRunSettings): JestTestElementInfo? {
|
||||
val module = element.module?.jsOrJsImpl() ?: return null
|
||||
val project = module.project
|
||||
val testFilePath = module.jsTestOutputFilePath ?: return null
|
||||
val settings = if (originalSettings.workingDirSystemDependentPath.isBlank()) {
|
||||
val workingDir = FileUtil.toSystemDependentName(project.baseDir.path)
|
||||
originalSettings.toBuilder().setWorkingDir(workingDir).build()
|
||||
} else originalSettings
|
||||
val testElementPath = TestElementPath.forElement(element, module) ?: return null
|
||||
val builder = settings.toBuilder()
|
||||
builder.setTestFilePath(testFilePath)
|
||||
when (testElementPath) {
|
||||
is TestElementPath.BySuite -> {
|
||||
val (suiteNames, testName) = testElementPath
|
||||
if (testName == null) {
|
||||
builder.setScopeKind(JestScopeKind.SUITE)
|
||||
builder.setTestNames(suiteNames)
|
||||
} else {
|
||||
builder.setScopeKind(JestScopeKind.TEST)
|
||||
builder.setTestNames(suiteNames + testName)
|
||||
}
|
||||
}
|
||||
|
||||
is TestElementPath.BySingleFile -> {
|
||||
builder.setScopeKind(JestScopeKind.TEST_FILE)
|
||||
}
|
||||
}
|
||||
builder.setEnvData(module.getNodeJsEnvironmentVars())
|
||||
|
||||
return JestTestElementInfo(builder.build(), element)
|
||||
}
|
||||
|
||||
override fun isConfigurationFromCompatibleContext(configuration: JestRunConfiguration, context: ConfigurationContext): Boolean {
|
||||
val element = context.psiLocation ?: return false
|
||||
val (thisRunSettings, _) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
|
||||
val thatRunSettings = configuration.runSettings
|
||||
|
||||
if (thisRunSettings.configFileSystemDependentPath != thatRunSettings.configFileSystemDependentPath) return false
|
||||
if (thatRunSettings.scopeKind != thisRunSettings.scopeKind) return false
|
||||
return when (thisRunSettings.scopeKind) {
|
||||
JestScopeKind.ALL -> true
|
||||
JestScopeKind.TEST_FILE -> thisRunSettings.testFileSystemDependentPath == thatRunSettings.testFileSystemDependentPath
|
||||
JestScopeKind.SUITE, JestScopeKind.TEST ->
|
||||
thisRunSettings.testFileSystemDependentPath == thatRunSettings.testFileSystemDependentPath &&
|
||||
thisRunSettings.testNames == thatRunSettings.testNames
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupConfigurationFromCompatibleContext(
|
||||
configuration: JestRunConfiguration,
|
||||
context: ConfigurationContext,
|
||||
sourceElement: Ref<PsiElement>
|
||||
): Boolean {
|
||||
val element = context.psiLocation ?: return false
|
||||
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 false
|
||||
|
||||
val (runSettings, enclosingTestElement) = createTestElementRunInfo(element, configuration.runSettings) ?: return false
|
||||
configuration.runSettings = runSettings
|
||||
sourceElement.set(enclosingTestElement)
|
||||
configuration.setGeneratedName()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.nodejs
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.getModuleDir
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
data class TestElementInfo<out Settings>(val runSettings: Settings, val enclosingTestElement: PsiElement)
|
||||
|
||||
sealed class TestElementPath {
|
||||
data class BySuite(val suiteNames: List<String>, val testName: String?) : TestElementPath()
|
||||
object BySingleFile : TestElementPath()
|
||||
|
||||
companion object {
|
||||
fun isModuleAssociatedDir(element: PsiElement, module: Module): Boolean {
|
||||
return element is PsiDirectory && module.getModuleDir() == element.virtualFile.path
|
||||
}
|
||||
|
||||
fun forElement(element: PsiElement, module: Module): TestElementPath? {
|
||||
if (isModuleAssociatedDir(element, module)) return TestElementPath.BySingleFile
|
||||
|
||||
val declaration = element.getNonStrictParentOfType<KtNamedDeclaration>() ?: return null
|
||||
val klass = when (declaration) {
|
||||
is KtClassOrObject -> declaration
|
||||
is KtNamedFunction -> declaration.containingClassOrObject ?: return null
|
||||
else -> return null
|
||||
}
|
||||
val suiteNames = klass.parentsWithSelf
|
||||
.filterIsInstance<KtClassOrObject>()
|
||||
.mapNotNull { it.name }
|
||||
.toList()
|
||||
.asReversed()
|
||||
val testName = (declaration as? KtNamedFunction)?.name
|
||||
return TestElementPath.BySuite(suiteNames, testName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-41
@@ -18,15 +18,12 @@ package org.jetbrains.kotlin.idea.nodejs.mocha
|
||||
|
||||
import com.intellij.execution.RunManager
|
||||
import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import com.intellij.util.SmartList
|
||||
@@ -35,25 +32,14 @@ import com.jetbrains.nodejs.mocha.MochaUtil
|
||||
import com.jetbrains.nodejs.mocha.execution.*
|
||||
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
|
||||
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.nodejs.TestElementInfo
|
||||
import org.jetbrains.kotlin.idea.nodejs.TestElementPath
|
||||
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
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
private typealias MochaTestElementInfo = TestElementInfo<MochaRunSettings>
|
||||
|
||||
class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
private data class TestElementInfo(val runSettings: MochaRunSettings, val enclosingTestElement: PsiElement)
|
||||
private sealed class TestElementPath {
|
||||
data class BySuite(val suiteNames: List<String>, val testName: String?) : TestElementPath()
|
||||
object BySingleFile : TestElementPath()
|
||||
}
|
||||
|
||||
// Copied from MochaRunConfigurationProducer.collectMochaTestRoots()
|
||||
private fun collectMochaTestRoots(project: Project): List<VirtualFile> {
|
||||
return RunManager
|
||||
@@ -103,27 +89,7 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
return VfsUtilCore.isUnder(file, dirs)
|
||||
}
|
||||
|
||||
private fun createSuiteOrTestData(element: PsiElement, module: Module): TestElementPath? {
|
||||
if (element is PsiDirectory && module.getModuleDir() == element.virtualFile.path) {
|
||||
return TestElementPath.BySingleFile
|
||||
}
|
||||
|
||||
val declaration = element.getNonStrictParentOfType<KtNamedDeclaration>() ?: return null
|
||||
val klass = when (declaration) {
|
||||
is KtClassOrObject -> declaration
|
||||
is KtNamedFunction -> declaration.containingClassOrObject ?: return null
|
||||
else -> return null
|
||||
}
|
||||
val suiteNames = klass.parentsWithSelf
|
||||
.filterIsInstance<KtClassOrObject>()
|
||||
.mapNotNull { it.name }
|
||||
.toList()
|
||||
.asReversed()
|
||||
val testName = (declaration as? KtNamedFunction)?.name
|
||||
return TestElementPath.BySuite(suiteNames, testName)
|
||||
}
|
||||
|
||||
private fun createTestElementRunInfo(element: PsiElement, originalSettings: MochaRunSettings): TestElementInfo? {
|
||||
private fun createTestElementRunInfo(element: PsiElement, originalSettings: MochaRunSettings): MochaTestElementInfo? {
|
||||
val module = element.module?.jsOrJsImpl() ?: return null
|
||||
val project = module.project
|
||||
val testFilePath = module.jsTestOutputFilePath ?: return null
|
||||
@@ -132,7 +98,7 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
originalSettings.builder().setWorkingDir(workingDir).build()
|
||||
}
|
||||
else originalSettings
|
||||
val testElementPath = createSuiteOrTestData(element, module) ?: return null
|
||||
val testElementPath = TestElementPath.forElement(element, module) ?: return null
|
||||
val builder = settings.builder()
|
||||
builder.setTestFilePath(testFilePath)
|
||||
if (settings.ui.isEmpty()) {
|
||||
@@ -158,7 +124,7 @@ class KotlinMochaRunConfigurationProducer : MochaRunConfigurationProducer() {
|
||||
|
||||
builder.setEnvData(module.getNodeJsEnvironmentVars())
|
||||
|
||||
return TestElementInfo(builder.build(), element)
|
||||
return MochaTestElementInfo(builder.build(), element)
|
||||
}
|
||||
|
||||
override fun isConfigurationFromCompatibleContext(configuration: MochaRunConfiguration, context: ConfigurationContext): Boolean {
|
||||
|
||||
+2
-7
@@ -21,17 +21,12 @@ import com.intellij.execution.actions.ConfigurationContext
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
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.facet.implementingModules
|
||||
import org.jetbrains.kotlin.idea.js.jsOrJsImpl
|
||||
import org.jetbrains.kotlin.idea.js.jsTestOutputFilePath
|
||||
import org.jetbrains.kotlin.idea.nodejs.TestElementPath
|
||||
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
|
||||
|
||||
class KotlinProtractorRunConfigurationProducer :
|
||||
CompatibleRunConfigurationProducer<KotlinProtractorRunConfiguration>(KotlinProtractorConfigurationType.getInstance()) {
|
||||
@@ -52,7 +47,7 @@ class KotlinProtractorRunConfigurationProducer :
|
||||
): Boolean {
|
||||
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 (!TestElementPath.isModuleAssociatedDir(element, module)) return false
|
||||
val jsModule = module.jsOrJsImpl() ?: return false
|
||||
val testFilePath = jsModule.jsTestOutputFilePath ?: return false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user