Skip to content

Conversation

@claude
Copy link

@claude claude bot commented Jan 8, 2026

Summary

  • Fixed RiderUiTest.run() timeout failure caused by insufficient wait time for IDE frame to appear
  • Replaced fixed Thread.sleep() delays with condition-based waitFor() calls
  • Extended IDE frame search timeout from 60s to 2 minutes

Root Cause Analysis

The test was failing with WaitForConditionTimeoutException: Failed to find 'Idea frame' by 'IdeFrameImpl type' in 60s.

Analysis of CI artifacts revealed:

  • Screenshot & Video: Rider remained on the "New Solution" dialog throughout the test
  • UI Hierarchy: Only FlatWelcomeFrame with MyDialog present, no IdeFrameImpl
  • Issue: After clicking "Create", the project was never created and IDE never opened

The test used Thread.sleep(5000) after clicking Create, which is insufficient for:

  1. .NET SDK installation (if required)
  2. Project template generation
  3. Solution file creation
  4. IDE initialization with the new project

Changes

1. Extended IDE Frame Wait Timeout

// Before: 60 second timeout (hardcoded)
idea { ... }

// After: 2 minute timeout (configurable)
idea(Duration.ofMinutes(2)) { ... }

Modified IdeaFrame.kt to accept optional timeout parameter in idea() function.

2. Replaced Fixed Delays with Condition-Based Waiting

// Before: Fixed 10-second wait after clicking Install
installButton.click()
Thread.sleep(10000)

// After: Wait for Create button to become enabled (up to 60s)
installButton.click()
waitFor(Duration.ofSeconds(60), Duration.ofSeconds(1)) {
  button("Create").isShowing && button("Create").isEnabled()
}
// Before: Fixed 2-second wait before clicking Create
Thread.sleep(2000)
button("Create").click()

// After: Wait for Create button to be ready (up to 30s)
val createButton = button("Create")
waitFor(Duration.ofSeconds(30), Duration.ofSeconds(1)) {
  createButton.isShowing && createButton.isEnabled()
}
createButton.click()

Test Plan

  • ✅ Compilation verified: ./gradlew compileKotlin compileTestKotlin passes
  • 🔄 Recommended: Run ./gradlew :tests:ui-rd-tests:testUi to verify fix (requires Rider environment)

Best Practices Followed

As noted in the task instructions:

Cause-Effect Over Timeouts: UI tests should wait for specific conditions rather than arbitrary timeouts.

  • ✅ GOOD: Wait for a button to become visible or enabled before clicking it
  • ❌ BAD: Use Thread.sleep() or fixed delays

This change makes the test:

  • More robust: Adapts to varying system speeds (especially in CI)
  • More deterministic: Based on observable UI state changes
  • Clearer intent: Explicitly shows what we're waiting for

References

  • Test failure report: tests/ui-rd-tests/build/reports/tests/testUi/classes/RiderUiTest.html
  • Detailed analysis: build/reports/ai-analysis.txt
  • CI screen recording and UI hierarchy files were analyzed to identify the issue

🤖 Generated with Claude Code

…sed waiting

The RiderUiTest was failing because it couldn't find the IdeFrameImpl within
60 seconds. Analysis of the CI screen recording and UI hierarchy revealed that
after clicking "Create" in the New Solution dialog, the IDE frame never
appeared - the dialog remained open throughout the test execution.

Root cause:
- Test used Thread.sleep(5000) after clicking Create button
- This fixed delay is insufficient for:
  * .NET SDK installation (if needed)
  * Project template generation and solution file creation
  * IDE initialization with the new project

Changes:
1. Extended IDE frame wait timeout from 60s to 2 minutes
   - Added timeout parameter to idea() function in IdeaFrame.kt
   - Updated test to use idea(Duration.ofMinutes(2)) { }

2. Replaced Thread.sleep() calls with condition-based waitFor() in startNewProject()
   - Wait for Create button to be enabled after SDK installation (up to 60s)
   - Wait for Create button to be showing and enabled before clicking (up to 30s)
   - This follows UI test best practices: wait for specific conditions rather than arbitrary timeouts

These changes make the test more robust and deterministic by waiting for
observable UI state changes instead of assuming fixed durations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@claude
Copy link
Author

claude bot commented Jan 8, 2026

Code Review

Critical Issues

RiderUiTest.kt:60,87 - Inconsistent timing approach: PR removes Thread.sleep() after keyboard input in project creation (lines 134-142, 149-154) but leaves identical Thread.sleep(1000) calls after keyboard input in test methods. Either all delays should be condition-based or there's a reason these specific ones need fixed delays - clarify which.

RiderUiTest.kt:136-141 - Exception handling masks failures: The try-catch block silently converts any button interaction failure to false. If the button exists but throws for another reason (e.g., component disposed), the test will wait 60s then proceed anyway. Check exception type or log it.

RiderUiTest.kt:135 - Inefficient polling: The code repeatedly calls button("Create") every second for up to 60 seconds, triggering component searches. Consider caching the button reference outside the loop if the framework allows it.

Minor Issues

IdeaFrame.kt:22 - Parameter name could be clearer: timeout doesn't indicate it's specifically for finding the IDE frame. Consider frameFindTimeout or document that this is the find timeout, not an operation timeout.

RiderUiTest.kt:43 - 2-minute timeout may be excessive: While CI environments are slower, 120s is very generous. Consider if this masks underlying issues with project creation. Document why this specific duration was chosen.

Positive

  • Proper use of condition-based waiting over fixed sleeps
  • Backward-compatible API change to IdeaFrame.idea()
  • Detailed PR description with root cause analysis

Thread.sleep(10000)
// Wait for SDK installation to complete by checking when Create button becomes enabled
waitFor(Duration.ofSeconds(60), Duration.ofSeconds(1)) {
try {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching all exceptions hides real errors. If button("Create") throws for reasons other than "not found" (e.g., component disposed, RPC failure), test continues silently. Consider catching specific exception type or logging.

// Wait for SDK installation to complete by checking when Create button becomes enabled
waitFor(Duration.ofSeconds(60), Duration.ofSeconds(1)) {
try {
val createBtn = button("Create")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling button("Create") inside waitFor repeats the component search every second for 60 seconds. More efficient to find the button reference once outside the loop if possible.

@AlexPl292 AlexPl292 closed this Jan 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants