package com.intellij.javascript.karma.execution; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; import com.intellij.javascript.karma.scope.KarmaScopeKind; import com.intellij.javascript.karma.util.KarmaUtil; import com.intellij.javascript.testFramework.JsTestElementPath; import com.intellij.javascript.testFramework.PreferableRunConfiguration; import com.intellij.javascript.testFramework.jasmine.JasmineFileStructure; import com.intellij.javascript.testFramework.jasmine.JasmineFileStructureBuilder; import com.intellij.javascript.testing.JsTestRunConfigurationProducer; import com.intellij.lang.javascript.psi.JSFile; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collections; public class KarmaRunConfigurationProducer extends JsTestRunConfigurationProducer<KarmaRunConfiguration> { public KarmaRunConfigurationProducer() { super(KarmaConfigurationType.getInstance(), Collections.singletonList(KarmaUtil.NODE_PACKAGE_NAME)); } @Override protected boolean setupConfigurationFromCompatibleContext(@NotNull KarmaRunConfiguration configuration, @NotNull ConfigurationContext context, @NotNull Ref<PsiElement> sourceElement) { PsiElement element = context.getPsiLocation(); if (element == null || !isTestRunnerPackageAvailableFor(element)) { return false; } Pair<KarmaRunSettings, PsiElement> pair = setup(element, configuration.getRunSettings()); if (pair != null) { configuration.setRunSettings(pair.getFirst()); sourceElement.set(pair.getSecond()); configuration.setGeneratedName(); return true; } return false; } @Nullable private static Pair<KarmaRunSettings, PsiElement> setup(@Nullable PsiElement element, @NotNull KarmaRunSettings templateRunSettings) { JSFile file = ObjectUtils.tryCast(element != null ? element.getContainingFile() : null, JSFile.class); VirtualFile virtualFile = PsiUtilCore.getVirtualFile(file); if (virtualFile == null) { return null; } if (!(element instanceof PsiFileSystemItem)) { Pair<KarmaRunSettings, PsiElement> suiteOrTestConfiguration = setupAsSuiteOrTest(file, virtualFile, element, templateRunSettings); if (suiteOrTestConfiguration != null) { return suiteOrTestConfiguration; } } if (KarmaUtil.isKarmaConfigFile(virtualFile.getNameSequence(), false)) { return Pair.create(templateRunSettings.toBuilder() .setScopeKind(KarmaScopeKind.ALL) .setConfigPath(virtualFile.getPath()).build(), file); } return null; } @Nullable private static Pair<KarmaRunSettings, PsiElement> setupAsSuiteOrTest(@NotNull JSFile file, @NotNull VirtualFile virtualFile, @NotNull PsiElement element, @NotNull KarmaRunSettings templateSettings) { TextRange textRange = element.getTextRange(); if (textRange == null || !file.isTestFile()) { return null; } JasmineFileStructure jasmineStructure = JasmineFileStructureBuilder.getInstance().fetchCachedTestFileStructure(file); JsTestElementPath path = jasmineStructure.findTestElementPath(textRange); if (path != null) { templateSettings = guessConfigFileIfNeeded(templateSettings, virtualFile, element.getProject()); KarmaRunSettings.Builder builder = templateSettings.toBuilder(); String testName = path.getTestName(); if (testName == null) { builder.setScopeKind(KarmaScopeKind.SUITE); builder.setTestNames(path.getSuiteNames()); } else { builder.setScopeKind(KarmaScopeKind.TEST); builder.setTestNames(path.getAllNames()); } return Pair.create(builder.build(), path.getTestElement()); } return null; } @NotNull private static KarmaRunSettings guessConfigFileIfNeeded(@NotNull KarmaRunSettings settings, @NotNull VirtualFile contextFile, @NotNull Project project) { if (!settings.getConfigPath().isEmpty()) { return settings; } ProjectFileIndex fileIndex = ProjectFileIndex.getInstance(project); VirtualFile dir = contextFile.isDirectory() ? contextFile : contextFile.getParent(); if (dir == null) { return settings; } VirtualFile contentRoot = fileIndex.getContentRootForFile(dir, false); while (dir != null && contentRoot != null) { VirtualFile[] children = dir.getChildren(); for (VirtualFile child : children) { if (KarmaUtil.isKarmaConfigFile(child.getNameSequence(), true)) { return settings.toBuilder().setConfigPath(child.getPath()).build(); } } if (dir.equals(contentRoot)) { dir = dir.getParent(); contentRoot = fileIndex.getContentRootForFile(dir, false); } else { dir = dir.getParent(); } } return settings; } @Override protected boolean isConfigurationFromCompatibleContext(@NotNull KarmaRunConfiguration configuration, @NotNull ConfigurationContext context) { KarmaRunSettings confSettings = configuration.getRunSettings(); // use configuration.getRunSettings() as template settings to use equals method Pair<KarmaRunSettings, PsiElement> data = setup(context.getPsiLocation(), confSettings); return data != null && confSettings.equals(data.first); } @Override public boolean isPreferredConfiguration(ConfigurationFromContext self, ConfigurationFromContext other) { PsiFile psiFile = self.getSourceElement().getContainingFile(); if (psiFile != null && other != null) { PreferableRunConfiguration otherRc = ObjectUtils.tryCast(other.getConfiguration(), PreferableRunConfiguration.class); if (otherRc != null && otherRc.isPreferredOver(self.getConfiguration(), psiFile)) { return false; } } return true; } }