Skip to content

Commit

Permalink
Merge pull request #158 from TarCV/optional-java
Browse files Browse the repository at this point in the history
Make Java plugin an optional dependency
  • Loading branch information
TarCV authored Jan 2, 2024
2 parents 05953e1 + f90b2c4 commit b3eb0c1
Show file tree
Hide file tree
Showing 24 changed files with 453 additions and 204 deletions.
60 changes: 29 additions & 31 deletions .github/workflows/run-ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,18 @@ jobs:
fail-fast: false
matrix:
os: [ macos-latest, ubuntu-latest, windows-latest ]
ideDate: [ IC-2022.2, IC-2022.3, IC-2023.1, IC-2023.2 ]
include:
# - ideDate: IC-EAP # TODO: Run this variant weekly
# ide: IC
# version: LATEST_EAP
- ideDate: IC-2023.2
ide: IC
version: 2023.2.3 # released on 11.10.2023, major from 26.07.2023
- ideDate: IC-2023.1
ide: IC
version: 2023.1.5 # released on 25.07.2023, major from 28.03.2023
- ideDate: IC-2022.3
ide: IC
version: 2022.3.3 # released on 8.03.2023, major from 30.11.2022
- ideDate: IC-2022.2
ide: IC
version: 2022.2.5 # released on 15.03.2023, major from 26.07.2022

ideDate: # Up to 2 versions per year, initial major ver release date should be not older than a year
# - IC-LATEST_EAP # TODO: Run this variant weekly
- IC-2023.3.2 # released on 20.12.2023, major from 06.12.2023
- IC-2023.1.5 # released on 25.07.2023, major from 28.03.2023
- IC-2022.3.3 # released on 8.03.2023, major from 30.11.2022
# - PC-LATEST_EAP # TODO: Run this variant weekly
- PC-2023.3.2 # released on 20.12.2023, major from 06.12.2023
- PC-2023.1.4 # released on 13.07.2023, major from 30.03.2023
- PC-2022.3.3 # released on 10.03.2023, major from 01.12.2022
# Versions should match https://jb.gg/android-studio-releases-list.xml
# TODO:
# - ideDate: AI-2023
# ide: AI
# version: 2023.1.1 # released on 27.09.2023
# - ideDate: AI-2022
# ide: AI
# version: 2022.3.1 # released on 28.09.2023
# - ideDate: AI-2021
# ide: AI
# version: 2021.3.1.17 # released on 13.10.2022

include:
- os: ubuntu-latest
runTests: |
export DISPLAY=:99.0
Expand All @@ -89,11 +71,18 @@ jobs:
reportName: ui-tests-windows

env:
IDE_CODE: ${{ matrix.ide }}
IDE_VERSION: ${{ matrix.version }}
PLUGIN_PATH: "${{ github.workspace }}/${{ needs.getPlugin.outputs.path }}"
steps:

- uses: actions/github-script@v7
id: prepare-IDE_CODE
with:
script: return "${{ matrix.ideDate }}".split("-", 2)[0]
result-encoding: string
- uses: actions/github-script@v7
id: prepare-IDE_VERSION
with:
script: return "${{ matrix.ideDate }}".split("-", 2)[1]
result-encoding: string
- name: Setup FFmpeg
uses: FedericoCarboni/setup-ffmpeg@v2
with:
Expand All @@ -104,13 +93,19 @@ jobs:
# Setup Java environment for the next steps
- name: Setup Java
uses: actions/setup-java@v3
env:
IDE_CODE: ${{ steps.prepare-IDE_CODE.outputs.result }}
IDE_VERSION: ${{ steps.prepare-IDE_VERSION.outputs.result }}
with:
distribution: zulu
java-version: 11

# Setup Gradle
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
env:
IDE_CODE: ${{ steps.prepare-IDE_CODE.outputs.result }}
IDE_VERSION: ${{ steps.prepare-IDE_VERSION.outputs.result }}
with:
gradle-home-cache-cleanup: true

Expand All @@ -128,6 +123,9 @@ jobs:

# Run tests
- name: Tests
env:
IDE_CODE: ${{ steps.prepare-IDE_CODE.outputs.result }}
IDE_VERSION: ${{ steps.prepare-IDE_VERSION.outputs.result }}
run: ${{ matrix.runTests }}

# Collect Tests Result of failed tests
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ UI Surveyor plugin provides tools helping with mobile application automation.
They provide the following features:
* **_Evaluating_ element selectors against an XML UI snapshots** <br />
![Search](docs/Search.png)
* **Syntax highlighting and autocomplete for element selectors** <br />
* **Syntax highlighting and autocomplete for element selectors (Java IDEs only)** <br />
![Autocomplete & Highlighting](docs/Autocomplete.png)
* **Improved structure navigation for XML UI snapshots** <br />
![Structure navigation](docs/StructureNavigation.png)
Expand All @@ -24,7 +24,7 @@ UI Surveyor plugin provides tools helping work with Android UI Snapshot in XML f

Those tools are:
* `Locate Element` tool window for **evaluating** element selectors against a currently open XML UI snapshots
* Basic syntax highlighting and autocomplete for UIAutomator selectors (as Java code)
* Basic syntax highlighting and autocomplete for UIAutomator selectors (as Java code, supported only for Java IDEs)
* Improved structure navigation for UI snapshots

All trademarks are the property of their respective owners. All company, product and service names
Expand Down
3 changes: 1 addition & 2 deletions ci/poms/droid-selector/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
Expand Down
3 changes: 1 addition & 2 deletions ci/poms/droid-stubs/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
Expand Down
3 changes: 1 addition & 2 deletions ci/poms/library/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
Expand Down
3 changes: 1 addition & 2 deletions ci/poms/plugin-test/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
Expand Down
3 changes: 1 addition & 2 deletions ci/poms/plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ package com.github.tarcv.testingteam.surveyoridea
import com.intellij.remoterobot.utils.waitFor
import java.time.Duration

fun <T> waitingAssertion(errorMessage: String, expectedValue: T, valueSupplier: () -> T) {
fun <T> waitingAssertEquals(errorMessage: String, expectedValue: T, valueSupplier: () -> T) {
return waitingAssertion(
errorMessage,
valueSupplier
) { it == expectedValue }
}

fun <T> waitingAssertion(errorMessage: String, valueSupplier: () -> T, assertion: (T) -> Boolean) {
var lastValue: T? = null
waitFor(Duration.ofSeconds(20), errorMessageSupplier = { "$errorMessage Actual value was $lastValue" }) {
lastValue = valueSupplier()
lastValue == expectedValue
waitFor(Duration.ofSeconds(20), errorMessageSupplier = { "$errorMessage. Actual value was: $lastValue" }) {
val value = valueSupplier()
lastValue = value
assertion(value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ import java.nio.file.Paths

private var started = false

private val requestedIdeCode: String
get() = getEnvValue("IDE_CODE")

private fun getEnvValue(key: String) = requireNotNull(System.getenv(key)) {
"$key environment variable should be set"
}

val hasJavaSupport: Boolean
get() = when (requestedIdeCode) {
"AI", "AQ", "IC", "IU" -> true
else -> false
}

class LaunchIdeExtension : BeforeAllCallback, ExtensionContext.Store.CloseableResource {
private lateinit var process: Process
private lateinit var tempDir: Path
Expand All @@ -30,12 +43,8 @@ class LaunchIdeExtension : BeforeAllCallback, ExtensionContext.Store.CloseableRe

tempDir = Files.createTempDirectory("junit")

val requestedIdeCode = requireNotNull(System.getenv("IDE_CODE")) {
"IDE_CODE environment variable should be set"
}
val requestedIdeVersion = requireNotNull(System.getenv("IDE_VERSION")) {
"IDE_CODE environment variable should be set"
}
val requestedIdeCode = requestedIdeCode
val requestedIdeVersion = getEnvValue("IDE_VERSION")

val ideDownloader = IdeDownloader(OkHttpClient())
val cacheDir = getCacheRoot(tempDir)
Expand All @@ -48,6 +57,9 @@ class LaunchIdeExtension : BeforeAllCallback, ExtensionContext.Store.CloseableRe
ideDownloader.getIde(ide, requestedIdeVersion, cacheDir)
}

// TODO: Remove this once https://github.com/JetBrains/intellij-ui-test-robot/issues/387 is fixed
workaroundRemoteIdeIssue(pathToIde)

val pluginPath = requireNotNull(System.getenv("PLUGIN_PATH")) {
"PLUGIN_PATH environment variable should be set"
}.let { Paths.get(it) }
Expand Down Expand Up @@ -81,6 +93,22 @@ class LaunchIdeExtension : BeforeAllCallback, ExtensionContext.Store.CloseableRe
context.root.getStore(GLOBAL).put(LaunchIdeExtension::class.java.name, this)
}

private fun workaroundRemoteIdeIssue(pathToIde: Path) {
val binDir = when (Os.hostOS()) {
Os.MAC -> pathToIde.resolve("Contents").resolve("bin")
else -> pathToIde.resolve("bin")
}
Files.list(binDir)
.filter {
it.fileName.toString().endsWith(".vmoptions")
&& it.fileName.toString().contains("_client")
}
.forEach {
println("Removing unsupported $it")
Files.delete(it)
}
}

override fun close() {
try {
kotlin.runCatching {
Expand Down Expand Up @@ -122,7 +150,13 @@ class LaunchIdeExtension : BeforeAllCallback, ExtensionContext.Store.CloseableRe
.resolve("${ide.code}-$requestedIdeVersion")
.apply { Files.createDirectories(this) }
val previousArchive = ideCacheDir.toFile().listFiles { f: File -> f.isFile && !f.isHidden }?.singleOrNull()
val previousExtractedDir = ideCacheDir.toFile().listFiles { f: File -> f.isDirectory }?.singleOrNull()

val previousExtractedDir = getExtractedIdeDir(ideCacheDir)
if (previousExtractedDir != null) {
println("File was already downloaded and extracted, so using $previousExtractedDir")
return previousExtractedDir.toPath()
}

return try {
val extractedPath = when (requestedIdeVersion) {
"LATEST_EAP" -> downloadAndExtractLatestEap(ide, ideCacheDir)
Expand All @@ -131,25 +165,32 @@ class LaunchIdeExtension : BeforeAllCallback, ExtensionContext.Store.CloseableRe
Ide.BuildType.RELEASE, requestedIdeVersion
)
}
if (previousArchive != null || previousExtractedDir != null) {
println("Found stale files from the previous download, deleting...")
previousArchive?.delete()
previousExtractedDir?.deleteRecursively()
if (previousArchive != null) {
println("Found a stale archive from the previous download, deleting...")
previousArchive.delete()
println("Deleted")
}

extractedPath
} catch (e: FileAlreadyExistsException) {
val extractedDir = ideCacheDir.toFile()
.listFiles { f: File -> f.isDirectory }
?.single()
val extractedDir = getExtractedIdeDir(ideCacheDir)
?.toPath()
?: error("Archive is already download, but extracted dir wasn't found. Please fix the cache.")
?: error("Archive was already downloaded, but extracted dir wasn't found. Please fix the cache.")
println("File was already downloaded, so using $extractedDir")
extractedDir
}
}

private fun getExtractedIdeDir(ideCacheDir: Path): File? {
val candidateDirs = ideCacheDir.toFile().listFiles { f: File -> f.isDirectory }
?: error("$ideCacheDir should be a directory")
return when(candidateDirs.size) {
0 -> null
1 -> candidateDirs.single()
else -> error("Found multiple extracted directories under $ideCacheDir, but expected no more then one")
}
}

private fun IdeDownloader.getRobotPlugin(cacheDir: Path) = try {
downloadRobotPlugin(cacheDir)
} catch (e: FileAlreadyExistsException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.IdeaFrame
import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.idea
import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.locateElementToolWindow
import com.github.tarcv.testingteam.surveyoridea.trimAllIndent
import com.github.tarcv.testingteam.surveyoridea.waitingAssertion
import com.github.tarcv.testingteam.surveyoridea.waitingAssertEquals
import com.intellij.remoterobot.utils.keyboard
import org.apache.commons.text.StringEscapeUtils
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -81,7 +81,7 @@ class LocateActionUiTests : BaseTestProjectTests() {
}
triggerActionWithBlock()

waitingAssertion(
waitingAssertEquals(
"Correct node should be selected.",
"""
<node index="4" text="-0.00" resource-id="com.github.tarcv.converter:id/celsiusText"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.github.tarcv.testingteam.surveyoridea.gui

import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.idea
import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.locateElementToolWindow
import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.noticeFrame
import com.github.tarcv.testingteam.surveyoridea.waitingAssertion
import org.junit.jupiter.api.Test
import java.lang.Thread.sleep

class NoticeTests : BaseTestProjectTests() {
@Test
fun testLocatingFromToolButton() = with(remoteRobot) {
idea {
openFileInTestProject(droidAutomatorSnapshotFile, "editorWithSnapshot")

selectInMenuBar(
"View",
"Tool Windows",
"Locate Element"
)

// Opening 'Locate Element' tool window sometimes causes reindexing
sleep(2_000)
commonSteps.waitForSmartMode(1)

locateElementToolWindow {
noticeButton.click()
}
}
noticeFrame {
val overallIntroFragment = "depends on libraries which are covered by"

waitingAssertion("Correct text is present in the overall intro area", { overallIntro.text }) {
it.contains(overallIntroFragment)
}

jList {
clickItem("UIAutomator library - Apache License")
}
waitingAssertion("Correct text is present in the overall intro area", { overallIntro.text }) {
it.contains(overallIntroFragment)
}
waitingAssertion("Correct text is present in the notice intro area", { noticeIntro.text }) {
it.contains("library which is covered by")
}
waitingAssertion("Correct text is present in the notice area", { noticeText.text }) {
it.contains("Licensed under the Apache License")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package com.github.tarcv.testingteam.surveyoridea.gui

import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.idea
import com.github.tarcv.testingteam.surveyoridea.gui.fixtures.locateElementToolWindow
import com.github.tarcv.testingteam.surveyoridea.hasJavaSupport
import com.intellij.remoterobot.client.IdeaSideException
import com.intellij.remoterobot.utils.keyboard
import com.intellij.remoterobot.utils.waitFor
import org.apache.commons.text.StringEscapeUtils
import org.junit.jupiter.api.Assumptions
import org.junit.jupiter.api.Test
import java.awt.Point
import java.lang.Thread.sleep
Expand All @@ -15,6 +17,8 @@ import kotlin.test.assertEquals
class ParsingTest : BaseTestProjectTests() {
@Test
fun testDroidSelectorParsing() = with(remoteRobot) {
Assumptions.assumeTrue(hasJavaSupport, "This feature requires an IDE with Java support")

idea {
openFileInTestProject(droidAutomatorSnapshotFile, "editorWithSnapshot")

Expand Down
Loading

0 comments on commit b3eb0c1

Please sign in to comment.