@@ -34,37 +34,95 @@ class ModuleMakerUiTest {
3434 @Test
3535 fun `opens via Find Action and creates repository module` () {
3636 with (remoteRobot) {
37- step(" Wait for IDE frame to load " ) {
37+ step(" Wait for IDE to be ready and dismiss blocking dialogs " ) {
3838 waitFor(duration = Duration .ofMinutes(3 ), interval = Duration .ofSeconds(2 )) {
3939 dismissBlockingDialogs()
40- findAll<ComponentFixture >(
40+
41+ // Check if the project frame is open
42+ val ideFrame = findAll<ComponentFixture >(
4143 byXpath(" //div[@class='IdeFrameImpl']" )
42- ).isNotEmpty()
44+ )
45+ if (ideFrame.isNotEmpty()) {
46+ println (" Found IdeFrameImpl" )
47+ true
48+ } else {
49+ // Dump what top-level components exist so we can diagnose CI failures
50+ val allComponents = findAll<ComponentFixture >(byXpath(" //div" ))
51+ val classNames = allComponents.mapNotNull { fixture ->
52+ try {
53+ fixture.callJs<String >(" component.getClass().getName()" )
54+ } catch (_: Exception ) {
55+ null
56+ }
57+ }.distinct()
58+ println (" Waiting for IdeFrameImpl... Found components: ${classNames.take(30 )} " )
59+
60+ // If stuck on Welcome screen, the project didn't auto-open
61+ val welcomeFrame = findAll<ComponentFixture >(
62+ byXpath(" //div[@class='FlatWelcomeFrame']" )
63+ )
64+ if (welcomeFrame.isNotEmpty()) {
65+ println (" Detected Welcome screen - project did not auto-open" )
66+ }
67+
68+ false
69+ }
4370 }
4471 }
4572
46- step(" Open Module Maker via Find Action" ) {
47- find<ComponentFixture >(
48- byXpath(" //div[@class='IdeFrameImpl']" ),
49- Duration .ofSeconds(10 )
50- ).click()
73+ step(" Wait for IDE to settle after loading" ) {
74+ // On CI the IDE may still be indexing or initializing after the frame appears.
75+ // Give it time before sending hotkeys.
76+ Thread .sleep(10_000 )
77+ // Dismiss any dialogs that appeared during loading
78+ dismissBlockingDialogs()
79+ Thread .sleep(2_000 )
80+ }
5181
82+ step(" Open Module Maker via Find Action" ) {
5283 val isMac = System .getProperty(" os.name" ).contains(" Mac" , ignoreCase = true )
53- keyboard {
54- if (isMac) {
55- hotKey(KeyEvent .VK_META , KeyEvent .VK_SHIFT , KeyEvent .VK_A )
84+
85+ // Retry the Find Action flow — on CI the first attempt may fail
86+ // if the IDE hasn't fully initialized its action system.
87+ waitFor(duration = Duration .ofSeconds(60 ), interval = Duration .ofSeconds(5 )) {
88+ // Click the IDE frame to ensure it has focus
89+ find<ComponentFixture >(
90+ byXpath(" //div[@class='IdeFrameImpl']" ),
91+ Duration .ofSeconds(10 )
92+ ).click()
93+ Thread .sleep(500 )
94+
95+ keyboard {
96+ if (isMac) {
97+ hotKey(KeyEvent .VK_META , KeyEvent .VK_SHIFT , KeyEvent .VK_A )
98+ } else {
99+ hotKey(KeyEvent .VK_CONTROL , KeyEvent .VK_SHIFT , KeyEvent .VK_A )
100+ }
101+ }
102+ Thread .sleep(2_000 )
103+
104+ // Check if Find Action popup appeared
105+ val searchField = findAll<ComponentFixture >(
106+ byXpath(" //div[@class='SearchEverywhereUI']" )
107+ )
108+ if (searchField.isEmpty()) {
109+ println (" Find Action popup not found, retrying..." )
110+ // Press Escape to clean up any partial state
111+ keyboard { hotKey(KeyEvent .VK_ESCAPE ) }
112+ Thread .sleep(1_000 )
113+ false
56114 } else {
57- hotKey(KeyEvent .VK_CONTROL , KeyEvent .VK_SHIFT , KeyEvent .VK_A )
115+ println (" Find Action popup appeared" )
116+ keyboard { enterText(" Module Maker" ) }
117+ Thread .sleep(1_000 )
118+ keyboard { hotKey(KeyEvent .VK_ENTER ) }
119+ true
58120 }
59121 }
60- Thread .sleep(1_000 )
61- keyboard { enterText(" Module Maker" ) }
62- Thread .sleep(500 )
63- keyboard { hotKey(KeyEvent .VK_ENTER ) }
64122 }
65123
66124 step(" Verify Module Maker dialog opened" ) {
67- waitFor(duration = Duration .ofSeconds(15 )) {
125+ waitFor(duration = Duration .ofSeconds(30 )) {
68126 findAll<ComponentFixture >(
69127 byXpath(" //div[@title='Module Maker']" )
70128 ).isNotEmpty()
@@ -283,6 +341,27 @@ class ModuleMakerUiTest {
283341 // Any "Continue" or "Skip" buttons
284342 findAll<ComponentFixture >(byXpath(" //div[@text='Continue']" )).firstOrNull()?.click()
285343 findAll<ComponentFixture >(byXpath(" //div[@text='Skip Remaining and Set Defaults']" )).firstOrNull()?.click()
344+
345+ // Catch-all: if a DialogWrapper dialog is blocking, find buttons and click
346+ // a safe one. Skip "Cancel"/"No"/"Exit" to avoid killing legitimate operations.
347+ val dialogButtons = findAll<JButtonFixture >(
348+ byXpath(" //div[@class='MyDialog']//div[@class='JButton']" )
349+ )
350+ for (btn in dialogButtons) {
351+ val btnText = try {
352+ btn.callJs<String >(" component.getText()" )?.trim() ? : " "
353+ } catch (_: Exception ) {
354+ " "
355+ }
356+ val lower = btnText.lowercase()
357+ if (lower in listOf (" cancel" , " no" , " exit" , " abort" , " stop" )) {
358+ println (" Skipping dangerous dialog button: '$btnText '" )
359+ continue
360+ }
361+ println (" Dismissing blocking dialog by clicking button: '$btnText '" )
362+ btn.click()
363+ break
364+ }
286365 }
287366
288367 private companion object {
0 commit comments