1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-06-02 13:34:07 +02:00

fixed Ide Fatal Errors

added UI tests reporting
This commit is contained in:
eugene.nizienko 2021-07-23 01:32:52 +02:00 committed by Alex Pláte
parent 4158bf1663
commit a58ca80fc9
10 changed files with 189 additions and 45 deletions

66
.github/workflows/runUiTests.yml vendored Normal file
View File

@ -0,0 +1,66 @@
name: Run UI Tests
on:
workflow_dispatch
jobs:
build-for-ui-test-mac-os:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v2.1.0
with:
distribution: zulu
java-version: 11
- name: Build Plugin
run: gradle :buildPlugin
- name: Run Idea
run: |
mkdir -p build/reports
gradle :runIdeForUiTests > build/reports/idea.log &
- name: Wait for Idea started
uses: jtalk/url-health-check-action@1.5
with:
url: http://127.0.0.1:8082
max-attempts: 20
retry-delay: 10s
- name: Tests
run: gradle :testUi
- name: Save fails report
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: ui-test-fails-report-mac
path: |
build/reports
# build-for-ui-test-linux:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Setup Java
# uses: actions/setup-java@v2.1.0
# with:
# distribution: zulu
# java-version: 11
# - name: Build Plugin
# run: gradle :buildPlugin
# - name: Run Idea
# run: |
# export DISPLAY=:99.0
# Xvfb -ac :99 -screen 0 1920x1080x16 &
# mkdir -p build/reports
# gradle :runIdeForUiTests #> build/reports/idea.log
# - name: Wait for Idea started
# uses: jtalk/url-health-check-action@1.5
# with:
# url: http://127.0.0.1:8082
# max-attempts: 15
# retry-delay: 30s
# - name: Tests
# run: gradle :testUi
# - name: Save fails report
# if: ${{ failure() }}
# uses: actions/upload-artifact@v2
# with:
# name: ui-test-fails-report-linux
# path: |
# ui-test-example/build/reports

View File

@ -360,6 +360,10 @@ Contributors:
[![icon][github]](https://github.com/MichalPlacek)
 
Michal Placek
* [![icon][mail]](mailto:eugene.nizienko@jetbrains.com)
[![icon][github]](https://github.com/nizienko)
 
eugene nizienko
If you are a contributor and your name is not listed here, feel free to
contact the maintainers.

View File

@ -36,6 +36,7 @@ val kotlinVersion: String by project
val ideaVersion: String by project
val downloadIdeaSources: String by project
val instrumentPluginCode: String by project
val remoteRobotVersion: String by project
val publishChannels: String by project
val publishToken: String by project
@ -55,8 +56,8 @@ dependencies {
testImplementation("com.ensarsarajcic.neovim.java:neovim-api:0.2.3")
testImplementation("com.ensarsarajcic.neovim.java:core-rpc:0.2.3")
testImplementation("com.intellij.remoterobot:remote-robot:0.11.6")
testImplementation("com.intellij.remoterobot:remote-fixtures:1.1.18")
testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
}
// --- Compilation
@ -116,7 +117,7 @@ intellij {
tasks {
downloadRobotServerPlugin {
version.set("0.10.0")
version.set(remoteRobotVersion)
}
publishPlugin {

View File

@ -5,6 +5,7 @@ downloadIdeaSources=true
instrumentPluginCode=true
version=SNAPSHOT
javaVersion=1.8
remoteRobotVersion=0.11.6
# Please don't forget to update kotlin version in buildscript section
kotlinVersion=1.5.0

View File

@ -23,7 +23,6 @@ import com.intellij.remoterobot.fixtures.ContainerFixture
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.stepsProcessing.step
import com.intellij.remoterobot.utils.keyboard
import com.intellij.remoterobot.utils.waitFor
import org.assertj.swing.core.MouseButton
import org.junit.Test
import ui.pages.Editor
@ -53,7 +52,7 @@ class UiTests {
}
@Test
fun ideaVimTest() = uiTest {
fun ideaVimTest() = uiTest("ideaVimTest") {
val sharedSteps = JavaExampleSteps(this)
welcomeFrame {
@ -69,12 +68,14 @@ class UiTests {
button("Finish").click()
}
}
sharedSteps.closeTipOfTheDay()
with(sharedSteps) {
closeIdeaVimDialog()
closeTipOfTheDay()
}
idea {
step("Create App file") {
with(projectViewTree) {
findText(projectName).doubleClick()
waitFor { hasText("src") }
expand(projectName, "src")
findText("src").click(MouseButton.RIGHT_BUTTON)
}
actionMenu("New").click()

View File

@ -54,8 +54,19 @@ class Editor(
val caretOffset: Int
get() = callJs("component.getEditor().getCaretModel().getOffset()", runInEdt = true)
val isBlockCursor: Boolean
get() = callJs("component.getEditor().getSettings().isBlockCursor()", true)
fun injectText(text: String) {
runJs("component.getEditor().getDocument().setText('${text.escape()}')", runInEdt = true)
runJs("""
const app = com.intellij.openapi.application.ApplicationManager.getApplication()
app.invokeLaterOnWriteThread(()=>{
app['runWriteAction(com.intellij.openapi.util.Computable)'](()=>{
component.getEditor().getDocument().setText('${text.escape()}')
})
})
""")
}
@Suppress("unused")

View File

@ -24,6 +24,7 @@ import com.intellij.remoterobot.fixtures.CommonContainerFixture
import com.intellij.remoterobot.fixtures.ContainerFixture
import com.intellij.remoterobot.fixtures.DefaultXpath
import com.intellij.remoterobot.fixtures.FixtureName
import com.intellij.remoterobot.fixtures.JTreeFixture
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.stepsProcessing.step
import com.intellij.remoterobot.utils.waitFor
@ -41,7 +42,7 @@ class IdeaFrame(
) : CommonContainerFixture(remoteRobot, remoteComponent) {
val projectViewTree
get() = find<ContainerFixture>(byXpath("ProjectViewTree", "//div[@class='ProjectViewTree']"))
get() = find<JTreeFixture>(byXpath("ProjectViewTree", "//div[@class='ProjectViewTree']"), Duration.ofSeconds(10))
val projectName
get() = step("Get project name") { return@step callJs<String>("component.getProject().getName()") }

View File

@ -18,28 +18,48 @@
package ui.utils
import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.fixtures.JButtonFixture
import com.intellij.remoterobot.search.locators.byXpath
import com.intellij.remoterobot.stepsProcessing.step
import com.intellij.remoterobot.utils.Keyboard
import ui.pages.DialogFixture
import ui.pages.DialogFixture.Companion.byTitle
import ui.pages.IdeaFrame
import ui.pages.dialog
import ui.pages.idea
class JavaExampleSteps(private val remoteRobot: RemoteRobot) {
@Suppress("unused")
private val keyboard: Keyboard = Keyboard(remoteRobot)
fun closeTipOfTheDay() {
step(
"Close Tip of the Day if it appears",
Runnable {
fun closeIdeaVimDialog() = optionalStep("Close Idea Vim dialog if it appears") {
remoteRobot.idea {
dialog("IdeaVim") { button("Yes").click() }
}
}
fun closeTipOfTheDay() = optionalStep("Close Tip of the Day if it appears") {
val idea: IdeaFrame = remoteRobot.find(IdeaFrame::class.java)
idea.dumbAware {
try {
idea.find(DialogFixture::class.java, byTitle("Tip of the Day")).button("Close").click()
}
closeAllGotIt()
}
fun closeAllGotIt() = step("Close Got It") {
remoteRobot.findAll<JButtonFixture>(byXpath("//div[@accessiblename='Got It']")).forEach {
it.click()
}
}
private fun optionalStep(stepName: String, code: () -> Unit) = step(stepName) {
try {
code()
} catch (ignore: Throwable) {
println("$stepName ignored")
}
}
}
)
}
}

View File

@ -19,7 +19,54 @@
package ui.utils
import com.intellij.remoterobot.RemoteRobot
import okhttp3.OkHttpClient
import okhttp3.Request
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.io.File
import javax.imageio.ImageIO
fun uiTest(url: String = "http://127.0.0.1:8082", test: RemoteRobot.() -> Unit) {
RemoteRobot(url).apply(test)
fun uiTest(testName: String = "test_${System.currentTimeMillis()}", url: String = "http://127.0.0.1:8082", test: RemoteRobot.() -> Unit) {
val remoteRobot = RemoteRobot(url)
try {
remoteRobot.test()
} catch (e: Throwable) {
saveScreenshot(testName, remoteRobot)
saveHierarchy(testName, url)
throw e
}
}
private val client by lazy { OkHttpClient() }
private fun BufferedImage.save(name: String) {
val bytes = ByteArrayOutputStream().use { b ->
ImageIO.write(this, "png", b)
b.toByteArray()
}
File("build/reports").apply { mkdirs() }.resolve("$name.png").writeBytes(bytes)
}
fun saveScreenshot(testName: String, remoteRobot: RemoteRobot) {
fetchScreenShot(remoteRobot).save(testName)
}
private fun fetchScreenShot(remoteRobot: RemoteRobot): BufferedImage {
return remoteRobot.getScreenshot()
}
private fun saveHierarchy(testName: String, url: String) {
val hierarchySnapshot =
saveFile(url, "build/reports", "hierarchy-$testName.html")
if (File("build/reports/styles.css").exists().not()) {
saveFile("$url/styles.css", "build/reports", "styles.css")
}
println("Hierarchy snapshot: ${hierarchySnapshot.absolutePath}")
}
private fun saveFile(url: String, folder: String, name: String): File {
val response = client.newCall(Request.Builder().url(url).build()).execute()
return File(folder).apply {
mkdirs()
}.resolve(name).apply {
writeText(response.body?.string() ?: "")
}
}

View File

@ -22,6 +22,7 @@ import com.intellij.remoterobot.fixtures.Fixture
import com.intellij.remoterobot.fixtures.dataExtractor.RemoteText
import com.intellij.remoterobot.utils.waitFor
import org.assertj.swing.core.MouseButton
import ui.pages.Editor
import java.awt.Point
fun RemoteText.doubleClickOnRight(shiftX: Int, fixture: Fixture, button: MouseButton = MouseButton.LEFT_BUTTON) {
@ -38,22 +39,13 @@ fun RemoteText.tripleClickOnRight(shiftX: Int, fixture: Fixture, button: MouseBu
}
}
fun RemoteText.moveMouseTo(goal: RemoteText, fixture: Fixture): Boolean {
fun RemoteText.moveMouseTo(goal: RemoteText, editor: Editor): Boolean {
this.moveMouse()
val goalPoint = goal.point
val caretDuringDragging = fixture.callJs<Boolean>(
"""
const point = new java.awt.Point(${goalPoint.x}, ${goalPoint.y});
let isBlock = true;
robot.pressMouseWhileRunning(MouseButton.LEFT_BUTTON, () => {
robot.moveMouse(component, point)
isBlock = component.getEditor().getSettings().isBlockCursor();
})
isBlock
"""
)
waitFor { fixture.callJs("component.getEditor().getSettings().isBlockCursor()") }
editor.runJs("robot.pressMouse(MouseButton.LEFT_BUTTON)")
goal.moveMouse()
val caretDuringDragging = editor.isBlockCursor
editor.runJs("robot.releaseMouse(MouseButton.LEFT_BUTTON)")
waitFor { editor.isBlockCursor }
return caretDuringDragging
}
@ -71,22 +63,22 @@ fun RemoteText.moveMouseInGutterTo(goal: RemoteText, fixture: Fixture) {
)
}
fun RemoteText.moveMouseForthAndBack(middle: RemoteText, fixture: Fixture) {
fun RemoteText.moveMouseForthAndBack(middle: RemoteText, editor: Editor) {
this.moveMouse()
val initialPoint = this.point
val middlePoint = middle.point
fixture.runJs(
editor.runJs(
"""
const initialPoint = new java.awt.Point(${initialPoint.x}, ${initialPoint.y});
const point = new java.awt.Point(${middlePoint.x}, ${middlePoint.y});
const initialPoint = new Point(${initialPoint.x}, ${initialPoint.y});
const point = new Point(${middlePoint.x}, ${middlePoint.y});
robot.pressMouseWhileRunning(MouseButton.LEFT_BUTTON, () => {
robot.moveMouse(component, point)
robot.moveMouse(component, initialPoint)
})
"""
)
waitFor { fixture.callJs("component.getEditor().getSettings().isBlockCursor()") }
waitFor { editor.isBlockCursor }
}
fun String.escape(): String = this.replace("\n", "\\n")