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

ci: add ui tests #6

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
58 changes: 58 additions & 0 deletions .github/workflows/_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Reusable Test Workflow
name: _Test

on:
workflow_call:

jobs:
test-ui:
name: Test UI (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
runTests: |
export DISPLAY=:99.0
Xvfb -ac :99 -screen 0 1920x1080x24 &
sleep 10
./gradlew test
reportName: ui-test-fails-report-linux
- os: windows-latest
runTests: ./gradlew test
reportName: ui-test-fails-report-windows
- os: macos-latest
runTests: ./gradlew test
reportName: ui-test-fails-report-mac

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup
uses: ./.github/actions/setup

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 18

- name: Install basic project fixture dependencies
working-directory: src/test/testData/basic-project
run: npm i

- name: Install IDEA license key
run: |
mkdir -p ./build/idea-sandbox/config-uiTest
echo "${{ secrets.JETBRAINS_LICENSE_KEY }}" | base64 --decode > ./build/idea-sandbox/config-uiTest/idea.key

- name: Run
run: ${{ matrix.runTests }}

- name: Save fails report
if: ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.reportName }}
path: ./build/reports
3 changes: 3 additions & 0 deletions .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ jobs:
build:
name: Build
uses: ./.github/workflows/_build.yaml
test:
name: Test
uses: ./.github/workflows/_test.yaml
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ repositories {
dependencies {
testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
testImplementation("com.intellij.remoterobot:ide-launcher:$remoteRobotVersion")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.9.3")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,89 +2,144 @@ package com.github.biomejs.intellijbiome

import com.github.biomejs.intellijbiome.pages.*
import com.github.biomejs.intellijbiome.utils.RemoteRobotExtension
import java.awt.event.KeyEvent.*
import com.github.biomejs.intellijbiome.utils.StepsLogger
import com.github.biomejs.intellijbiome.utils.isAvailable
import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.launcher.Ide
import com.intellij.remoterobot.launcher.IdeDownloader
import com.intellij.remoterobot.launcher.IdeLauncher
import com.intellij.remoterobot.launcher.Os
import com.intellij.remoterobot.stepsProcessing.StepLogger
import com.intellij.remoterobot.stepsProcessing.StepWorker
import com.intellij.remoterobot.stepsProcessing.step
import com.intellij.remoterobot.utils.keyboard
import com.intellij.remoterobot.utils.waitFor
import com.intellij.remoterobot.utils.waitForIgnoringError
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import okhttp3.OkHttpClient
import org.junit.jupiter.api.*
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.TestWatcher
import java.awt.Point
import java.awt.event.KeyEvent.*
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.time.Duration
import java.time.Duration.ofMinutes
import java.util.concurrent.TimeUnit
import javax.imageio.ImageIO


@ExtendWith(RemoteRobotExtension::class)
class BasicProjectNpmTest {



init {
StepsLogger.init()
}

@BeforeEach
fun waitForIde(remoteRobot: RemoteRobot) {
fun waitForIde() {
waitForIgnoringError(ofMinutes(3)) { remoteRobot.callJs("true") }
}

@Test
fun openQuickFixes(remoteRobot: RemoteRobot) = with(remoteRobot) {
fun checkStatusBarVersion() = with(remoteRobot) {
idea {
step("Check biome running version") {

step("Open index.js file") {
waitFor(ofMinutes(5)) { isDumbMode().not() }

step("Open file") {
openFile("index.js")
val editor = editor("index.js")
editor.click(Point(0, 0))
}
}

step("Open quickfixes dialog") {
keyboard {
hotKey(VK_ALT, VK_ENTER)
}
quickfix {
val items = collectItems()


assertTrue(items.contains("Use 'const' instead."))
assertTrue(items.contains("Suppress rule lint/style/noVar"))
}
}
step("Check Biome's version in statusbar") {
statusBar {
val biomeWidget = byContainsText("Biome")
val version = biomeWidget.callJs<String>("component.getText();")

keyboard {
hotKey(VK_ESCAPE)
assert(version == "Biome 1.4.1")
}
}
}

}

companion object {
private val basicProjectPath = File("src/test/testData/basic-project")
private var ideaProcess: Process? = null
private var tmpDir: Path = Files.createTempDirectory("launcher")
private lateinit var remoteRobot: RemoteRobot

@JvmStatic
@BeforeAll
fun selectProject(remoteRobot: RemoteRobot) = with(remoteRobot) {
welcomeFrame {
openProjectLink.click()
dialog("Open File or Project") {
directoryPath.text = basicProjectPath.absolutePath
button("OK").click()
fun startup() {
StepWorker.registerProcessor(StepLogger())

val client = OkHttpClient()
remoteRobot = RemoteRobot("http://localhost:8082", client)
val ideDownloader = IdeDownloader(client)

val pathToIde = ideDownloader.downloadAndExtract(Ide.IDEA_ULTIMATE, tmpDir, Ide.BuildType.RELEASE)

println("fixing vmoptions files...")
val ideBinDir = pathToIde.resolve(
when (Os.hostOS()) {
Os.MAC -> "Contents/bin"
else -> "bin"
}
)
Files
.list(ideBinDir)
.filter {
val filename = it.fileName.toString()
filename == "jetbrains_client.vmoptions"
}
.forEach {
println("Deleting problematic file $it")
Files.delete(it)
}

ideaProcess = IdeLauncher.launchIde(
pathToIde,
mapOf(
"robot-server.port" to 8082,
"ide.mac.message.dialogs.as.sheets" to false,
"jb.privacy.policy.text" to "<!--999.999-->",
"jb.consents.confirmation.enabled" to false,
"ide.mac.file.chooser.native" to false,
"jbScreenMenuBar.enabled" to false,
"apple.laf.useScreenMenuBar" to false,
"idea.trust.all.projects" to true,
"ide.show.tips.on.startup.default.value" to false,
"eap.require.license" to false
),
emptyList(),
listOf(ideDownloader.downloadRobotPlugin(tmpDir)),
tmpDir
)
waitFor(Duration.ofSeconds(120), Duration.ofSeconds(5)) {
remoteRobot.isAvailable()
}

with(remoteRobot) {
welcomeFrame {
openProjectLink.click()
dialog("Open File or Project") {
directoryPath.text = basicProjectPath.absolutePath
button("OK").click()
}
}
}
}

@JvmStatic
@AfterAll
fun closeProject(remoteRobot: RemoteRobot) = with(remoteRobot) {
fun cleanup() = with(remoteRobot) {
ideaProcess?.destroy()
tmpDir.toFile().deleteRecursively()
idea {
menuBar.select("File", "Close Project")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package com.github.biomejs.intellijbiome.pages

import com.intellij.remoterobot.RemoteRobot
import com.intellij.remoterobot.data.RemoteComponent
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.*
import com.intellij.remoterobot.search.locators.byXpath
import java.time.Duration

Expand All @@ -26,8 +23,8 @@ class StatusbarFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent)
)
)

fun byContainsText(text: String) =
byXpath("text $text", "//div[contains(@text,'$text') and @class='WithIconAndArrows']")
fun byContainsText(text: String): ComponentFixture =
find<ComponentFixture>(byXpath("//div[contains(@text,'$text') and @text.key='biome.widget.version']"))

val text: String
get() = callJs("component.getText();")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.biomejs.intellijbiome.utils

import com.intellij.remoterobot.RemoteRobot

fun RemoteRobot.isAvailable(): Boolean = runCatching {
callJs<Boolean>("true")
}.getOrDefault(false)
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class RemoteRobotExtension : AfterTestExecutionCallback, ParameterResolver {
val testMethodName = testMethod.name
val testFailed: Boolean = context.executionException?.isPresent ?: false
if (testFailed) {
// saveScreenshot(testMethodName)
saveScreenshot(testMethodName)
saveIdeaFrames(testMethodName)
saveHierarchy(testMethodName)
}
Expand Down
1 change: 1 addition & 0 deletions src/test/testData/basic-project/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
Loading
Loading