-
Notifications
You must be signed in to change notification settings - Fork 133
WIP: SWTBot: add additional target support for the Build & Flash test case. #1401
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
base: master
Are you sure you want to change the base?
Changes from all commits
8512c15
71c7fba
beefce2
ca23e99
5d5e0a0
6bd931b
cbf6d9a
5244f30
ca2a355
07f8d5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,115 +30,169 @@ | |
|
|
||
| /** | ||
| * Test class to test the Flash process | ||
| * | ||
| * | ||
| * @author Andrii Filippov | ||
| * | ||
| */ | ||
| @SuppressWarnings("restriction") | ||
| @RunWith(SWTBotJunit4ClassRunner.class) | ||
| @FixMethodOrder(MethodSorters.NAME_ASCENDING) | ||
|
|
||
| public class NewEspressifIDFProjectFlashProcessTest | ||
| { | ||
| public class NewEspressifIDFProjectFlashProcessTest { | ||
| @BeforeClass | ||
| public static void beforeTestClass() throws Exception | ||
| { | ||
| public static void beforeTestClass() throws Exception { | ||
| Fixture.loadEnv(); | ||
| } | ||
|
|
||
| @AfterClass | ||
| public static void tearDown() | ||
| { | ||
| public static void tearDown() { | ||
| Fixture.cleanupEnvironment(); | ||
| } | ||
|
|
||
| @Test | ||
| public void givenNewProjectCreatedBuiltWhenSelectSerialPortWhenFlashThenCheckFlashedSuccessfully() throws Exception | ||
| { | ||
| public void givenNewProjectCreatedBuiltWhenSelectSerialPortWhenFlashThenCheckFlashedSuccessfully() | ||
| throws Exception { | ||
| if (SystemUtils.IS_OS_LINUX) // temporary solution until new ESP boards arrive for Windows | ||
| { | ||
| Fixture.givenNewEspressifIDFProjectIsSelected("EspressIf", "Espressif IDF Project"); | ||
| Fixture.givenProjectNameIs("NewProjectFlashTest"); | ||
| Fixture.whenNewProjectIsSelected(); | ||
| Fixture.whenTurnOffOpenSerialMonitorAfterFlashingInLaunchConfig(); | ||
| Fixture.whenProjectIsBuiltUsingContextMenu(); | ||
| Fixture.whenSelectLaunchTargetSerialPort(); | ||
| Fixture.whenFlashProject(); | ||
| Fixture.thenVerifyFlashDoneSuccessfully(); | ||
| } | ||
| else | ||
| { | ||
| Fixture.whenBuildAndFlashForAllTargetsSequentially(); | ||
| Fixture.whenChangeLaunchTargetBackToESP32(); | ||
| } else { | ||
| assertTrue(true); | ||
| } | ||
| } | ||
|
|
||
| private static class Fixture | ||
| { | ||
| private static class Fixture { | ||
| private static SWTWorkbenchBot bot; | ||
| private static String category; | ||
| private static String subCategory; | ||
| private static String projectName; | ||
|
|
||
| private static void loadEnv() throws Exception | ||
| { | ||
| private static final TargetPort[] TARGETS = new TargetPort[] { | ||
| new TargetPort("esp32", "/dev/ttyUSB1 Dual RS232-HS"), | ||
| new TargetPort("esp32c61", "/dev/ttyUSB0 CP2102N USB to UART Bridge Controller"), | ||
| new TargetPort("esp32c5", "/dev/ttyUSB2 CP2102N USB to UART Bridge Controller"), | ||
| new TargetPort("esp32h2", "/dev/ttyUSB3 CP2102N USB to UART Bridge Controller"), | ||
| new TargetPort("esp32s2", "/dev/ttyUSB5 CP2102N USB to UART Bridge Controller"), | ||
| new TargetPort("esp32s3", "/dev/ttyUSB6 CP2102N USB to UART Bridge Controller"), | ||
| new TargetPort("esp32c3", "/dev/ttyUSB7 CP2102N USB to UART Bridge Controller") | ||
| }; | ||
|
|
||
| private static void loadEnv() throws Exception { | ||
| bot = WorkBenchSWTBot.getBot(); | ||
| EnvSetupOperations.setupEspressifEnv(bot); | ||
| bot.sleep(1000); | ||
| ProjectTestOperations.deleteAllProjects(bot); | ||
| } | ||
|
|
||
| private static void givenNewEspressifIDFProjectIsSelected(String category, String subCategory) | ||
| { | ||
| private static void givenNewEspressifIDFProjectIsSelected(String category, String subCategory) { | ||
| Fixture.category = category; | ||
| Fixture.subCategory = subCategory; | ||
| } | ||
|
|
||
| private static void givenProjectNameIs(String projectName) | ||
| { | ||
| private static void givenProjectNameIs(String projectName) { | ||
| Fixture.projectName = projectName; | ||
| } | ||
|
|
||
| private static void whenNewProjectIsSelected() throws Exception | ||
| { | ||
| private static void whenNewProjectIsSelected() throws Exception { | ||
| ProjectTestOperations.setupProject(projectName, category, subCategory, bot); | ||
| } | ||
|
|
||
| private static void whenProjectIsBuiltUsingContextMenu() throws IOException | ||
| { | ||
| private static void whenBuildAndFlashForAllTargetsSequentially() throws Exception { | ||
| for (int i = 0; i < TARGETS.length; i++) { | ||
| TargetPort tp = TARGETS[i]; | ||
|
|
||
| boolean skipTargetChangeDialog = (i == 0); | ||
| whenChangeLaunchTarget(tp.target, skipTargetChangeDialog); | ||
|
|
||
| whenProjectIsBuiltUsingContextMenu(); | ||
| whenSelectLaunchTargetSerialPort(tp.port); | ||
| whenFlashProject(); | ||
| thenVerifyFlashDoneSuccessfully(); | ||
|
|
||
| TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot); | ||
| bot.sleep(500); | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| private static void whenChangeLaunchTarget(String targetText, boolean skipDialogOnThisRun) throws Exception { | ||
| // skip first iteration since esp32 target was selected during Project Creation | ||
| if (!skipDialogOnThisRun) { | ||
| LaunchBarTargetSelector targetSelector = new LaunchBarTargetSelector(bot); | ||
| targetSelector.selectTarget(targetText); | ||
| TestWidgetWaitUtility.waitForDialogToAppear(bot, "IDF Launch Target Changed", 20000); | ||
| SWTBotShell shell = bot.shell("IDF Launch Target Changed"); | ||
| shell.setFocus(); | ||
| bot.button("Yes").click(); | ||
| } | ||
|
|
||
| TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot); | ||
| } | ||
|
|
||
| private static void whenChangeLaunchTargetBackToESP32() throws Exception { | ||
| LaunchBarTargetSelector targetSelector = new LaunchBarTargetSelector(bot); | ||
| targetSelector.selectTarget("esp32"); | ||
| TestWidgetWaitUtility.waitForDialogToAppear(bot, "IDF Launch Target Changed", 20000); | ||
| SWTBotShell shell = bot.shell("IDF Launch Target Changed"); | ||
| shell.setFocus(); | ||
| bot.button("Yes").click(); | ||
| TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot); | ||
| } | ||
|
|
||
| private static void whenProjectIsBuiltUsingContextMenu() throws IOException { | ||
| ProjectTestOperations.buildProjectUsingContextMenu(projectName, bot); | ||
| ProjectTestOperations.waitForProjectBuild(bot); | ||
| TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot); | ||
| } | ||
|
|
||
| private static void whenSelectLaunchTargetSerialPort() throws Exception | ||
| { | ||
| private static void whenSelectLaunchTargetSerialPort(String portPrefixOrExact) throws Exception { | ||
| LaunchBarTargetSelector targetSelector = new LaunchBarTargetSelector(bot); | ||
| targetSelector.clickEdit(); | ||
|
|
||
| TestWidgetWaitUtility.waitForDialogToAppear(bot, "New ESP Target", 20000); | ||
| SWTBotShell shell = bot.shell("New ESP Target"); | ||
| bot.comboBoxWithLabel("Serial Port:").setSelection("/dev/ttyUSB1 Dual RS232-HS"); | ||
| try { | ||
| bot.comboBoxWithLabel("Serial Port:").setSelection(portPrefixOrExact); | ||
| } catch (Exception ignored) { | ||
| String[] items = bot.comboBoxWithLabel("Serial Port:").items(); | ||
| String match = null; | ||
|
|
||
| for (String item : items) { | ||
| if (item != null && item.startsWith(portPrefixOrExact)) { | ||
| match = item; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (match == null) { | ||
| throw new AssertionError("No serial port matched: " + portPrefixOrExact + " ; available=" | ||
| + String.join(", ", items)); | ||
| } | ||
|
|
||
| bot.comboBoxWithLabel("Serial Port:").setSelection(match); | ||
| } | ||
|
|
||
|
Comment on lines
+150
to
+176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Identify which exception type setSelection throws when the item is absent,
# to help narrow the catch clause.
rg -nP 'setSelection\s*\(' -C2 --type=java | head -80
rg -nP 'class\s+SWTBotCombo\b' -C3Repository: espressif/idf-eclipse-plugin Length of output: 11266 🌐 Web query:
💡 Result: The exceptions WidgetNotFoundException and IllegalArgumentException when using SWTBot's setSelection (likely on SWTBotTree or SWTBotTable) typically occur due to timing, focus, or incorrect widget targeting issues. WidgetNotFoundException causes: - Widget not yet loaded or disposed: Common in trees when trying to access child nodes without expanding parent first (e.g., bot.tree.getTreeItem("Parent").getNode("Child").select fails; expand first: item.expand). - Wrong widget index: Multiple trees/tables present; use bot.tree(1) or bot.table(0) instead of bot.tree. - Timing/race conditions: Widget appears/disappears intermittently. Increase timeouts with -Dorg.eclipse.swtbot.playback.poll.delay=500 -Dorg.eclipse.swtbot.playback.delay=400, or use bot.sleep / waitUntil conditions. - Focus loss: Especially in debugger or headless (Xvfb); force shell activation: bot.activeShell.setFocus or UIThreadRunnable.syncExec to forceActive. - Linux-specific focus issues: Use Xephyr for tests. IllegalArgumentException causes: - Invalid index or argument to setSelection (e.g., out-of-bounds row/column index). - Underlying SWT widget state invalid (e.g., disposed, wrong thread access). - For trees: Path not fully expanded before selection. - Launch config issues: Missing SWTBot plugins or classloader problems in Eclipse tests. Solutions: 1. Ensure proper expansion: SWTBotTreeItem item = bot.tree.expandNode("Parent", "Child"); item.select; 2. Wait for widgets: bot.waitUntil(Conditions.shellIsActive("Title")); bot.waitUntil(new DefaultCondition { test { return bot.tree.getItems.length > 0; } }); 3. Use correct indices: Inspect with Eclipse Spy or print bot.widgets(WidgetOfType.widgetOfType(Tree.class)). 4. Activate contexts: bot.tabItem("Tab").activate; bot.tree(1).select(0); 5. JVM args for timing: As above. 6. For tables: Ensure column count matches; bot.table.select(rowIndex); Official docs confirm setSelection throws WidgetNotFoundException if widget null/disposed, and operations fail if not enabled/found. Citations:
🌐 Web query:
💡 Result: The SWTBotCombo class in Eclipse SWTBot provides the setSelection(String text) method to set the combo box selection to the specified text. public void setSelection(String text) Set the selection to the specified text. Parameters: text - the text to set into the combo. This is documented in the official SWTBot API documentation. Usage example from tests and tutorials: SWTBotCombo combo = bot.comboBox; // or bot.comboBoxWithLabel("Label"); combo.setSelection("Option Text"); There is also typically a setSelection(int index) method inherited or available for index-based selection, and setText(String text) for editable combos, as seen in recorder tests: bot.comboBox.setText("value"); The API is stable across versions, with the primary method being setSelection(String text) for text matching. Citations:
🌐 Web query:
💡 Result: The source code for SWTBotCombo.setSelection in Eclipse SWTBot is located in the official GitHub repository at https://github.com/eclipse-swtbot/org.eclipse.swtbot. SWTBotCombo is a widget class in org.eclipse.swtbot.swt.finder.widgets package that wraps SWT Combo or CCombo controls. The setSelection method typically delegates to the underlying SWT widget's setSelection by index or text, using SWTBot's standard pattern of UIThreadRunnable.syncExec for thread-safe execution. SWTBot repositories have moved from git.eclipse.org cgit to GitHub (as noted in multiple sources). To view the exact implementation: 1. Navigate to https://github.com/eclipse-swtbot/org.eclipse.swtbot 2. Search for SWTBotCombo.java in the swt.finder module (likely examples/swtbot-eclipse/ or plugins/org.eclipse.swtbot.swt.finder/src/org/eclipse/swtbot/swt/finder/widgets/) 3. Look for public void setSelection(int index) or setSelection(String text) methods. Related evidence from Eclipse git mirrors: - Tests use bot.comboBox.setText("kikoo") for Combo interaction (source 1 from first search). - SWTBot generator rules include ComboSelectionRule and CComboSelectionRule, indicating SWTBotCombo likely handles both Combo and CCombo selection (source 9 from second search). - SWT CCombo has setSelection(Point selection) on its text field (source 2). No exact code snippet found in search highlights, but the GitHub repo is the authoritative up-to-date source per Eclipse migration notices (sources 6,7 across searches). Citations:
Narrow the caught exception type to avoid masking real widget failures. The broad Consider either:
|
||
| TestWidgetWaitUtility.waitForOperationsInProgressToFinishSync(bot); | ||
| shell.setFocus(); | ||
| bot.button("Finish").click(); | ||
| } | ||
|
|
||
| private static void whenTurnOffOpenSerialMonitorAfterFlashingInLaunchConfig() throws Exception | ||
| { | ||
| private static void whenTurnOffOpenSerialMonitorAfterFlashingInLaunchConfig() throws Exception { | ||
| LaunchBarConfigSelector configSelector = new LaunchBarConfigSelector(bot); | ||
| configSelector.clickEdit(); | ||
| TestWidgetWaitUtility.waitForDialogToAppear(bot, "Edit Configuration", 20000); | ||
| bot.cTabItem("Main").show(); | ||
| bot.cTabItem("Main").setFocus(); | ||
| SWTBotCheckBox checkBox = bot.checkBox("Open Serial Monitor After Flashing"); | ||
| if (checkBox.isChecked()) | ||
| { | ||
| if (checkBox.isChecked()) { | ||
| checkBox.click(); | ||
| } | ||
| bot.button("OK").click(); | ||
| } | ||
|
|
||
| private static void whenFlashProject() throws IOException | ||
| { | ||
| private static void whenFlashProject() throws IOException { | ||
| ProjectTestOperations.launchCommandUsingContextMenu(projectName, bot, "Run Configurations..."); | ||
| TestWidgetWaitUtility.waitForDialogToAppear(bot, "Run Configurations", 10000); | ||
| bot.tree().getTreeItem("ESP-IDF Application").select(); | ||
|
|
@@ -148,16 +202,24 @@ private static void whenFlashProject() throws IOException | |
| bot.button("Run").click(); | ||
| } | ||
|
|
||
| private static void thenVerifyFlashDoneSuccessfully() throws Exception | ||
| { | ||
| private static void thenVerifyFlashDoneSuccessfully() throws Exception { | ||
| ProjectTestOperations.waitForProjectFlash(bot); | ||
| } | ||
|
|
||
| static void cleanupEnvironment() | ||
| { | ||
| static void cleanupEnvironment() { | ||
| TestWidgetWaitUtility.waitForOperationsInProgressToFinishAsync(bot); | ||
| ProjectTestOperations.closeAllProjects(bot); | ||
| ProjectTestOperations.deleteAllProjects(bot); | ||
| } | ||
|
|
||
| private static class TargetPort { | ||
| final String target; | ||
| final String port; | ||
|
|
||
| TargetPort(String target, String port) { | ||
| this.target = target; | ||
| this.port = port; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded ports/descriptors make this test brittle and environment-specific.
The
TARGETSarray pins each target to an exact/dev/ttyUSBNdevice path and a specific USB-UART chip description (e.g.Dual RS232-HS,CP2102N USB to UART Bridge Controller). This assumes:ttyUSBNin the order devices are probed, which is not stable across reboots, replugging, or hub changes).If any device re-enumerates, the test will silently pick the wrong board and flash it, or fall back to the
startsWithmatch on line 164 and still flash the wrong target. At minimum, consider:/dev/esp32s3) pinned by USB serial number rather thanttyUSBN.🤖 Prompt for AI Agents