diff --git a/src/io/pivotal/intellij/jasmine/JasmineConfigurationEditor.kt b/src/io/pivotal/intellij/jasmine/JasmineConfigurationEditor.kt index 038c7a9..01dcb73 100644 --- a/src/io/pivotal/intellij/jasmine/JasmineConfigurationEditor.kt +++ b/src/io/pivotal/intellij/jasmine/JasmineConfigurationEditor.kt @@ -1,43 +1,85 @@ package io.pivotal.intellij.jasmine -import com.intellij.execution.configuration.EnvironmentVariablesComponent +import com.intellij.execution.configuration.EnvironmentVariablesTextFieldWithBrowseButton import com.intellij.javascript.nodejs.interpreter.NodeJsInterpreterField import com.intellij.javascript.nodejs.util.NodePackageField +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.options.SettingsEditor import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.TextFieldWithBrowseButton +import com.intellij.openapi.util.io.FileUtil +import com.intellij.ui.RawCommandLineEditor +import com.intellij.ui.components.fields.ExpandableTextField +import com.intellij.util.ui.ComponentWithEmptyText import com.intellij.util.ui.FormBuilder +import com.intellij.util.ui.SwingHelper import javax.swing.JComponent import javax.swing.JPanel -class JasmineConfigurationEditor(project: Project) : SettingsEditor() { +class JasmineConfigurationEditor(private var project: Project) : SettingsEditor() { private var nodeJsInterpreterField: NodeJsInterpreterField = NodeJsInterpreterField(project, false) + private var nodeOptionsField: RawCommandLineEditor = RawCommandLineEditor() + private var workingDirectoryField = createWorkingDirectoryField() + private var envVars: EnvironmentVariablesTextFieldWithBrowseButton = EnvironmentVariablesTextFieldWithBrowseButton() private var jasminePackageField: NodePackageField = NodePackageField(nodeJsInterpreterField, "jasmine") - private var envVars: EnvironmentVariablesComponent = EnvironmentVariablesComponent() + private var jasmineOptionsField = createJasmineOptionsField() private var rootForm: JPanel init { + nodeOptionsField.dialogCaption = "Node Options" rootForm = FormBuilder() .setAlignLabelOnRight(false) - .addLabeledComponent("Node interpreter", nodeJsInterpreterField) - .addLabeledComponent("Jasmine package", jasminePackageField) - .addComponent(envVars) + .addLabeledComponent("Node &interpreter", nodeJsInterpreterField) + .addLabeledComponent("Node &options", nodeOptionsField) + .addLabeledComponent("&Working directory", workingDirectoryField) + .addLabeledComponent("&Environment variables", envVars) + .addLabeledComponent("&Jasmine package", jasminePackageField) + .addLabeledComponent("E&xtra Jasmine options", jasmineOptionsField) .panel } + private fun createWorkingDirectoryField(): TextFieldWithBrowseButton { + val field = TextFieldWithBrowseButton() + SwingHelper.installFileCompletionAndBrowseDialog(project, field, "Jasmine Working Directory", + FileChooserDescriptorFactory.createSingleFolderDescriptor()) + return field + } + + private fun createJasmineOptionsField(): RawCommandLineEditor { + val editor = RawCommandLineEditor() + editor.dialogCaption = "Extra Jasmine Options" + val field = editor.textField + if (field is ExpandableTextField) { + field.putClientProperty("monospaced", false) + } + + if (field is ComponentWithEmptyText) { + (field as ComponentWithEmptyText).emptyText.text = "CLI options, e.g. --fail-fast=true" + } + + return editor + } + override fun createEditor(): JComponent = rootForm override fun applyEditorTo(config: JasmineRunConfiguration) { - config.nodeJs = nodeJsInterpreterField.interpreterRef + config.jasmineRunSettings = config.jasmineRunSettings.copy( + nodeJs = nodeJsInterpreterField.interpreterRef, + nodeOptions = nodeOptionsField.text, + workingDir = workingDirectoryField.text, + envData = envVars.data, + extraJasmineOptions = jasmineOptionsField.text) config.setJasminePackage(jasminePackageField.selected) - config.envData = envVars.envData } override fun resetEditorFrom(config: JasmineRunConfiguration) { - nodeJsInterpreterField.interpreterRef = config.nodeJs + val runSettings = config.jasmineRunSettings + nodeJsInterpreterField.interpreterRef = runSettings.nodeJs + nodeOptionsField.text = runSettings.nodeOptions + workingDirectoryField.text = FileUtil.toSystemDependentName(runSettings.workingDir) + envVars.data = runSettings.envData jasminePackageField.selected = config.selectedJasminePackage() - if (config.envData != null) { - envVars.envData = config.envData!! - } + jasmineOptionsField.text = runSettings.extraJasmineOptions } } diff --git a/src/io/pivotal/intellij/jasmine/JasmineConfigurationType.kt b/src/io/pivotal/intellij/jasmine/JasmineConfigurationType.kt index f869a9a..827b8e0 100644 --- a/src/io/pivotal/intellij/jasmine/JasmineConfigurationType.kt +++ b/src/io/pivotal/intellij/jasmine/JasmineConfigurationType.kt @@ -20,11 +20,6 @@ class JasmineConfigurationType : ConfigurationTypeBase("JavascriptTestRunnerJasm fun getInstance(): JasmineConfigurationType { return Holder.INSTANCE } - - fun getFactory(): ConfigurationFactory { - val type = getInstance() - return type.getConfigurationFactories()[0] - } } diff --git a/src/io/pivotal/intellij/jasmine/JasmineRunConfiguration.kt b/src/io/pivotal/intellij/jasmine/JasmineRunConfiguration.kt index aa0b415..2c2d2b9 100644 --- a/src/io/pivotal/intellij/jasmine/JasmineRunConfiguration.kt +++ b/src/io/pivotal/intellij/jasmine/JasmineRunConfiguration.kt @@ -1,20 +1,17 @@ package io.pivotal.intellij.jasmine import com.intellij.execution.Executor -import com.intellij.execution.configuration.EnvironmentVariablesData import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.configurations.LocatableConfigurationBase import com.intellij.execution.runners.ExecutionEnvironment -import com.intellij.javascript.nodejs.interpreter.NodeJsInterpreterRef import com.intellij.javascript.nodejs.interpreter.local.NodeJsLocalInterpreter import com.intellij.javascript.nodejs.util.NodePackage import com.intellij.openapi.project.Project class JasmineRunConfiguration(project: Project, factory: ConfigurationFactory, name: String) : LocatableConfigurationBase(project, factory, name) { - var nodeJs = NodeJsInterpreterRef.createProjectRef() + var jasmineRunSettings = JasmineRunSettings() private var _jasminePackage: NodePackage? = null - var envData: EnvironmentVariablesData? = null override fun getConfigurationEditor() = JasmineConfigurationEditor(project) @@ -22,7 +19,7 @@ class JasmineRunConfiguration(project: Project, factory: ConfigurationFactory, n fun selectedJasminePackage(): NodePackage { if (_jasminePackage == null) { - val interpreter = NodeJsLocalInterpreter.tryCast(nodeJs.resolve(project)) + val interpreter = NodeJsLocalInterpreter.tryCast(jasmineRunSettings.nodeJs.resolve(project)) val pkg = NodePackage.findPreferredPackage(project, "Jasmine", interpreter) _jasminePackage = pkg return pkg diff --git a/src/io/pivotal/intellij/jasmine/JasmineRunConfigurationProducer.kt b/src/io/pivotal/intellij/jasmine/JasmineRunConfigurationProducer.kt index 3376835..a97b237 100644 --- a/src/io/pivotal/intellij/jasmine/JasmineRunConfigurationProducer.kt +++ b/src/io/pivotal/intellij/jasmine/JasmineRunConfigurationProducer.kt @@ -1,16 +1,57 @@ -package io.pivotal.intellij.jasmine; +package io.pivotal.intellij.jasmine -import com.intellij.execution.actions.ConfigurationContext; -import com.intellij.execution.actions.RunConfigurationProducer; -import com.intellij.openapi.util.Ref; -import com.intellij.psi.PsiElement; +import com.google.common.collect.ImmutableList +import com.intellij.execution.actions.ConfigurationContext +import com.intellij.javascript.testing.JsTestRunConfigurationProducer +import com.intellij.lang.javascript.psi.JSFile +import com.intellij.openapi.util.Ref +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFileSystemItem +import com.intellij.psi.util.PsiUtilCore +import com.intellij.util.ObjectUtils.tryCast -class JasmineRunConfigurationProducer : RunConfigurationProducer(JasmineConfigurationType.getInstance()) { +class JasmineRunConfigurationProducer : JsTestRunConfigurationProducer(JasmineConfigurationType.getInstance(), ImmutableList.of("jasmine")) { + override fun isConfigurationFromCompatibleContext(runConfig: JasmineRunConfiguration, context: ConfigurationContext): Boolean { + val element = context.psiLocation ?: return false + val currentFile = PsiUtilCore.getVirtualFile(element) ?: return false + if (currentFile.isDirectory) { + // not sure the right way to run a dir + return false + } - override fun setupConfigurationFromContext(runConfig: JasmineRunConfiguration, - config: ConfigurationContext, - sourceElement: Ref) = true + val psiFile = tryCast(element.containingFile, JSFile::class.java) ?: return false + psiFile.testFileType ?: return false - override fun isConfigurationFromContext(p0: JasmineRunConfiguration?, - p1: ConfigurationContext?) = true +// if (element is PsiFileSystemItem) { + runConfig.jasmineRunSettings = runConfig.jasmineRunSettings.copy( + specFile = currentFile.path + ) +// } else return false + + return true + } + + override fun setupConfigurationFromCompatibleContext(runConfig: JasmineRunConfiguration, context: ConfigurationContext, sourceElement: Ref): Boolean { + val element = context.psiLocation ?: return false + val currentFile = PsiUtilCore.getVirtualFile(element) ?: return false + if (currentFile.isDirectory) { + // not sure the right way to run a dir + return false + } + + val psiFile = tryCast(element.containingFile, JSFile::class.java) ?: return false + + if (element is PsiFileSystemItem) { + psiFile.testFileType ?: return false + + runConfig.jasmineRunSettings = runConfig.jasmineRunSettings.copy( + specFile = currentFile.path + ) + sourceElement.set(psiFile) + runConfig.setGeneratedName() + } else return false + + + return true + } } diff --git a/src/io/pivotal/intellij/jasmine/JasmineRunProfileState.kt b/src/io/pivotal/intellij/jasmine/JasmineRunProfileState.kt index c7c54f1..0c173f2 100644 --- a/src/io/pivotal/intellij/jasmine/JasmineRunProfileState.kt +++ b/src/io/pivotal/intellij/jasmine/JasmineRunProfileState.kt @@ -14,6 +14,8 @@ import com.intellij.execution.ui.ConsoleView import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.FileUtil import com.intellij.util.PathUtil +import com.intellij.util.execution.ParametersListUtil +import org.apache.commons.lang.StringUtils import java.io.File import java.nio.file.Paths @@ -23,16 +25,36 @@ class JasmineRunProfileState(private var project: Project, environment: ExecutionEnvironment) : CommandLineState(environment) { override fun startProcess(): ProcessHandler { - val interpreter = runConfig.nodeJs.resolveAsLocal(project) + val runSettings = runConfig.jasmineRunSettings + val interpreter = runSettings.nodeJs.resolveAsLocal(project) val commandLine = GeneralCommandLine() - commandLine.workDirectory = File(project.baseDir.path) + + if (StringUtils.isBlank(runSettings.workingDir)) { + commandLine.withWorkDirectory(project.baseDir.path) + } else { + commandLine.withWorkDirectory(runSettings.workingDir) + } + commandLine.exePath = interpreter.interpreterSystemDependentPath + runSettings.envData.configureCommandLine(commandLine, true) + + val nodeOptionsList = ParametersListUtil.parse(runSettings.nodeOptions.trim()) + commandLine.addParameters(nodeOptionsList) commandLine.addParameter(jasminePath(runConfig)) + + val jasmineOptionsList = ParametersListUtil.parse(runSettings.extraJasmineOptions.trim()) + commandLine.addParameters(jasmineOptionsList) + + if (!StringUtils.isBlank(runSettings.jasmineConfigFile)) { + commandLine.addParameter("--config=${runSettings.jasmineConfigFile}") + } + commandLine.addParameter("--reporter=${findReporterPath()}") - if (runConfig.envData != null) { - commandLine.environment.putAll(runConfig.envData!!.envs) + + if (!StringUtils.isBlank(runSettings.specFile)) { + commandLine.addParameter(runSettings.specFile) } val processHandler = KillableColoredProcessHandler(commandLine) diff --git a/src/io/pivotal/intellij/jasmine/JasmineRunProgramRunner.kt b/src/io/pivotal/intellij/jasmine/JasmineRunProgramRunner.kt index 34fe575..1c6d819 100644 --- a/src/io/pivotal/intellij/jasmine/JasmineRunProgramRunner.kt +++ b/src/io/pivotal/intellij/jasmine/JasmineRunProgramRunner.kt @@ -4,10 +4,7 @@ import com.intellij.execution.configurations.RunProfile import com.intellij.execution.configurations.RunProfileState import com.intellij.execution.configurations.RunnerSettings import com.intellij.execution.executors.DefaultRunExecutor -import com.intellij.execution.runners.ExecutionEnvironment -import com.intellij.execution.runners.GenericProgramRunner -import com.intellij.execution.runners.RerunTestsAction -import com.intellij.execution.runners.RunContentBuilder +import com.intellij.execution.runners.* import com.intellij.execution.ui.RunContentDescriptor import com.intellij.openapi.fileEditor.FileDocumentManager @@ -24,6 +21,7 @@ object JasmineRunProgramRunner : GenericProgramRunner() { val builder = RunContentBuilder(result, environment) val descriptor = builder.showRunContent(environment.contentToReuse) + RerunTestsNotification.showRerunNotification(environment.contentToReuse, result.executionConsole) RerunTestsAction.register(descriptor) return descriptor } diff --git a/src/io/pivotal/intellij/jasmine/JasmineRunSettings.kt b/src/io/pivotal/intellij/jasmine/JasmineRunSettings.kt new file mode 100644 index 0000000..4120b2e --- /dev/null +++ b/src/io/pivotal/intellij/jasmine/JasmineRunSettings.kt @@ -0,0 +1,14 @@ +package io.pivotal.intellij.jasmine + +import com.intellij.execution.configuration.EnvironmentVariablesData +import com.intellij.javascript.nodejs.interpreter.NodeJsInterpreterRef + +data class JasmineRunSettings( + var nodeJs : NodeJsInterpreterRef = NodeJsInterpreterRef.createProjectRef(), + var nodeOptions : String = "", + var workingDir : String = "", + var envData : EnvironmentVariablesData = EnvironmentVariablesData.DEFAULT, + var extraJasmineOptions : String = "", + var jasmineConfigFile : String = "", + var specFile : String = "" +) \ No newline at end of file