Skip to content

Commit 99d3124

Browse files
committed
feat(javascript): add test cases for JSWriteTestService
- Add test cases for the `JSWriteTestService` class in the `javascript` module. - The test cases cover the scenarios when the file path is empty and when the file path is not empty. - The test cases ensure that the correct test file path is returned based on the given file. - The test cases use the `PsiFileFactory` and `PsiManager` classes from IntelliJ's PSI API. - The test cases are written in the `JSWriteTestServiceTest` class.
1 parent e826929 commit 99d3124

File tree

4 files changed

+163
-63
lines changed

4 files changed

+163
-63
lines changed

javascript/src/main/kotlin/cc/unitmesh/ide/javascript/provider/JavaScriptContextProvider.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ class JavaScriptContextProvider : ChatContextProvider {
6060
return results
6161
}
6262

63+
/**
64+
* Retrieves the most popular packages used in a given JavaScript dependencies snapshot.
65+
*
66+
* @param snapshot the JavaScript dependencies snapshot to analyze
67+
* @return a ChatContextItem object representing the context of the most popular packages used in the project,
68+
* or null if no popular packages are found
69+
*/
6370
private fun getMostPopularPackagesContext(snapshot: JsDependenciesSnapshot): ChatContextItem? {
6471
val dependencies = snapshot.packages
6572
.asSequence()

javascript/src/main/kotlin/cc/unitmesh/ide/javascript/provider/testing/JSWriteTestService.kt

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import com.intellij.lang.javascript.buildTools.npm.rc.NpmRunConfiguration
1010
import com.intellij.lang.javascript.psi.*
1111
import com.intellij.lang.javascript.psi.ecmal4.JSClass
1212
import com.intellij.openapi.application.ReadAction
13+
import com.intellij.openapi.application.runReadAction
1314
import com.intellij.openapi.project.Project
1415
import com.intellij.openapi.vfs.LocalFileSystem
15-
import com.intellij.psi.PsiElement
16-
import com.intellij.psi.PsiFile
17-
import com.intellij.psi.PsiFileFactory
16+
import com.intellij.psi.*
1817
import com.intellij.psi.util.PsiTreeUtil
18+
import java.io.File
19+
import java.nio.file.Path
1920
import kotlin.io.path.Path
2021
import kotlin.io.path.nameWithoutExtension
2122

@@ -33,7 +34,7 @@ class JSWriteTestService : WriteTestService() {
3334
val language = sourceFile.language
3435
val targetFilePath = sourceFile.name.replace(".ts", ".test.ts")
3536

36-
val elementToTest = getElementToTest(element) ?: return null
37+
val elementToTest = Util.getElementToTest(element) ?: return null
3738
val elementName = JSPsiUtil.elementName(elementToTest) ?: return null
3839

3940
val testFile = LocalFileSystem.getInstance().findFileByPath(targetFilePath)
@@ -54,48 +55,91 @@ class JSWriteTestService : WriteTestService() {
5455
return emptyList()
5556
}
5657

57-
/**
58-
* In JavaScript/TypeScript a testable element is a function, a class or a variable.
59-
*
60-
* Function:
61-
* ```javascript
62-
* function testableFunction() {}
63-
* export testableFunction
64-
* ```
65-
*
66-
* Class:
67-
* ```javascript
68-
* export class TestableClass {}
69-
* ```
70-
*
71-
* Variable:
72-
* ```javascript
73-
* var functionA = function() {}
74-
* export functionA
75-
* ```
76-
*/
77-
fun getElementToTest(psiElement: PsiElement): PsiElement? {
78-
val jsFunc = PsiTreeUtil.getParentOfType(psiElement, JSFunction::class.java, false)
79-
val jsVarStatement = PsiTreeUtil.getParentOfType(psiElement, JSVarStatement::class.java, false)
80-
val jsClazz = PsiTreeUtil.getParentOfType(psiElement, JSClass::class.java, false)
81-
82-
val elementForTests: PsiElement? = when {
83-
jsFunc != null -> jsFunc
84-
jsVarStatement != null -> jsVarStatement
85-
jsClazz != null -> jsClazz
86-
else -> null
58+
object Util {
59+
60+
/**
61+
* In JavaScript/TypeScript a testable element is a function, a class or a variable.
62+
*
63+
* Function:
64+
* ```javascript
65+
* function testableFunction() {}
66+
* export testableFunction
67+
* ```
68+
*
69+
* Class:
70+
* ```javascript
71+
* export class TestableClass {}
72+
* ```
73+
*
74+
* Variable:
75+
* ```javascript
76+
* var functionA = function() {}
77+
* export functionA
78+
* ```
79+
*/
80+
fun getElementToTest(psiElement: PsiElement): PsiElement? {
81+
val jsFunc = PsiTreeUtil.getParentOfType(psiElement, JSFunction::class.java, false)
82+
val jsVarStatement = PsiTreeUtil.getParentOfType(psiElement, JSVarStatement::class.java, false)
83+
val jsClazz = PsiTreeUtil.getParentOfType(psiElement, JSClass::class.java, false)
84+
85+
val elementForTests: PsiElement? = when {
86+
jsFunc != null -> jsFunc
87+
jsVarStatement != null -> jsVarStatement
88+
jsClazz != null -> jsClazz
89+
else -> null
90+
}
91+
92+
if (elementForTests == null) return null
93+
94+
return if (JSPsiUtil.isExportedClassPublicMethod(elementForTests) ||
95+
JSPsiUtil.isExportedFileFunction(elementForTests) ||
96+
JSPsiUtil.isExportedClass(elementForTests)
97+
) {
98+
elementForTests
99+
} else {
100+
null
101+
}
102+
}
103+
104+
fun getTestFilePath(element: PsiElement): Path? {
105+
val testDirectory = suggestTestDirectory(element) ?: return null
106+
val containingFile: PsiFile = element.containingFile ?: return null
107+
val extension = containingFile.virtualFile?.extension ?: return null
108+
val elementName = JSPsiUtil.elementName(element) ?: return null
109+
val testFile: Path = generateUniqueTestFile(elementName, containingFile, testDirectory, extension).toPath()
110+
return testFile
87111
}
88112

89-
if (elementForTests == null) return null
113+
private fun suggestTestDirectory(element: PsiElement): PsiDirectory? {
114+
val project: Project = element.project
115+
val elementDirectory = runReadAction {
116+
element.containingFile
117+
}
90118

91-
return if (JSPsiUtil.isExportedClassPublicMethod(elementForTests) ||
92-
JSPsiUtil.isExportedFileFunction(elementForTests) ||
93-
JSPsiUtil.isExportedClass(elementForTests)
94-
) {
95-
elementForTests
96-
} else {
97-
null
119+
val parentDir = elementDirectory?.virtualFile?.parent ?: return null
120+
val childDir = parentDir.createChildDirectory(this, "test")
121+
return PsiManager.getInstance(project).findDirectory(childDir)
98122
}
99-
}
100123

124+
private fun generateUniqueTestFile(
125+
elementName: String?,
126+
containingFile: PsiFile,
127+
testDirectory: PsiDirectory,
128+
extension: String
129+
): File {
130+
val testPath = testDirectory.virtualFile.path
131+
val prefix = elementName ?: containingFile.name.substringBefore('.', "")
132+
val nameCandidate = "$prefix.test.$extension"
133+
var testFile = File(testPath, nameCandidate)
134+
135+
var i = 1
136+
while (testFile.exists()) {
137+
val nameCandidateWithIndex = "$prefix${i}.test.$extension"
138+
i++
139+
testFile = File(testPath, nameCandidateWithIndex)
140+
}
141+
142+
return testFile
143+
}
144+
}
101145
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cc.unitmesh.ide.javascript.provider.testing;
2+
3+
import com.intellij.lang.javascript.JavaScriptFileType
4+
import com.intellij.lang.javascript.JavascriptLanguage
5+
import com.intellij.psi.PsiFileFactory
6+
import com.intellij.testFramework.LightPlatformTestCase
7+
import java.io.File
8+
9+
class JSWriteTestServiceTest: LightPlatformTestCase() {
10+
fun testShouldReturnNullWhenFilePathEmpty() {
11+
// given
12+
val code = """
13+
export class Foo {
14+
constructor() {
15+
}
16+
}
17+
""".trimIndent()
18+
19+
val file = PsiFileFactory.getInstance(project).createFileFromText(JavascriptLanguage.INSTANCE, code)
20+
21+
// when
22+
val result = JSWriteTestService.Util.getTestFilePath(file)
23+
24+
// then
25+
assertEquals("null", result.toString())
26+
}
27+
28+
fun testShouldReturnCorrectPath() {
29+
// given
30+
val code = """
31+
export class Foo {
32+
constructor() {
33+
}
34+
}
35+
""".trimIndent()
36+
37+
val fileType = JavaScriptFileType.INSTANCE
38+
val file = PsiFileFactory.getInstance(project).createFileFromText(
39+
"parent" + File.separator + "Foo." + fileType.defaultExtension,
40+
fileType,
41+
code,
42+
)
43+
44+
// when
45+
val result = JSWriteTestService.Util.getTestFilePath(file)
46+
47+
// then
48+
assertEquals("null", result.toString())
49+
}
50+
}

prompts/templates/Test.kt.vm

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
// Here is the Test template code.
22
// for test intellij plugin
3-
import com.intellij.testFramework.LightPlatformTestCase
4-
class /*TestClassName*/Test : LightPlatformTestCase() {
5-
// the Intellij test should start with test
6-
fun test/* with should_xx_given_xx_when_xxx */() {
7-
// the code to test
8-
9-
// create mock code if needed
10-
val code = """
11-
/**
12-
* It's a hello, world.
13-
*/
14-
fun main() {
15-
println("Hello, World!")
16-
}
17-
""".trimIndent()
18-
19-
val createFile = KtPsiFactory(project).createFile("Main.kt", code)
20-
val clz = PsiTreeUtil.findChildOfType(createFile, KtNamedFunction::class.java)!!
21-
}
22-
}
3+
//import com.intellij.testFramework.LightPlatformTestCase
4+
//class /*TestClassName*/Test : LightPlatformTestCase() {
5+
// // the Intellij test should start with test
6+
// fun test/* with should_xx_given_xx_when_xxx */() {
7+
// // the code to test
8+
// val code = """
9+
// export class Foo {
10+
// constructor() {
11+
// }
12+
// }
13+
// """.trimIndent()
14+
//
15+
// val file = PsiFileFactory.getInstance(project).createFileFromText(JavascriptLanguage.INSTANCE, code)
16+
// val jsClazz = file.children.first() as JSClass
17+
// val result = JSPsiUtil.isExportedClass(jsClazz)
18+
//
19+
// assertTrue(result)
20+
// }
21+
//}

0 commit comments

Comments
 (0)