Testing Guide¶
Running Tests¶
# Run all tests
./gradlew test
# Run tests with coverage report
./gradlew test koverHtmlReport
# View coverage report
open build/reports/kover/html/index.html
Test Structure¶
Tests are located in src/test/kotlin/com/rescript/plugin/ and mirror the source code package structure:
src/test/kotlin/com/rescript/plugin/
├── highlight/
│ ├── RescriptSyntaxHighlighterTest.kt
│ └── RescriptBraceMatcherTest.kt
├── lang/
│ ├── RescriptLexerTest.kt
│ └── RescriptParserTest.kt
├── folding/
│ └── RescriptFoldingBuilderTest.kt
├── ...
Writing Tests¶
Test Conventions¶
File naming:
<TargetClass>Test.ktLocation: Same package as the class being tested
Framework: JUnit 5 with IntelliJ test fixtures
IntelliJ Test Fixtures¶
Most tests extend IntelliJ Platform test base classes:
class RescriptMyFeatureTest : BasePlatformTestCase() {
override fun getTestDataPath(): String = "src/test/testData/myfeature"
fun testBasicCase() {
// Configure test fixture with a ReScript file
myFixture.configureByText("Test.res", "let x = 1")
// Invoke the feature and assert results
}
}
Test Data Files¶
Test data files go in src/test/testData/<feature>/:
src/test/testData/
├── folding/
│ ├── module.res
│ └── comments.res
├── highlighting/
│ └── keywords.res
└── ...
Lexer Tests¶
Test that the lexer produces correct token sequences:
fun testKeywords() {
val lexer = RescriptLexer()
lexer.start("let x = 1")
assertEquals(RescriptTokenTypes.LET, lexer.tokenType)
lexer.advance()
// ... continue checking tokens
}
Parser Tests¶
Test that the parser produces correct PSI structures:
fun testLetDeclaration() {
myFixture.configureByText("Test.res", "let x = 1")
val file = myFixture.file
val declarations = PsiTreeUtil.findChildrenOfType(file, RescriptLetDeclaration::class.java)
assertEquals(1, declarations.size)
}
Integration Tests¶
Integration tests use IntelliJ Platform’s test infrastructure to verify features in a realistic IDE environment, including PSI trees, editor fixtures, and file-based test data.
Unit Tests vs Integration Tests¶
Aspect |
Unit Tests |
Integration Tests |
|---|---|---|
Base class |
None or plain JUnit |
|
Speed |
Fast (no IDE bootstrap) |
Slower (IDE platform initialized) |
Scope |
Single class / function |
Feature end-to-end in IDE context |
Use when |
Testing pure logic (lexer tokens, utility functions) |
Testing features that interact with PSI, editor, or fixtures |
BasePlatformTestCase Pattern¶
Integration tests extend BasePlatformTestCase, which bootstraps a lightweight IDE environment with an editor, PSI infrastructure, and project model:
class RescriptMyFeatureIntegrationTest : BasePlatformTestCase() {
override fun getTestDataPath(): String = "src/test/testData/myfeature"
fun testFeatureWithInlineCode() {
// Configure editor with inline ReScript code
myFixture.configureByText("Test.res", """
let x = 1
module M = {
let y = 2
}
""".trimIndent())
// Invoke the feature and assert results
// e.g., myFixture.testStructureView { ... }
}
fun testFeatureWithTestDataFile() {
// Load a test data file from getTestDataPath()
myFixture.configureByFile("Example.res")
// Assert against the loaded file
}
}
Key methods:
myFixture.configureByText(filename, content)— Create an in-memory file and open it in the editormyFixture.configureByFile(filename)— Load a file from thetestDataPathdirectorymyFixture.testStructureView { view -> ... }— Open the structure view and assert its contentsmyFixture.testHighlighting(...)— Run highlighting and check annotations
Integration Test Classes¶
The project includes the following integration test categories:
Test Class |
Feature |
Example Assertion |
|---|---|---|
|
Syntax highlighting |
Token colors match expected attributes |
|
Code folding |
Fold regions match |
|
Structure view |
Tree contains expected declarations |
|
Auto-indentation |
Indent levels after Enter key |
|
Parser + PSI tree |
PSI tree matches expected structure |
|
Lexer token stream |
Full-file token sequences match expectations |
testData Directory¶
Test data files are organized by feature under src/test/testData/:
src/test/testData/
├── folding/ # .res files with <fold> markers
├── highlighting/ # .res files for highlighting tests
├── structure/ # .res files for structure view tests
├── indent/ # .res files for indentation tests
├── parser/ # .res files for parser tests
└── lexer/ # .res files for lexer tests
Each test class points to its data directory via getTestDataPath(). Test data files are plain .res files, sometimes with special markers (e.g., <fold text="...">) for framework-assisted assertions.
Test Coverage¶
The project uses Kover for code coverage.
# Generate HTML report
./gradlew koverHtmlReport
# Generate XML report (used by CI)
./gradlew koverXmlReport
Coverage reports are generated at build/reports/kover/html/.
Coverage Requirements¶
New code should have test coverage
CI reports coverage on pull requests
Exceptions: UI components (Swing), LSP integration classes that require a running server
UI Tests (Remote-Robot)¶
The project includes UI tests powered by IntelliJ Remote-Robot for end-to-end IDE testing and automated Marketplace screenshot capture.
Prerequisites¶
macOS: Grant accessibility permissions to Java (System Settings > Privacy & Security > Accessibility)
The sample project at
src/uiTest/testData/sample-project/must have its npm dependencies installed:
cd src/uiTest/testData/sample-project
npm install
Running UI Tests¶
UI tests require a two-step process — the IDE must be running before tests can connect:
# Terminal 1: Start the IDE with Remote-Robot server (port 8082)
./gradlew runIdeForUiTests
# Terminal 2: Open the sample project in the IDE, then run the tests
./gradlew uiTest
Screenshot Output¶
The MarketplaceScreenshotTest class captures 11 screenshots demonstrating key plugin features. Screenshots are saved to build/screenshots/:
Screenshot |
Feature |
|---|---|
|
ReScript code colorization |
|
LSP completion popup |
|
Inline error/warning display |
|
Type inference hints |
|
File symbol tree |
|
Function type annotations |
|
JSX syntax highlighting |
|
.resi nesting and compiled JS |
|
Alt+Enter intention menu |
|
Type info and documentation |
|
Interactive REPL tool window |
Test Structure¶
UI tests are in a separate source set (src/uiTest/) and do not run with ./gradlew test:
src/uiTest/kotlin/com/rescript/plugin/uitest/
├── UiTestBase.kt # Base class (connection, screenshots)
├── fixtures/
│ └── IdeFixtures.kt # IDE component fixtures
└── screenshot/
└── MarketplaceScreenshotTest.kt # Marketplace screenshot capture
Notes¶
UI tests are not included in CI (requires a display)
The
uiTestsource set is excluded from Kover coverageScreenshots use Darcula theme for Marketplace appeal
CI Testing¶
The CI pipeline runs tests automatically on every push and PR:
./gradlew test koverXmlReport koverHtmlReportCoverage is reported on PRs via the Kover report action
Test results are uploaded as artifacts