@@ -2,6 +2,7 @@ package org.utbot.intellij.plugin.language.js
2
2
3
3
import api.JsTestGenerator
4
4
import com.intellij.codeInsight.CodeInsightUtil
5
+ import com.intellij.javascript.nodejs.interpreter.local.NodeJsLocalInterpreterManager
5
6
import com.intellij.lang.ecmascript6.psi.ES6Class
6
7
import com.intellij.lang.javascript.psi.JSFile
7
8
import com.intellij.lang.javascript.refactoring.util.JSMemberInfo
@@ -12,10 +13,13 @@ import com.intellij.openapi.module.Module
12
13
import com.intellij.openapi.progress.ProgressIndicator
13
14
import com.intellij.openapi.progress.Task
14
15
import com.intellij.openapi.project.Project
16
+ import com.intellij.openapi.ui.Messages
15
17
import com.intellij.psi.PsiDocumentManager
16
18
import com.intellij.psi.PsiFileFactory
17
19
import com.intellij.psi.impl.file.PsiDirectoryFactory
18
20
import com.intellij.util.concurrency.AppExecutorUtil
21
+ import framework.codegen.Mocha
22
+ import mu.KotlinLogging
19
23
import org.jetbrains.kotlin.idea.util.application.invokeLater
20
24
import org.jetbrains.kotlin.idea.util.application.runReadAction
21
25
import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -26,6 +30,9 @@ import settings.JsDynamicSettings
26
30
import settings.JsExportsSettings.endComment
27
31
import settings.JsExportsSettings.startComment
28
32
import settings.JsTestGenerationSettings.dummyClassName
33
+ import utils.JsCmdExec
34
+
35
+ private val logger = KotlinLogging .logger {}
29
36
30
37
object JsDialogProcessor {
31
38
@@ -38,28 +45,37 @@ object JsDialogProcessor {
38
45
editor : Editor ,
39
46
file : JSFile
40
47
) {
41
- createDialog(project, srcModule, fileMethods, focusedMethod, containingFilePath, file)?.let { dialogProcessor ->
42
- if (! dialogProcessor.showAndGet()) return
43
- /*
44
- Since Tern.js accesses containing file, sync with file system required before test generation.
45
- */
46
- runWriteAction {
47
- with (FileDocumentManager .getInstance()) {
48
- saveDocument(editor.document)
48
+ val model = createJsTestModel(project, srcModule, fileMethods, focusedMethod, containingFilePath, file)
49
+ (object : Task .Backgroundable (
50
+ project,
51
+ " Check the requirements"
52
+ ) {
53
+ override fun run (indicator : ProgressIndicator ) {
54
+ invokeLater {
55
+ getFrameworkLibraryPath(Mocha .displayName.lowercase(), model)
56
+ createDialog(model)?.let { dialogProcessor ->
57
+ if (! dialogProcessor.showAndGet()) return @invokeLater
58
+ // Since Tern.js accesses containing file, sync with file system required before test generation.
59
+ runWriteAction {
60
+ with (FileDocumentManager .getInstance()) {
61
+ saveDocument(editor.document)
62
+ }
63
+ }
64
+ createTests(dialogProcessor.model, containingFilePath, editor)
65
+ }
49
66
}
50
67
}
51
- createTests(dialogProcessor.model, containingFilePath, editor)
52
- }
68
+ }).queue()
53
69
}
54
70
55
- private fun createDialog (
71
+ private fun createJsTestModel (
56
72
project : Project ,
57
73
srcModule : Module ,
58
74
fileMethods : Set <JSMemberInfo >,
59
75
focusedMethod : JSMemberInfo ? ,
60
76
filePath : String ,
61
77
file : JSFile
62
- ): JsDialogWindow ? {
78
+ ): JsTestsModel ? {
63
79
val testModules = srcModule.testModules(project)
64
80
65
81
if (testModules.isEmpty()) {
@@ -70,19 +86,42 @@ object JsDialogProcessor {
70
86
showErrorDialogLater(project, errorMessage, " Test source roots not found" )
71
87
return null
72
88
}
89
+ return JsTestsModel (
90
+ project = project,
91
+ srcModule = srcModule,
92
+ potentialTestModules = testModules,
93
+ fileMethods = fileMethods,
94
+ selectedMethods = if (focusedMethod != null ) setOf (focusedMethod) else emptySet(),
95
+ file = file
96
+ ).apply {
97
+ containingFilePath = filePath
98
+ }
73
99
74
- return JsDialogWindow (
75
- JsTestsModel (
76
- project = project,
77
- srcModule = srcModule,
78
- potentialTestModules = testModules,
79
- fileMethods = fileMethods,
80
- selectedMethods = if (focusedMethod != null ) setOf (focusedMethod) else emptySet(),
81
- file = file
82
- ).apply {
83
- containingFilePath = filePath
84
- }
85
- )
100
+ }
101
+
102
+ private fun createDialog (
103
+ jsTestsModel : JsTestsModel ?
104
+ ): JsDialogWindow ? {
105
+ try {
106
+ jsTestsModel?.pathToNode = NodeJsLocalInterpreterManager .getInstance()
107
+ .interpreters.first().interpreterSystemIndependentPath
108
+ val (_, error) = JsCmdExec .runCommand(
109
+ shouldWait = true ,
110
+ cmd = arrayOf(" node" , " -v" )
111
+ )
112
+ if (error.readText().isNotEmpty()) throw NoSuchElementException ()
113
+ } catch (e: NoSuchElementException ) {
114
+ Messages .showErrorDialog(
115
+ " Node.js interpreter is not found in IDEA settings.\n " +
116
+ " Please set it in Settings > Languages & Frameworks > Node.js" ,
117
+ " Requirement Error"
118
+ )
119
+ logger.error { " Node.js interpreter was not found in IDEA settings." }
120
+ return null
121
+ }
122
+ return jsTestsModel?.let {
123
+ JsDialogWindow (it)
124
+ }
86
125
}
87
126
88
127
private fun unblockDocument (project : Project , document : Document ) {
@@ -207,3 +246,34 @@ object JsDialogProcessor {
207
246
}
208
247
}
209
248
}
249
+
250
+ // TODO(MINOR): Add indicator.text for each installation
251
+ fun installMissingRequirement (project : Project , pathToNPM : String , requirement : String ) {
252
+ val message = """
253
+ Requirement is not installed:
254
+ $requirement
255
+ Install it?
256
+ """ .trimIndent()
257
+ val result = Messages .showOkCancelDialog(
258
+ project,
259
+ message,
260
+ " Requirement Missmatch Error" ,
261
+ " Install" ,
262
+ " Cancel" ,
263
+ null
264
+ )
265
+
266
+ if (result == Messages .CANCEL )
267
+ return
268
+
269
+ val (_, errorStream) = installRequirement(pathToNPM, requirement, project.basePath)
270
+
271
+ val errorText = errorStream.readText()
272
+ if (errorText.isNotEmpty()) {
273
+ showErrorDialogLater(
274
+ project,
275
+ " Requirements installing failed with some reason:\n ${errorText} " ,
276
+ " Requirements error"
277
+ )
278
+ }
279
+ }
0 commit comments