Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4bce544

Browse files
Merge pull request #2511 from vitaliyboykocontributor/new-module-ui-test
New module creation UI test + Refactor and consolidate UI test setup ...
2 parents 25eae35 + f4c1566 commit 4bce544

File tree

11 files changed

+430
-158
lines changed

11 files changed

+430
-158
lines changed

‎.github/workflows/gradle.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- name: Grant execute permission for gradlew
3333
run: chmod +x gradlew
3434
- name: Run automated tests
35-
run: ./gradlew test --no-daemon
35+
run: ./gradlew test -PexcludeTests="**/userInterface/**" --no-daemon
3636

3737
build-windows:
3838
runs-on: windows-latest
@@ -58,7 +58,7 @@ jobs:
5858
- name: Grant execute permission for gradlew
5959
run: chmod +x gradlew
6060
- name: Run automated tests
61-
run: ./gradlew test --no-daemon
61+
run: ./gradlew test -PexcludeTests="**/userInterface/**" --no-daemon
6262

6363
build-macos:
6464
runs-on: macos-latest
@@ -84,7 +84,7 @@ jobs:
8484
- name: Grant execute permission for gradlew
8585
run: chmod +x gradlew
8686
- name: Run automated tests
87-
run: ./gradlew test --no-daemon
87+
run: ./gradlew test -PexcludeTests="**/userInterface/**" --no-daemon
8888

8989
static-tests:
9090
runs-on: ubuntu-latest

‎.github/workflows/uitests.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
if: matrix.os == 'ubuntu-latest'
6767
run: |
6868
export DISPLAY=:99.0
69-
./gradlew uiTests
69+
./gradlew test -PexcludeTests="**/reference/**,**/linemarker/**,**/inspections/**,**/completion/**,**/actions/**"
7070
7171
# Uncomment if investigation is needed:
7272

‎build.gradle.kts‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,15 @@ tasks {
137137
}
138138

139139
test {
140-
exclude("**/userInterface/**")
140+
val excludePatterns = project.findProperty("excludeTests") as String?
141+
142+
if (!excludePatterns.isNullOrEmpty()) {
143+
// Split the comma-separated string and apply exclusions
144+
excludePatterns.split(",").forEach {
145+
exclude(it.trim())
146+
}
147+
}
148+
141149
useJUnitPlatform()
142150
}
143151

@@ -247,11 +255,3 @@ kover {
247255
}
248256
}
249257
}
250-
251-
tasks.register<Test>("uiTests") {
252-
exclude("**/reference/**")
253-
exclude("**/linemarker/**")
254-
exclude("**/inspections/**")
255-
exclude("**/completion/**")
256-
exclude("**/actions/**") // Deprecated, all actions should be reimplemented in the UI tests and this exclude should be removed
257-
}

‎runTests.sh‎

Lines changed: 0 additions & 16 deletions
This file was deleted.

‎runUiTests.sh‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
rm -rf intellij-test-project
4+
./gradlew clean
5+
./gradlew runIdeForUiTests &
6+
RUN_IDE_PID=$!
7+
8+
sleep 10
9+
10+
./gradlew test -PexcludeTests="**/reference/**,**/linemarker/**,**/inspections/**,**/completion/**,**/actions/**" --no-daemon
11+
12+
kill $RUN_IDE_PID
13+
14+
wait $RUN_IDE_PID 2>/dev/null

‎src/main/java/com/magento/idea/magento2plugin/actions/generation/dialog/NewModuleDialog.form‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
44
<margin top="10" left="10" bottom="10" right="10"/>
55
<constraints>
6-
<xy x="48" y="54" width="746" height="642"/>
6+
<xy x="48" y="54" width="746" height="646"/>
77
</constraints>
88
<properties>
99
<preferredSize width="455" height="600"/>
@@ -68,6 +68,7 @@
6868
</grid>
6969
</constraints>
7070
<properties>
71+
<name value="Package Name"/>
7172
<text value=""/>
7273
<toolTipText resource-bundle="magento2/validation" key="validator.mustNotBeEmptyShouldContainLettersOrNumbers"/>
7374
</properties>
@@ -92,6 +93,7 @@
9293
</grid>
9394
</constraints>
9495
<properties>
96+
<name value="Module Name"/>
9597
<text value=""/>
9698
<toolTipText resource-bundle="magento2/validation" key="validator.mustNotBeEmptyShouldContainLettersOrNumbers"/>
9799
</properties>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.pages
7+
8+
import com.intellij.remoterobot.RemoteRobot
9+
import com.intellij.remoterobot.data.RemoteComponent
10+
import com.intellij.remoterobot.fixtures.CommonContainerFixture
11+
import com.intellij.remoterobot.fixtures.DefaultXpath
12+
import com.intellij.remoterobot.fixtures.FixtureName
13+
import com.intellij.remoterobot.fixtures.JTextFieldFixture
14+
import com.intellij.remoterobot.search.locators.byXpath
15+
import java.time.Duration
16+
17+
fun RemoteRobot.createAModuleDialog(function: CreateAModuleDialogFixture.() -> Unit) {
18+
find<CreateAModuleDialogFixture>(timeout = Duration.ofSeconds(10)).apply(function)
19+
}
20+
21+
@FixtureName("CreateAModuleDialog")
22+
@DefaultXpath("CreateAModuleDialog type", "//div[@class='NewModuleDialog']")
23+
class CreateAModuleDialogFixture(
24+
remoteRobot: RemoteRobot,
25+
remoteComponent: RemoteComponent) : CommonContainerFixture(remoteRobot, remoteComponent) {
26+
27+
val packageName
28+
get() = find<JTextFieldFixture>(byXpath("FilteredComboBox", "//div[@name='Package Name']"))
29+
30+
val moduleName
31+
get() = find<JTextFieldFixture>(byXpath("FilteredComboBox", "//div[@name='Module Name']"))
32+
}

‎src/test/kotlin/com/magento/idea/magento2plugin/pages/IdeaFrame.kt‎

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import com.intellij.remoterobot.RemoteRobot
99
import com.intellij.remoterobot.data.RemoteComponent
1010
import com.intellij.remoterobot.fixtures.*
1111
import com.intellij.remoterobot.search.locators.byXpath
12-
import com.intellij.remoterobot.stepsProcessing.step
13-
import com.intellij.remoterobot.utils.waitFor
1412
import java.time.Duration
1513

1614

@@ -29,21 +27,6 @@ class IdeaFrame(remoteRobot: RemoteRobot, remoteComponent: RemoteComponent) :
2927
val projectViewTree
3028
get() = find<ContainerFixture>(byXpath("//div[@class='ProjectViewTree']"))
3129

32-
@JvmOverloads
33-
fun dumbAware(timeout: Duration = Duration.ofMinutes(5), function: () -> Unit) {
34-
step("Wait for smart mode") {
35-
waitFor(duration = timeout, interval = Duration.ofSeconds(5)) {
36-
runCatching { isDumbMode().not() }.getOrDefault(false)
37-
}
38-
function()
39-
step("..wait for smart mode again") {
40-
waitFor(duration = timeout, interval = Duration.ofSeconds(5)) {
41-
isDumbMode().not()
42-
}
43-
}
44-
}
45-
}
46-
4730
fun isProjectViewVisible(): Boolean {
4831
return try {
4932
with(projectViewTree) {
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.steps
7+
8+
import com.intellij.remoterobot.RemoteRobot
9+
import com.intellij.remoterobot.fixtures.ContainerFixture
10+
import com.intellij.remoterobot.fixtures.JTextFieldFixture
11+
import com.intellij.remoterobot.search.locators.byXpath
12+
import com.intellij.remoterobot.steps.CommonSteps
13+
import com.intellij.remoterobot.stepsProcessing.step
14+
import com.intellij.remoterobot.utils.keyboard
15+
import com.intellij.remoterobot.utils.waitFor
16+
import com.magento.idea.magento2plugin.pages.*
17+
import java.awt.Point
18+
import java.awt.event.KeyEvent.*
19+
import java.io.File
20+
import java.io.IOException
21+
import java.nio.file.Paths
22+
import java.time.Duration.ofMinutes
23+
import java.util.*
24+
25+
class SharedSteps(private val remoteRobot: RemoteRobot) {
26+
private lateinit var tempProjectDir: File
27+
28+
fun createOrOpenTestProject(): File {
29+
setupTemporaryMagentoProject()
30+
31+
step("Create Or Open Test Project", Runnable {
32+
try {
33+
remoteRobot.welcomeFrame {
34+
val newProjectButton = remoteRobot.find(
35+
ContainerFixture::class.java,
36+
byXpath("//div[@visible_text='New Project']")
37+
)
38+
newProjectButton.click()
39+
Thread.sleep(2_000)
40+
41+
val jTextFieldFixture = find<JTextFieldFixture>(byXpath("//div[@class='TextFieldWithBrowseButton']"))
42+
jTextFieldFixture.click()
43+
jTextFieldFixture.keyboard {
44+
hotKey(VK_CONTROL, VK_A)
45+
key(VK_DELETE)
46+
enterText(tempProjectDir.absolutePath.toString().replace("\\", "\\\\"))
47+
}
48+
keyboard { key(VK_ENTER) }
49+
50+
dialog("Directory Is Not Empty") {
51+
button("Create from Existing Sources").click()
52+
}
53+
54+
enableMagentoSupport()
55+
}
56+
} catch (exception: Exception) {
57+
// temporary workaround until we get license for CI
58+
activateIde()
59+
// end temporary workaround
60+
try {
61+
val launchedFromScript = remoteRobot.find(
62+
ContainerFixture::class.java,
63+
byXpath("//div[@class='LinkLabel']")
64+
)
65+
launchedFromScript.click()
66+
} catch (e: Exception) {
67+
// Element does not exist, continue without failing the test
68+
}
69+
70+
createProjectFromExistingFiles()
71+
enableMagentoSupport()
72+
}
73+
})
74+
75+
return tempProjectDir;
76+
}
77+
78+
fun closeProject() {
79+
CommonSteps(remoteRobot).closeProject()
80+
}
81+
82+
private fun setupTemporaryMagentoProject() {
83+
// Create a parent directory and a random child directory inside it
84+
val parentDir = Paths.get("intellij-test-project").toFile()
85+
if (parentDir.exists()) {
86+
parentDir.deleteRecursively()
87+
}
88+
parentDir.mkdirs()
89+
90+
// Create a randomly named child directory inside the parent directory
91+
tempProjectDir = File(parentDir, UUID.randomUUID().toString()).apply {
92+
mkdirs()
93+
}
94+
95+
// Define the source directory for the test data
96+
val sourceDir = File("testData/project/magento2")
97+
98+
// Copy the test data to the temporary directory
99+
sourceDir.copyRecursively(
100+
target = tempProjectDir,
101+
overwrite = true
102+
)
103+
}
104+
105+
private fun activateIde() {
106+
if ("true" == System.getenv("GITHUB_ACTIONS")) {
107+
val startTrial =
108+
remoteRobot.find(ContainerFixture::class.java, byXpath("//div[@visible_text='Start trial']"))
109+
startTrial.click()
110+
111+
val startTrialFree = remoteRobot.find(ContainerFixture::class.java, byXpath("//div[@class='s']"))
112+
startTrialFree.click()
113+
114+
val dialog = remoteRobot.find(
115+
DialogFixture::class.java, byXpath("//div[@class='MyDialog']")
116+
)
117+
dialog.button("Close").click()
118+
119+
try {
120+
Thread.sleep(10000)
121+
} catch (e: InterruptedException) {
122+
Thread.currentThread().interrupt()
123+
throw RuntimeException(e)
124+
}
125+
126+
closeBrowser()
127+
} else {
128+
val dialog = remoteRobot.find(
129+
DialogFixture::class.java, byXpath("//div[@class='MyDialog']")
130+
)
131+
dialog.button("Activate").click()
132+
dialog.button("Close").click()
133+
}
134+
}
135+
136+
private fun enableMagentoSupport() {
137+
remoteRobot.idea {
138+
step("Enable Magento Integration") {
139+
waitFor(ofMinutes(1)) { isDumbMode().not() }
140+
Thread.sleep(5_000)
141+
enableSupportLink.click(Point(1, 1))
142+
waitFor(ofMinutes(1)) { isDumbMode().not() }
143+
144+
if (!isProjectViewVisible()) {
145+
keyboard {
146+
hotKey(VK_ALT, VK_1)
147+
}
148+
}
149+
}
150+
}
151+
}
152+
153+
private fun createProjectFromExistingFiles() {
154+
remoteRobot.welcomeFrame {
155+
try {
156+
val launchedFromScript = find<ContainerFixture>(byXpath("//div[@class='LinkLabel']"))
157+
launchedFromScript.click()
158+
} catch (e: Exception) {
159+
// Element does not exist, continue without failing the test
160+
}
161+
162+
createNewProjectFromExistingFilesLink.click()
163+
selectProjectPath()
164+
}
165+
}
166+
167+
private fun WelcomeFrame.selectProjectPath() {
168+
dialog("Open File or Project") {
169+
// Set the path for the copied test data
170+
val comboBox = find<ContainerFixture>(byXpath("//div[@class='BorderlessTextField']"))
171+
comboBox.click() // Focus on the comboBox
172+
comboBox.keyboard {
173+
hotKey(VK_CONTROL, VK_A) // Select all text
174+
key(VK_DELETE) // Delete selected text
175+
enterText(tempProjectDir.absolutePath.toString().replace("\\", "\\\\"))
176+
}
177+
178+
button("OK").click()
179+
trustProjectLink.click()
180+
}
181+
}
182+
183+
/**
184+
* Closes the browser by terminating its process based on the operating system.
185+
*/
186+
fun closeBrowser() {
187+
val os = System.getProperty("os.name").lowercase(Locale.getDefault())
188+
189+
try {
190+
if (os.contains("win")) {
191+
// For Windows: Close common browsers like Chrome, Firefox, etc.
192+
Runtime.getRuntime().exec("taskkill /F /IM edge.exe")
193+
} else if (os.contains("mac")) {
194+
// For macOS: Kill browsers using `pkill`
195+
Runtime.getRuntime().exec("killall -9 safari")
196+
} else if (os.contains("nix") || os.contains("nux")) {
197+
// For Linux-based systems: Kill typical browser processes
198+
Runtime.getRuntime().exec("killall -9 firefox")
199+
}
200+
} catch (e: IOException) {
201+
e.printStackTrace()
202+
}
203+
}
204+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /