Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to fix e2e flakiness #59

Merged
merged 15 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,22 @@ Now open the plugin's code in IntelliJ IDEA. Create a new Gradle run configurati
Running this configuration in debug will open a new IDE window.
You can set breakpoints in the plugin's code in the first window, and use the plugin in the second window to reach the breakpoints.

You can control which IDE is opened with a `PLATFORMTYPE` environment variable. For example, set `PLATFORMTYPE=IU` for IntelliJ IDEA Ultimate.
You can control which IDE is opened with a `PLATFORMTYPE` environment variable. For example, set `PLATFORMTYPE=IU` for IntelliJ IDEA Ultimate.


## Adding E2E tests

We use the [intellij-ui-test-robot](https://github.com/JetBrains/intellij-ui-test-robot) to automate UI tests for the extension.

- If you have made a change to the UI, to add new tests, run `./gradlew runIdeForUITests` and open a test project,
go to [localhost:8082](http://localhost:8082) and choose the elements you want to click on by their Xpath.

- To make sure the test doesn't flake in the CI, check if all the elements related to UI component have loaded by using
a `waitFor` fixture or if a change depends on files to be indexed, use the `dumbAware` fixture.

- As a rule of thumb try to encapsulate functionality in fixtures in the `utils` folder.

- To verify things work as expected locally,
infiniteregrets marked this conversation as resolved.
Show resolved Hide resolved



11 changes: 6 additions & 5 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ version = properties("pluginVersion")
// Configure project's dependencies
repositories {
mavenCentral()
maven {
url = uri("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
repositories {
maven {
url = uri("https://packages.jetbrains.team/maven/p/iuia/qa-automation-maven")
}
}

maven {
url = uri("https://packages.jetbrains.team/maven/p/iuia/qa-automation-maven")
url = uri("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
}
}

val remoteRobotVersion = "0.11.19.416"
val remoteRobotVersion = "0.11.19"

dependencies {
implementation(project(":mirrord-products-idea"))
Expand Down
1 change: 1 addition & 0 deletions changelog.d/+e2e-fix.internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix e2e flakiness
30 changes: 21 additions & 9 deletions src/test/kotlin/com/metalbear/mirrord/MirrordPluginTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal class MirrordPluginTest {
init {
StepsLogger.init()
}

companion object {
private var ideaProcess: Process? = null
private var tmpDir: Path = Files.createTempDirectory("launcher")
Expand Down Expand Up @@ -92,16 +93,22 @@ internal class MirrordPluginTest {
}
idea {
step("Create config file") {
waitFor(ofSeconds(60)) {
mirrordDropdownButton.isShowing
// issue here is that elements move when git is visible
git.isShowing
}
// as per the extension this doesn't need to be in the dumbAware block
// however, there can be a loading page which can only be ignored by the
// dumbAware block
dumbAware {
waitFor(ofSeconds(30)) {
mirrordDropdownButton.isShowing
}
mirrordDropdownButton.click()
}
mirrordDropdownButton.click()

waitFor(ofSeconds(30)) {
mirrordDropdownMenu.isShowing
}

mirrordDropdownMenu.findText("Settings").click()

editorTabs {
Expand All @@ -112,11 +119,16 @@ internal class MirrordPluginTest {
}

step("Open `app.py`") {
openFileByName("app.py")

editorTabs {
with(projectViewTree) {
infiniteregrets marked this conversation as resolved.
Show resolved Hide resolved
waitFor(ofSeconds(30)) {
isFileOpened("app.py")
hasText("app.py")
hasText(".mirrord")
}
findText("app.py").doubleClick()
editorTabs {
waitFor {
isFileOpened("app.py")
}
}
}

Expand Down Expand Up @@ -156,8 +168,8 @@ internal class MirrordPluginTest {
enableMirrord.isShowing
startDebugging.isShowing
}
enableMirrord.click()
dumbAware {
enableMirrord.click()
startDebugging.click()
}
step("Select pod to mirror traffic from") {
Expand Down
40 changes: 9 additions & 31 deletions src/test/kotlin/com/metalbear/mirrord/utils/IdeaFrame.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import com.intellij.remoterobot.data.RemoteComponent
import com.intellij.remoterobot.fixtures.*
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 java.time.Duration

Expand All @@ -29,6 +28,15 @@ class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) :
Duration.ofSeconds(30)
)

val git
get() = find<ContainerFixture>(byXpath("//div[@visible_text='Git:' and @class='MyLabel']"), Duration.ofSeconds(30))

val projectViewTree
get() = find<ContainerFixture>(
byXpath("ProjectViewTree", "//div[@class='ProjectViewTree']"),
Duration.ofSeconds(60)
)

val mirrordDropdownMenu
get() = find<ContainerFixture>(
byXpath("//div[@class='MyList' and (@visible_text='Disabled || Select Active Config || Configuration || Settings' or @visible_text='Disabled || Settings || Configuration')]"),
Expand Down Expand Up @@ -57,27 +65,6 @@ class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) :
val xDebuggerFramesList
get() = find<ContainerFixture>(byXpath("//div[@class='XDebuggerFramesList']"))

fun openFileByName(name: String) {
find<ContainerFixture>(byXpath("//div[@class='ActionMenu' and @text='Navigate']")).click()
waitFor {
findAll<ContainerFixture>(byXpath("//div[@class='ActionMenuItem' and @text='Search Everywhere' and @defaulticon='find.svg']"))
.isNotEmpty()
}
findAll<ContainerFixture>(byXpath("//div[@class='ActionMenuItem' and @text='Search Everywhere' and @defaulticon='find.svg']"))
.first()
.click()
find<ContainerFixture>(byXpath("//div[@class='SearchField' and @visible_text='Type / to see commands']")).click()
keyboard {
enterText(name)
}
var listElems = emptyList<ContainerFixture>()
waitFor(Duration.ofSeconds(30)) {
listElems = findAll<ContainerFixture>(byXpath("//div[@class='JBList']")).filter { it.hasText(name) }
listElems.isNotEmpty()
}
listElems.first().findText(name).click()
}

// dumb and smart mode refer to the state of the IDE when it is indexing and not indexing respectively
@JvmOverloads
fun dumbAware(timeout: Duration = Duration.ofMinutes(5), function: () -> Unit) {
Expand Down Expand Up @@ -158,12 +145,3 @@ class StatusBar(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) :
).isEmpty()
}
}

fun RemoteRobot.leftStripe(function: LeftStripe.() -> Unit) {
find<LeftStripe>(timeout = Duration.ofSeconds(60)).apply(function)
}

// reprsents the slim bar on the left showing bookmarks, project, etc.
@DefaultXpath("Stripe type", "//div[@class='Stripe'][.//div[contains(@text.key, 'project.scheme')]]")
class LeftStripe(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) :
CommonContainerFixture(remoteRobot, remoteComponent)