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:
parent
4158bf1663
commit
a58ca80fc9
66
.github/workflows/runUiTests.yml
vendored
Normal file
66
.github/workflows/runUiTests.yml
vendored
Normal 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
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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")
|
||||
|
@ -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()") }
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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() ?: "")
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user