Skip to content

WIP: SWTBot test case: Serial Monitor verification#1297

Closed
AndriiFilippov wants to merge 1 commit into
masterfrom
IEP-1624
Closed

WIP: SWTBot test case: Serial Monitor verification#1297
AndriiFilippov wants to merge 1 commit into
masterfrom
IEP-1624

Conversation

@AndriiFilippov

@AndriiFilippov AndriiFilippov commented Aug 27, 2025

Copy link
Copy Markdown
Collaborator

Description

SWTBot Serial Monitor test cases

Fixes # (IEP-1624)

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

Test Configuration:

  • ESP-IDF Version:
  • OS (Windows,Linux and macOS):

Dependent components impacted by this PR:

  • Component 1
  • Component 2

Checklist

  • PR Self Reviewed
  • Applied Code formatting
  • Added Documentation
  • Added Unit Test
  • Verified on all platforms - Windows,Linux and macOS

Summary by CodeRabbit

  • Tests
    • Added end-to-end UI test for the Serial Monitor workflow on newly created projects (create, build, flash, verify output).
    • Enhanced test utilities to improve terminal/console handling, flash completion detection, and text-wait conditions.
    • Introduced a dedicated flash wait timeout in Linux test configurations to improve stability and timing.
    • Improved synchronization and reliability across UI-driven test flows.

@coderabbitai

coderabbitai Bot commented Aug 27, 2025

Copy link
Copy Markdown

Walkthrough

Adds a Linux test config flash timeout, introduces a new SWTBot UI test for Serial Monitor flow, extends ProjectTestOperations with terminal/flash wait helpers, and adds a text-contains wait utility for terminal content scanning.

Changes

Cohort / File(s) Summary
Test configuration
tests/com.espressif.idf.ui.test/configs/default-test-linux.properties
Adds property default.project.flash.wait=60000.
Test wait utilities
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/common/utility/TestWidgetWaitUtility.java
Adds waitUntilTextContains(...) to wait for case-insensitive text in Terminal view; minor whitespace tweak.
Project operations (helpers)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java
Adds waitForProjectMonitorAndDisconnect, findTextInSerialMonitorOutput, viewTerminal, waitProjectFlash; enhances viewConsole to select console via dropdown.
Executable UI test
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectSerialMonitorTest.java
New SWTBot JUnit test covering create → build → flash → serial monitor verification flow, with setup/teardown and dialog handling.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Tester
  participant SWTBot as SWTBot Runner
  participant IDE as Eclipse IDE
  participant Ops as ProjectTestOperations
  participant Util as TestWidgetWaitUtility
  participant Console as Console View
  participant Terminal as Terminal View

  Tester->>SWTBot: Run NewEspressifIDFProjectSerialMonitorTest
  SWTBot->>IDE: Create new ESP-IDF project
  SWTBot->>IDE: Build project via context menu
  Ops->>Console: viewConsole("Build Console")
  Ops->>Console: Wait for build completion

  SWTBot->>IDE: Open Run Configurations and Launch Flash
  Ops->>Console: viewConsole("ESP-IDF Console")
  Ops->>Console: waitProjectFlash (wait for "Hard resetting via RTS pin...")

  Ops->>Terminal: viewTerminal("Serial", timeout)
  Util->>Terminal: waitUntilTextContains("Hello", timeout)
  Ops->>Terminal: Disconnect terminal
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • kolipakakondal
  • alirana01

Poem

I built, I flashed—ears all a-quiver,
Watching the console’s texty river.
A “Hello” hops across the screen,
Terminal whispers, bright and clean.
Timeouts set, the waits align—
Carrots for logs; results divine. 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch IEP-1624

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@AndriiFilippov AndriiFilippov changed the title SWTBot test case: Serial Monitor verification WIP: SWTBot test case: Serial Monitor verification Aug 27, 2025
public boolean test() throws Exception {

String terminalText = terminalView.bot().canvas().getText();

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@kolipakakondal @alirana01 hi guys !

I need your advice. I'm writing a test for the Serial Monitor but can't extract text from the Terminal view.
Using SWT Inspector, I found that the terminal content is a textCanvas , not text() or styledText() , so it returns an empty string.
Since Canvas has no methods to get the content, I’m not sure how to proceed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (5)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java (3)

104-111: Guard disconnect action to avoid flaky failures

Clicking “Disconnect Terminal Connection” without checking connection state can throw if the toolbar button isn’t present/enabled. Add a presence/enablement check or catch WidgetNotFoundException.

- SWTBotView terminalView = viewTerminal("COM5", bot, 30000);
- terminalView.toolbarPushButton("Disconnect Terminal Connection").click();
+ SWTBotView terminalView = viewTerminal("COM5", bot, 30000);
+ try {
+   terminalView.toolbarPushButton("Disconnect Terminal Connection").click();
+ } catch (WidgetNotFoundException e) {
+   // Already disconnected or control not available; proceed
+ }

113-121: Make searched serial text configurable

Hard-coding "Hello" couples the helper to a specific example. Accept a parameter or read from a property (e.g., default.serial.monitor.text) to reuse across tests and targets.

- public static void findTextInSerialMonitorOutput(SWTWorkbenchBot bot) throws IOException
+ public static void findTextInSerialMonitorOutput(SWTWorkbenchBot bot) throws IOException
   {
     bot.sleep(5000);
     SWTBotView terminalView = viewTerminal("<Closed> COM5", bot, 30000);
     terminalView.show();
     terminalView.setFocus();
-    TestWidgetWaitUtility.waitUntilTextContains(bot, "Hello", terminalView,
+    String expected = DefaultPropertyFetcher.getStringPropertyValue("default.serial.monitor.text", "Hello");
+    TestWidgetWaitUtility.waitUntilTextContains(bot, expected, terminalView,
         DefaultPropertyFetcher.getLongPropertyValue(DEFAULT_FLASH_WAIT_PROPERTY, 20000));
   }

Note: add the DefaultPropertyFetcher import.


135-141: Unused parameters in viewTerminal

terminalType and timeOut are unused; either remove them or implement filtering/selection by terminal session title.

- public static SWTBotView viewTerminal(String terminalType, SWTWorkbenchBot bot, long timeOut)
+ public static SWTBotView viewTerminal(String terminalType, SWTWorkbenchBot bot, long timeOut)
   {
     SWTBotView view = bot.viewByPartName("Terminal");
     view.show();
     view.setFocus();
     return view;
   }

If keeping the signature, consider using terminalType to activate a specific CTab within the Terminal view.

tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectSerialMonitorTest.java (2)

111-111: Avoid hard-coded project name; use the variable set earlier

Prevents divergence if Fixture.givenProjectNameIs changes.

- prefrencesShell.bot().tree().getTreeItem("ESP-IDF Application").getNode("NewProjectSerialMonitorTest").select();
+ prefrencesShell.bot().tree().getTreeItem("ESP-IDF Application").getNode(projectName).select();

126-130: Order is okay, but consider verifying monitor readiness before disconnect

You disconnect then read text from a closed session. Usually fine, but add a short wait/assert that the terminal view has content before disconnect to reduce flakiness.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 023a056 and 009bef8.

📒 Files selected for processing (4)
  • tests/com.espressif.idf.ui.test/configs/default-test-linux.properties (1 hunks)
  • tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/common/utility/TestWidgetWaitUtility.java (2 hunks)
  • tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectSerialMonitorTest.java (1 hunks)
  • tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectSerialMonitorTest.java (4)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/common/WorkBenchSWTBot.java (1)
  • WorkBenchSWTBot (14-28)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/EnvSetupOperations.java (1)
  • EnvSetupOperations (12-85)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java (1)
  • ProjectTestOperations (51-803)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/common/utility/TestWidgetWaitUtility.java (1)
  • SuppressWarnings (31-325)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java (1)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/common/configs/DefaultPropertyFetcher.java (1)
  • DefaultPropertyFetcher (20-90)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build_windows
  • GitHub Check: build
  • GitHub Check: build_macos
🔇 Additional comments (1)
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java (1)

143-149: Flash wait relies on the wrong key (after fix above this will honor 60s Linux default)

Once DEFAULT_FLASH_WAIT_PROPERTY is corrected, this will stop waiting for hours and honor default.project.flash.wait=60000.

Comment on lines +144 to +159
public static void waitUntilTextContains(SWTWorkbenchBot bot, String text, SWTBotView terminalView, long timeOut) {
terminalView.bot().waitUntil(new DefaultCondition() {
@Override
public boolean test() throws Exception {

String terminalText = terminalView.bot().canvas().getText();

return terminalText.toLowerCase().contains(text.toLowerCase());
}

@Override
public String getFailureMessage() {
return "Text not found in terminal!";
}
}, timeOut, 3000); // Wait for up to 'timeOut' milliseconds
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Terminal text read uses Canvas.getText() (nonexistent) — switch to StyledText

SWT Canvas doesn’t expose text. This will fail at runtime/compile-time depending on bindings. Use styledText like elsewhere and ensure the view is visible/focused before reading.

- public static void waitUntilTextContains(SWTWorkbenchBot bot, String text, SWTBotView terminalView, long timeOut) {
-     terminalView.bot().waitUntil(new DefaultCondition() {
+ public static void waitUntilTextContains(SWTWorkbenchBot bot, String text, SWTBotView terminalView, long timeOut) {
+     terminalView.bot().waitUntil(new DefaultCondition() {
          @Override
          public boolean test() throws Exception {
-             
-             String terminalText = terminalView.bot().canvas().getText();
-             
-             return terminalText.toLowerCase().contains(text.toLowerCase());
+             terminalView.show();
+             terminalView.setFocus();
+             String terminalText = terminalView.bot().styledText().getText();
+             return terminalText.toLowerCase().contains(text.toLowerCase());
          }
 
          @Override
          public String getFailureMessage() {
              return "Text not found in terminal!";
          }
-     }, timeOut, 3000);  // Wait for up to 'timeOut' milliseconds
+     }, timeOut, 3000);
  }

Optional: de-duplicate with waitUntilViewContains by reusing it for terminal checks.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static void waitUntilTextContains(SWTWorkbenchBot bot, String text, SWTBotView terminalView, long timeOut) {
terminalView.bot().waitUntil(new DefaultCondition() {
@Override
public boolean test() throws Exception {
String terminalText = terminalView.bot().canvas().getText();
return terminalText.toLowerCase().contains(text.toLowerCase());
}
@Override
public String getFailureMessage() {
return "Text not found in terminal!";
}
}, timeOut, 3000); // Wait for up to 'timeOut' milliseconds
}
public static void waitUntilTextContains(SWTWorkbenchBot bot, String text, SWTBotView terminalView, long timeOut) {
terminalView.bot().waitUntil(new DefaultCondition() {
@Override
public boolean test() throws Exception {
terminalView.show();
terminalView.setFocus();
String terminalText = terminalView.bot().styledText().getText();
return terminalText.toLowerCase().contains(text.toLowerCase());
}
@Override
public String getFailureMessage() {
return "Text not found in terminal!";
}
}, timeOut, 3000);
}
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/common/utility/TestWidgetWaitUtility.java
around lines 144 to 159, the method reads terminal text via
terminalView.bot().canvas().getText() which is invalid; replace that with
retrieving the StyledText widget (e.g. find the StyledText in the view's bot or
use terminalView.bot().styledText().getText()), ensure the terminal view is
visible/focused before reading (call terminalView.show() /
terminalView.setFocus() or use waitUntil on view visibility), and optionally
call the existing waitUntilViewContains helper to avoid duplication by
delegating terminal checks to it.

public void givenNewProjectCreatedBuiltWhenFlashProjectThenCheckSerialMonitorOutput()
throws Exception
{
Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Typo breaks project template selection (“EspressIf” → “Espressif”)

Category is case-sensitive in the UI. This will fail to locate the wizard node.

- Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project");
+ Fixture.givenNewEspressifIDFProjectIsSelected("Espressif", "Espressif IDF Project");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project");
Fixture.givenNewEspressifIDFProjectIsSelected("Espressif", "Espressif IDF Project");
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/executable/cases/project/NewEspressifIDFProjectSerialMonitorTest.java
around line 57, the fixture call uses the wrong-cased category string
"EspressIf" causing the UI wizard node lookup to fail; replace the string with
the correct, case-sensitive "Espressif" so the template/category matches the UI
exactly and the wizard node can be located.

Comment on lines +116 to +124
private static void whenSelectSerialPort() throws IOException
{
TestWidgetWaitUtility.waitForDialogToAppear(bot, "Serial port not found", 30000);
bot.button("OK").click();
TestWidgetWaitUtility.waitForDialogToAppear(bot, "New ESP Target", 20000);
bot.comboBoxWithLabel("Serial Port:").setSelection("COM5 USB Serial Port (COM5)");
TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot);
bot.button("Finish").click();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Port selection is Windows-specific (“COM5”); make it portable or property-driven

Linux/macOS won’t have COM5. Read a property and fallback to the first item to keep CI portable.

- bot.comboBoxWithLabel("Serial Port:").setSelection("COM5 USB Serial Port (COM5)");
+ String preferredPort = DefaultPropertyFetcher.getStringPropertyValue("default.serial.port.label", "");
+ if (preferredPort != null && !preferredPort.isEmpty()) {
+     bot.comboBoxWithLabel("Serial Port:").setSelection(preferredPort);
+ } else {
+     bot.comboBoxWithLabel("Serial Port:").setSelection(0); // fallback: first available
+ }

Add missing import at the top of this file:

import com.espressif.idf.ui.test.common.configs.DefaultPropertyFetcher;


private static final String DEFAULT_PROJECT_BUILD_WAIT_PROPERTY = "default.project.build.wait";

private static final String DEFAULT_FLASH_WAIT_PROPERTY = "default.project.build.wait";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Wrong property key for flash timeout (causes hours-long waits)

DEFAULT_FLASH_WAIT_PROPERTY points to the build-wait key. This makes flash waits use 90,800,000 ms from the Linux config.

- private static final String DEFAULT_FLASH_WAIT_PROPERTY = "default.project.build.wait";
+ private static final String DEFAULT_FLASH_WAIT_PROPERTY = "default.project.flash.wait";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static final String DEFAULT_FLASH_WAIT_PROPERTY = "default.project.build.wait";
private static final String DEFAULT_FLASH_WAIT_PROPERTY = "default.project.flash.wait";
🤖 Prompt for AI Agents
In
tests/com.espressif.idf.ui.test/src/com/espressif/idf/ui/test/operations/ProjectTestOperations.java
around line 56, the constant DEFAULT_FLASH_WAIT_PROPERTY is set to the
build-wait key causing flash operations to pick up the wrong (very large)
timeout; change the string value from "default.project.build.wait" to the
correct flash timeout key (e.g. "default.project.flash.wait"), update any
references if needed, and run the tests to confirm flash waits now use the
intended timeout.

@AndriiFilippov AndriiFilippov self-assigned this Aug 27, 2025
@AndriiFilippov AndriiFilippov deleted the IEP-1624 branch November 27, 2025 09:53
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.

1 participant