Skip to content
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

Improve UI test coverage #2048

Merged
merged 13 commits into from
Mar 4, 2025
Merged

Improve UI test coverage #2048

merged 13 commits into from
Mar 4, 2025

Conversation

jo-elimu
Copy link
Member

@jo-elimu jo-elimu commented Mar 3, 2025

Issue Number

Purpose

  • Reduce time gap between bug introduction and bug discovery.

Technical Details

Testing Instructions

  • mvn verify -P regression-test-ui
[INFO] Results:
[INFO]
[WARNING] Tests run: 19, Failures: 0, Errors: 0, Skipped: 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:51 min

Screenshots


Format Checks

Note

Files in PRs are automatically checked for format violations with mvn spotless:check.

If this PR contains files with format violations, run mvn spotless:apply to fix them.

@jo-elimu jo-elimu self-assigned this Mar 3, 2025
@jo-elimu jo-elimu linked an issue Mar 3, 2025 that may be closed by this pull request
10 tasks
@jo-elimu jo-elimu changed the title test: ui tests - letters Improve UI test coverage Mar 3, 2025
Copy link

codecov bot commented Mar 3, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 14.53%. Comparing base (f88b290) to head (e9adba8).
Report is 11 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #2048   +/-   ##
=========================================
  Coverage     14.53%   14.53%           
  Complexity      418      418           
=========================================
  Files           256      256           
  Lines          7154     7154           
  Branches        796      796           
=========================================
  Hits           1040     1040           
  Misses         6064     6064           
  Partials         50       50           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jo-elimu jo-elimu marked this pull request as ready for review March 3, 2025 15:36
@jo-elimu jo-elimu requested a review from a team as a code owner March 3, 2025 15:36
@jo-elimu jo-elimu requested review from vrudas, eymaal and alexander-kuruvilla and removed request for a team March 3, 2025 15:36
Copy link
Contributor

coderabbitai bot commented Mar 3, 2025

Warning

Rate limit exceeded

@jo-elimu has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 15 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4552535 and e9adba8.

📒 Files selected for processing (7)
  • src/main/webapp/WEB-INF/jsp/content/emoji/list.jsp (2 hunks)
  • src/main/webapp/WEB-INF/jsp/content/main.jsp (6 hunks)
  • src/test/java/selenium/content/MainContentPage.java (1 hunks)
  • src/test/java/selenium/content/emoji/EmojiCreatePage.java (1 hunks)
  • src/test/java/selenium/content/emoji/EmojiEditPage.java (1 hunks)
  • src/test/java/selenium/content/emoji/EmojiListPage.java (1 hunks)
  • src/test/java/selenium/content/emoji/EmojiTest.java (1 hunks)

Walkthrough

The changes update the Maven dependency version for the ai.elimu:webapp artifact from 2.5.32-SNAPSHOT to 2.5.34-SNAPSHOT. Several JSP files are modified to add id and class attributes to <a> elements, enhancing element targeting. Additionally, new Selenium page object classes and corresponding test classes for letters, letter sounds, and numbers have been introduced, establishing a structured approach for UI testing and interaction.

Changes

File(s) Change Summary
pom-dependency-tree.txt Updated ai.elimu:webapp version from 2.5.32-SNAPSHOT to 2.5.34-SNAPSHOT.
.../WEB-INF/jsp/content/letter-sound/list.jsp, .../WEB-INF/jsp/content/letter/list.jsp, .../WEB-INF/jsp/content/main.jsp, .../WEB-INF/jsp/content/sound/list.jsp, .../WEB-INF/jsp/content/number/list.jsp, .../WEB-INF/jsp/content/word/list.jsp Added id and class attributes to <a> elements (e.g., id="createButton", class="editLink", id="letterListLink", etc.) without altering link functionality.
src/test/java/selenium/** Introduced new Selenium Page Object classes (MainContentPage, LetterCreatePage, LetterEditPage, LetterListPage, LetterSoundCreatePage, LetterSoundEditPage, LetterSoundListPage, SoundCreatePage, SoundEditPage, SoundListPage, NumberCreatePage, NumberEditPage, NumberListPage, WordCreatePage, WordEditPage, WordListPage) and test classes (LetterTest, LetterSoundTest, SoundTest, NumberTest, WordTest) to support UI testing of letter, letter sound, number, and word functionalities.

Sequence Diagram(s)

sequenceDiagram
    participant LT as LetterTest
    participant MC as MainContentPage
    participant LL as LetterListPage
    participant LE as LetterEditPage
    participant LC as LetterCreatePage
    LT->>MC: pressLetterListLink()
    MC->>LL: Load Letter List Page
    alt Edit existing letter
      LL->>LT: pressRandomLetter()
      LT->>LE: Load Letter Edit Page
    else Create new letter
      LL->>LT: pressCreateButton()
      LT->>LC: Load Letter Create Page
    end
Loading

Possibly related PRs

  • chore(deps): model 2.0.83 #2038: The changes in the main PR involve updating the version of the ai.elimu:webapp artifact, related to the retrieved PR that also updates the version of the same artifact.
  • test(selenium): word learning events #1856: The changes in the main PR involve adding an id attribute to an anchor element in a JSP file, related to the changes in the retrieved PR that also involve adding an id attribute to an anchor element in a different JSP file, specifically for the word learning events link.

Suggested reviewers

  • jpatel3
  • tomaszsmy
  • Souvik-Cyclic
  • AshishBagdane
  • nya-elimu

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (22)
src/test/java/selenium/content/sound/SoundEditPage.java (1)

1-15: Consider enhancing this page object with explicit waits and interaction methods.

The class follows the Page Object Model pattern, which is great for organizing Selenium tests. However, there are several improvements that could make this more robust:

  1. Add explicit waits to ensure the page is fully loaded before attempting to find elements
  2. Include methods for interacting with page elements (e.g., form fields, buttons)
  3. Add error handling for the findElement call
  4. Include JavaDoc comments to document the class purpose and methods

Here's a suggested improvement:

package selenium.content.sound;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import java.time.Duration;

+/**
+ * Page object representing the Sound Edit page.
+ * Provides methods to interact with elements on the page.
+ */
public class SoundEditPage {
    
    private WebDriver driver;
+    private WebDriverWait wait;

    public SoundEditPage(WebDriver driver) {
        this.driver = driver;
+        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));

-        driver.findElement(By.id("soundEditPage"));
+        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("soundEditPage")));
    }
+    
+    /**
+     * Example method: Saves the current sound
+     * @return SoundListPage The page displayed after saving
+     */
+    public SoundListPage saveSound() {
+        WebElement saveButton = wait.until(ExpectedConditions.elementToBeClickable(By.id("saveButton")));
+        saveButton.click();
+        return new SoundListPage(driver);
+    }
}
src/test/java/selenium/content/sound/SoundCreatePage.java (1)

1-15: Consider enhancing this page object with explicit waits and interaction methods.

Similar to the SoundEditPage, this class follows the Page Object Model pattern but could benefit from several improvements:

Here's a suggested improvement:

package selenium.content.sound;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import java.time.Duration;

+/**
+ * Page object representing the Sound Create page.
+ * Provides methods to interact with elements on the page.
+ */
public class SoundCreatePage {
    
    private WebDriver driver;
+    private WebDriverWait wait;

    public SoundCreatePage(WebDriver driver) {
        this.driver = driver;
+        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));

-        driver.findElement(By.id("soundCreatePage"));
+        wait.until(ExpectedConditions.presenceOfElementLocated(By.id("soundCreatePage")));
    }
+    
+    /**
+     * Example method: Fill in the sound value and save
+     * @param value The sound value to create
+     * @return SoundListPage The page displayed after creation
+     */
+    public SoundListPage createSound(String value) {
+        WebElement valueInput = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("value")));
+        valueInput.sendKeys(value);
+        
+        WebElement submitButton = wait.until(ExpectedConditions.elementToBeClickable(By.id("submitButton")));
+        submitButton.click();
+        return new SoundListPage(driver);
+    }
}
src/test/java/selenium/content/letter/LetterCreatePage.java (1)

1-15: Add error handling for page element verification.

The constructor attempts to find the page element without any error handling. If the element is not found, it will throw a NoSuchElementException, but this isn't handled or reported in a user-friendly way.

Here's a suggested improvement:

package selenium.content.letter;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import java.time.Duration;

public class LetterCreatePage {
    
    private WebDriver driver;
+    private WebDriverWait wait;

    public LetterCreatePage(WebDriver driver) {
        this.driver = driver;
+        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+        
+        try {
-        driver.findElement(By.id("letterCreatePage"));
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.id("letterCreatePage")));
+        } catch (TimeoutException | NoSuchElementException e) {
+            throw new RuntimeException("Failed to load Letter Create page. Page element 'letterCreatePage' not found.", e);
+        }
    }
+    
+    /**
+     * Example method: Fills the letter text field
+     * @param text The letter text to enter
+     * @return this page object for method chaining
+     */
+    public LetterCreatePage enterLetterText(String text) {
+        try {
+            wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("text")))
+                .sendKeys(text);
+            return this;
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to enter text in letter field", e);
+        }
+    }
+    
+    /**
+     * Example method: Submits the letter creation form
+     * @return LetterListPage The page displayed after submission
+     */
+    public LetterListPage submit() {
+        try {
+            wait.until(ExpectedConditions.elementToBeClickable(By.id("submitButton")))
+                .click();
+            return new LetterListPage(driver);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to submit letter creation form", e);
+        }
+    }
}
src/test/java/selenium/content/letter_sound/LetterSoundEditPage.java (1)

1-15: Good page object implementation for Selenium testing.

This is a well-structured implementation of the Page Object Model (POM) pattern for Selenium testing. The constructor properly validates that the correct page is loaded by checking for the presence of a specific element.

However, there are a few enhancements that could be made:

  1. The class could benefit from having exception handling for the findElement call, which will throw NoSuchElementException if the element isn't found.
  2. Currently, the class doesn't provide any methods to interact with page elements.

Consider enhancing the class with methods to interact with the page and proper exception handling:

 public class LetterSoundEditPage {
     
     private WebDriver driver;
 
     public LetterSoundEditPage(WebDriver driver) {
         this.driver = driver;
 
-        driver.findElement(By.id("letterSoundEditPage"));
+        try {
+            driver.findElement(By.id("letterSoundEditPage"));
+        } catch (org.openqa.selenium.NoSuchElementException e) {
+            throw new IllegalStateException("This is not the Letter Sound Edit page", e);
+        }
     }
+    
+    // Example of methods that could be added for page interactions
+    public void submitForm() {
+        driver.findElement(By.id("submitButton")).click();
+    }
 }
src/test/java/selenium/content/letter_sound/LetterSoundCreatePage.java (1)

1-15: Good page object implementation for Selenium testing.

This is a well-structured implementation of the Page Object Model (POM) pattern for Selenium testing. The constructor properly validates that the correct page is loaded by checking for the presence of a specific element.

Similar to the LetterSoundEditPage, there are a few enhancements that could be made:

  1. The class could benefit from having exception handling for the findElement call, which will throw NoSuchElementException if the element isn't found.
  2. Currently, the class doesn't provide any methods to interact with page elements.

Consider enhancing the class with methods to interact with the page and proper exception handling:

 public class LetterSoundCreatePage {
     
     private WebDriver driver;
 
     public LetterSoundCreatePage(WebDriver driver) {
         this.driver = driver;
 
-        driver.findElement(By.id("letterSoundCreatePage"));
+        try {
+            driver.findElement(By.id("letterSoundCreatePage"));
+        } catch (org.openqa.selenium.NoSuchElementException e) {
+            throw new IllegalStateException("This is not the Letter Sound Create page", e);
+        }
     }
+    
+    // Example of methods that could be added for page interactions
+    public void fillLetterField(String letter) {
+        driver.findElement(By.id("letterField")).sendKeys(letter);
+    }
+    
+    public void fillSoundField(String sound) {
+        driver.findElement(By.id("soundField")).sendKeys(sound);
+    }
+    
+    public void submitForm() {
+        driver.findElement(By.id("submitButton")).click();
+    }
 }
src/main/webapp/WEB-INF/jsp/content/letter-sound/list.jsp (1)

84-84: Good addition of ID attribute for UI testing.

The addition of the id="createButton" attribute to the anchor element is a good practice for UI testing. This makes the element easily selectable in Selenium tests and supports the PR's objective of improving UI test coverage.

For consistency, consider also adding class attributes to other actionable elements in the table, such as the edit links.

For better test coverage, add class attributes to the edit links in the table:

 <td>
-    <a href="<spring:url value='/content/letter-sound/edit/${letterSound.id}' />"><span class="material-icons">edit</span></a>
+    <a class="editLink" href="<spring:url value='/content/letter-sound/edit/${letterSound.id}' />"><span class="material-icons">edit</span></a>
 </td>
src/test/java/selenium/content/sound/SoundTest.java (2)

59-59: Fix method name typo.

The method name has a typo in it ('Creat' instead of 'Create').

-public void testSoundCreatPage() {
+public void testSoundCreatePage() {

15-70: Consider extracting common test setup to a base class.

The setup/teardown code is duplicated across test classes (SoundTest, LetterSoundTest, and LetterTest). Consider extracting this common functionality to a base class to promote code reuse and maintainability.

Example of a base test class:

public abstract class BaseSeleniumTest {
    
    protected WebDriver driver;

    @BeforeEach
    public void setUp() { 
        log.info("setUp");

        ChromeOptions chromeOptions = new ChromeOptions();

        // Read "headless" property set on the command line
        String headlessSystemProperty = System.getProperty("headless");
        log.info("headlessSystemProperty: \"" + headlessSystemProperty + "\"");
        if ("true".equals(headlessSystemProperty)) {
            chromeOptions.addArguments("headless");
        }
        
        driver = new ChromeDriver(chromeOptions);
        driver.get(DomainHelper.getBaseUrl() + "/content");
    }

    @AfterEach
    public void tearDown() {
        log.info("tearDown");
        driver.quit();
    }
}

Then your test classes could extend this base class:

@Slf4j
public class SoundTest extends BaseSeleniumTest {
    // Test methods only
}
src/test/java/selenium/content/letter_sound/LetterSoundTest.java (1)

59-59: Fix method name typo.

The method name has a typo in it ('Creat' instead of 'Create').

-public void testLetterSoundCreatPage() {
+public void testLetterSoundCreatePage() {
src/test/java/selenium/content/letter/LetterTest.java (2)

59-59: Fix method name typo.

The method name has a typo in it ('Creat' instead of 'Create').

-public void testLetterCreatPage() {
+public void testLetterCreatePage() {

15-70: Consider adding exception handling in test methods.

The test methods don't have any exception handling. While JUnit will mark tests as failed if an exception occurs, it would be helpful to add try-catch blocks to log more detailed information about failures, especially in UI tests where failures can be hard to diagnose.

Example implementation:

 @Test
 public void testRandomLetterEditPage() {
-    log.info("testRandomLetterEditPage");
-    
-    MainContentPage mainContentPage = new MainContentPage(driver);
-    mainContentPage.pressLetterListLink();
-
-    LetterListPage letterListPage = new LetterListPage(driver);
-    letterListPage.pressRandomLetter();
-
-    LetterEditPage letterEditPage = new LetterEditPage(driver);
+    log.info("Starting testRandomLetterEditPage");
+    try {
+        MainContentPage mainContentPage = new MainContentPage(driver);
+        mainContentPage.pressLetterListLink();
+
+        LetterListPage letterListPage = new LetterListPage(driver);
+        letterListPage.pressRandomLetter();
+
+        LetterEditPage letterEditPage = new LetterEditPage(driver);
+        assertTrue(letterEditPage.isPageLoaded(), "Letter edit page failed to load");
+        log.info("Successfully completed testRandomLetterEditPage");
+    } catch (Exception e) {
+        log.error("Error in testRandomLetterEditPage: " + e.getMessage(), e);
+        throw e; // rethrow to fail the test
+    }
 }
src/test/java/selenium/content/sound/SoundListPage.java (2)

9-17: Consider adding error handling for element verification.

The constructor correctly verifies we're on the expected page by checking for the "soundListPage" element ID, but it doesn't handle the potential NoSuchElementException that could be thrown if the element isn't found.

public SoundListPage(WebDriver driver) {
    this.driver = driver;

-   driver.findElement(By.id("soundListPage"));
+   try {
+       driver.findElement(By.id("soundListPage"));
+   } catch (org.openqa.selenium.NoSuchElementException e) {
+       throw new IllegalStateException("This is not the Sound List page. Current URL: " + driver.getCurrentUrl(), e);
+   }
}

26-29: Consider adding explicit wait for button clickability.

The pressCreateButton() method directly clicks on the button without ensuring that it's clickable. Adding an explicit wait would make the test more robust.

public void pressCreateButton() {
-   WebElement button = driver.findElement(By.id("createButton"));
-   button.click();
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("createButton")));
+   button.click();
}

You would need to add these imports:

import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
src/test/java/selenium/content/letter_sound/LetterSoundListPage.java (2)

9-17: Consider adding error handling for element verification.

Similar to the SoundListPage, the constructor should handle the potential NoSuchElementException when checking for the page ID.

public LetterSoundListPage(WebDriver driver) {
    this.driver = driver;

-   driver.findElement(By.id("letterSoundListPage"));
+   try {
+       driver.findElement(By.id("letterSoundListPage"));
+   } catch (org.openqa.selenium.NoSuchElementException e) {
+       throw new IllegalStateException("This is not the Letter Sound List page. Current URL: " + driver.getCurrentUrl(), e);
+   }
}

26-29: Consider adding explicit wait for button clickability.

Adding an explicit wait would make the test more robust when clicking the create button.

public void pressCreateButton() {
-   WebElement button = driver.findElement(By.id("createButton"));
-   button.click();
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("createButton")));
+   button.click();
}

You would need to add these imports:

import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
src/test/java/selenium/content/MainContentPage.java (3)

7-15: Add error handling for the page validation in the constructor.

The constructor should handle the potential NoSuchElementException when checking for the main content page ID.

public MainContentPage(WebDriver driver) {
    this.driver = driver;

-   driver.findElement(By.id("mainContentPage"));
+   try {
+       driver.findElement(By.id("mainContentPage"));
+   } catch (org.openqa.selenium.NoSuchElementException e) {
+       throw new IllegalStateException("This is not the Main Content page. Current URL: " + driver.getCurrentUrl(), e);
+   }
}

17-30: Add explicit waits for link clickability in navigation methods.

All three navigation methods would benefit from explicit waits to ensure the links are clickable before attempting to click them.

Here's an example for the pressLetterListLink() method (apply similar changes to the other methods):

public void pressLetterListLink() {
-   WebElement link = driver.findElement(By.id("letterListLink"));
-   link.click();
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   WebElement link = wait.until(ExpectedConditions.elementToBeClickable(By.id("letterListLink")));
+   link.click();
}

Don't forget to add these imports:

import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;

7-31: Consider implementing a return type for navigation methods.

The navigation methods could return the corresponding page objects to enable method chaining, which is a common pattern in Selenium page objects.

- public void pressLetterListLink() {
+ public LetterListPage pressLetterListLink() {
    WebElement link = driver.findElement(By.id("letterListLink"));
    link.click();
+   return new LetterListPage(driver);
}

- public void pressSoundListLink() {
+ public SoundListPage pressSoundListLink() {
    WebElement link = driver.findElement(By.id("soundListLink"));
    link.click();
+   return new SoundListPage(driver);
}

- public void pressLetterSoundListLink() {
+ public LetterSoundListPage pressLetterSoundListLink() {
    WebElement link = driver.findElement(By.id("letterSoundListLink"));
    link.click();
+   return new LetterSoundListPage(driver);
}

You would need to add these imports:

import selenium.content.letter.LetterListPage;
import selenium.content.sound.SoundListPage;
import selenium.content.letter_sound.LetterSoundListPage;
src/test/java/selenium/content/letter/LetterListPage.java (3)

9-17: Add error handling for page validation in the constructor.

The constructor should handle the potential NoSuchElementException when checking for the letter list page ID.

public LetterListPage(WebDriver driver) {
    this.driver = driver;

-   driver.findElement(By.id("letterListPage"));
+   try {
+       driver.findElement(By.id("letterListPage"));
+   } catch (org.openqa.selenium.NoSuchElementException e) {
+       throw new IllegalStateException("This is not the Letter List page. Current URL: " + driver.getCurrentUrl(), e);
+   }
}

26-29: Consider adding explicit wait for button clickability.

Adding an explicit wait would make the test more robust when clicking the create button.

public void pressCreateButton() {
-   WebElement button = driver.findElement(By.id("createButton"));
-   button.click();
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("createButton")));
+   button.click();
}

You would need to add these imports:

import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;

1-30: Consider using @findby annotations for Page Factory pattern.

The current code uses driver.findElement() for locating elements. Consider using the Page Factory pattern with @FindBy annotations for more readable and maintainable code.

Here's how the class could be refactored to use Page Factory:

package selenium.content.letter;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+ import org.openqa.selenium.support.FindBy;
+ import org.openqa.selenium.support.PageFactory;

public class LetterListPage {
    
    private WebDriver driver;
    
+   @FindBy(id = "letterListPage")
+   private WebElement letterListPageElement;
+   
+   @FindBy(className = "editLink")
+   private List<WebElement> editLinks;
+   
+   @FindBy(id = "createButton")
+   private WebElement createButton;

    public LetterListPage(WebDriver driver) {
        this.driver = driver;
-       driver.findElement(By.id("letterListPage"));
+       PageFactory.initElements(driver, this);
+       if (letterListPageElement == null) {
+           throw new IllegalStateException("This is not the Letter List page");
+       }
    }

    public void pressRandomLetter() {
-       List<WebElement> links = driver.findElements(By.className("editLink"));
+       if (editLinks.isEmpty()) {
+           throw new IllegalStateException("No letter elements found with class 'editLink' on the page");
+       }
-       int randomIndex = (int)(Math.random() * links.size());
-       WebElement randomLink = links.get(randomIndex);
+       int randomIndex = (int)(Math.random() * editLinks.size());
+       WebElement randomLink = editLinks.get(randomIndex);
        randomLink.click();
    }

    public void pressCreateButton() {
-       WebElement button = driver.findElement(By.id("createButton"));
-       button.click();
+       createButton.click();
    }
}

This applies to all the page object classes in this PR.

src/main/webapp/WEB-INF/jsp/content/main.jsp (1)

51-52: Consider adding IDs to the remaining list links for consistency.

The current changes add IDs to three specific list links, but several other similar links remain without IDs. For comprehensive UI test coverage, consider adding IDs to all list links following the same naming pattern ([resourceType]ListLink).

Also applies to: 62-64, 74-76

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec17796 and 044949f.

📒 Files selected for processing (18)
  • pom-dependency-tree.txt (1 hunks)
  • src/main/webapp/WEB-INF/jsp/content/letter-sound/list.jsp (1 hunks)
  • src/main/webapp/WEB-INF/jsp/content/letter/list.jsp (2 hunks)
  • src/main/webapp/WEB-INF/jsp/content/main.jsp (3 hunks)
  • src/main/webapp/WEB-INF/jsp/content/sound/list.jsp (2 hunks)
  • src/test/java/selenium/content/MainContentPage.java (1 hunks)
  • src/test/java/selenium/content/letter/LetterCreatePage.java (1 hunks)
  • src/test/java/selenium/content/letter/LetterEditPage.java (1 hunks)
  • src/test/java/selenium/content/letter/LetterListPage.java (1 hunks)
  • src/test/java/selenium/content/letter/LetterTest.java (1 hunks)
  • src/test/java/selenium/content/letter_sound/LetterSoundCreatePage.java (1 hunks)
  • src/test/java/selenium/content/letter_sound/LetterSoundEditPage.java (1 hunks)
  • src/test/java/selenium/content/letter_sound/LetterSoundListPage.java (1 hunks)
  • src/test/java/selenium/content/letter_sound/LetterSoundTest.java (1 hunks)
  • src/test/java/selenium/content/sound/SoundCreatePage.java (1 hunks)
  • src/test/java/selenium/content/sound/SoundEditPage.java (1 hunks)
  • src/test/java/selenium/content/sound/SoundListPage.java (1 hunks)
  • src/test/java/selenium/content/sound/SoundTest.java (1 hunks)
🔇 Additional comments (15)
src/main/webapp/WEB-INF/jsp/content/letter/list.jsp (2)

43-43: Good addition of class attribute for UI testing.

The addition of the class="editLink" attribute to the anchor element is a good practice for UI testing. This makes the element easily selectable in Selenium tests and supports the PR's objective of improving UI test coverage.


84-84: Good addition of ID attribute for UI testing.

The addition of the id="createButton" attribute to the anchor element is a good practice for UI testing. This makes the element easily selectable in Selenium tests and supports the PR's objective of improving UI test coverage.

The ID is consistent with the one used in the letter-sound list page, which is good for maintainability.

pom-dependency-tree.txt (1)

1-4: New dependency addition looks good.

The update to ai.elimu:webapp:war:2.5.33-SNAPSHOT and the addition of the model dependency com.github.elimu-ai:model:jar:model-2.0.83:compile with its transitive dependencies support the initiative to improve UI test coverage. This aligns well with the PR objectives.

src/test/java/selenium/content/sound/SoundTest.java (2)

19-36: Setup method looks good.

The setUp method correctly initializes the WebDriver with proper ChromeOptions configuration that supports headless mode through system properties, which is useful for CI/CD environments.


38-43: Teardown method is properly implemented.

The tearDown method correctly releases resources by quitting the WebDriver instance.

src/test/java/selenium/content/sound/SoundListPage.java (1)

1-8: Good package structure and import organization.

The package and imports are well-organized and appropriately concise, importing only what's needed for the page object.

src/test/java/selenium/content/letter_sound/LetterSoundListPage.java (1)

1-8: Good package structure and import organization.

The package and imports are well-organized and appropriately concise.

src/test/java/selenium/content/MainContentPage.java (1)

1-6: Good package structure and import organization.

The package and imports are well-organized and appropriately concise.

src/test/java/selenium/content/letter/LetterListPage.java (1)

1-8: Good package structure and import organization.

The package and imports are well-organized and appropriately concise.

src/main/webapp/WEB-INF/jsp/content/main.jsp (3)

17-17: Adding ID attributes to navigation links improves testability.

The addition of the id="letterListLink" attribute enhances the ability to target this specific element in Selenium tests, which directly supports the PR's objective of improving UI test coverage.


28-28: Adding ID attributes to navigation links improves testability.

The addition of the id="soundListLink" attribute enhances the ability to target this specific element in Selenium tests, which directly supports the PR's objective of improving UI test coverage.


39-39: Adding ID attributes to navigation links improves testability.

The addition of the id="letterSoundListLink" attribute enhances the ability to target this specific element in Selenium tests, which directly supports the PR's objective of improving UI test coverage.

src/main/webapp/WEB-INF/jsp/content/sound/list.jsp (3)

45-45: Adding class attributes to edit links improves testability.

The addition of the class="editLink" attribute to the sound edit links is a good practice for UI testing. Using a class (rather than an ID) is appropriate here since there are multiple edit links on the page.


87-87: Adding ID to the create button improves testability.

The addition of the id="createButton" attribute to the create sound button makes it easier to target this specific element in Selenium tests, supporting the PR's objective of improving UI test coverage.


7-18: Good existing practice with event handling.

The existing code for the export button already follows good practices by using a specific ID (exportToCsvButton) and properly implementing event handling. The new changes follow this same pattern, maintaining consistency in the codebase.

Comment on lines +1 to +15
package selenium.content.letter;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LetterEditPage {

private WebDriver driver;

public LetterEditPage(WebDriver driver) {
this.driver = driver;

driver.findElement(By.id("letterEditPage"));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider implementing a base page object to reduce duplication across page classes.

I notice a pattern of similar code structure across the different page objects. Consider creating a base page class to reduce duplication and improve maintainability.

Here's a suggested approach using a base page class:

package selenium.content.letter;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import java.time.Duration;
+import selenium.content.BasePage;

-public class LetterEditPage {
+/**
+ * Page object representing the Letter Edit page.
+ */
+public class LetterEditPage extends BasePage {
-    
-    private WebDriver driver;
-
    public LetterEditPage(WebDriver driver) {
-        this.driver = driver;
-
-        driver.findElement(By.id("letterEditPage"));
+        super(driver, "letterEditPage");
    }
+    
+    // Add methods specific to letter editing functionality
}

And create a base page class:

package selenium.content;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;

/**
 * Base class for all page objects.
 * Handles common functionality like waiting for page elements.
 */
public abstract class BasePage {
    
    protected WebDriver driver;
    protected WebDriverWait wait;
    
    /**
     * Constructor for BasePage.
     * 
     * @param driver The WebDriver instance
     * @param pageIdentifier The ID of an element that uniquely identifies this page
     */
    public BasePage(WebDriver driver, String pageIdentifier) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        
        // Wait for the page identifier to be present
        wait.until(ExpectedConditions.presenceOfElementLocated(By.id(pageIdentifier)));
    }
    
    /**
     * Waits for an element to be visible and returns it.
     * 
     * @param locator The By locator to find the element
     * @return The WebElement once it's visible
     */
    protected WebElement waitForVisibility(By locator) {
        return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
    }
    
    /**
     * Waits for an element to be clickable and returns it.
     * 
     * @param locator The By locator to find the element
     * @return The WebElement once it's clickable
     */
    protected WebElement waitForClickable(By locator) {
        return wait.until(ExpectedConditions.elementToBeClickable(locator));
    }
}

Comment on lines +45 to +56
@Test
public void testRandomSoundEditPage() {
log.info("testRandomSoundEditPage");

MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressSoundListLink();

SoundListPage soundListPage = new SoundListPage(driver);
soundListPage.pressRandomSound();

SoundEditPage soundEditPage = new SoundEditPage(driver);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add assertions to validate test outcomes.

The test navigates to pages but doesn't verify any expected outcomes. Consider adding assertions to validate that the page was loaded correctly or that specific elements are present.

 @Test
 public void testRandomSoundEditPage() {
     log.info("testRandomSoundEditPage");
     
     MainContentPage mainContentPage = new MainContentPage(driver);
     mainContentPage.pressSoundListLink();

     SoundListPage soundListPage = new SoundListPage(driver);
     soundListPage.pressRandomSound();

     SoundEditPage soundEditPage = new SoundEditPage(driver);
+    // Verify that we're on the edit page
+    assertTrue(soundEditPage.isPageLoaded(), "Sound edit page failed to load");
 }
📝 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
@Test
public void testRandomSoundEditPage() {
log.info("testRandomSoundEditPage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressSoundListLink();
SoundListPage soundListPage = new SoundListPage(driver);
soundListPage.pressRandomSound();
SoundEditPage soundEditPage = new SoundEditPage(driver);
}
@Test
public void testRandomSoundEditPage() {
log.info("testRandomSoundEditPage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressSoundListLink();
SoundListPage soundListPage = new SoundListPage(driver);
soundListPage.pressRandomSound();
SoundEditPage soundEditPage = new SoundEditPage(driver);
// Verify that we're on the edit page
assertTrue(soundEditPage.isPageLoaded(), "Sound edit page failed to load");
}

Comment on lines 58 to 69
@Test
public void testSoundCreatPage() {
log.info("testSoundCreatePage");

MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressSoundListLink();

SoundListPage soundListPage = new SoundListPage(driver);
soundListPage.pressCreateButton();

SoundCreatePage SoundCreatePage = new SoundCreatePage(driver);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add assertions and fix variable naming.

This test method has three issues:

  1. No assertions to validate expected outcomes
  2. Method name has a typo
  3. Variable name uses PascalCase instead of camelCase
 @Test
-public void testSoundCreatPage() {
+public void testSoundCreatePage() {
     log.info("testSoundCreatePage");

     MainContentPage mainContentPage = new MainContentPage(driver);
     mainContentPage.pressSoundListLink();

     SoundListPage soundListPage = new SoundListPage(driver);
     soundListPage.pressCreateButton();

-    SoundCreatePage SoundCreatePage = new SoundCreatePage(driver);
+    SoundCreatePage soundCreatePage = new SoundCreatePage(driver);
+    // Verify that we're on the create page
+    assertTrue(soundCreatePage.isPageLoaded(), "Sound create page failed to load");
 }
📝 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
@Test
public void testSoundCreatPage() {
log.info("testSoundCreatePage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressSoundListLink();
SoundListPage soundListPage = new SoundListPage(driver);
soundListPage.pressCreateButton();
SoundCreatePage SoundCreatePage = new SoundCreatePage(driver);
}
@Test
public void testSoundCreatePage() {
log.info("testSoundCreatePage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressSoundListLink();
SoundListPage soundListPage = new SoundListPage(driver);
soundListPage.pressCreateButton();
SoundCreatePage soundCreatePage = new SoundCreatePage(driver);
// Verify that we're on the create page
assertTrue(soundCreatePage.isPageLoaded(), "Sound create page failed to load");
}

Comment on lines +45 to +56
@Test
public void testRandomLetterSoundEditPage() {
log.info("testRandomLetterSoundEditPage");

MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterSoundListLink();

LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
letterSoundListPage.pressRandomLetterSound();

LetterSoundEditPage letterSoundEditPage = new LetterSoundEditPage(driver);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add assertions to validate test outcomes.

The test method navigates to pages but doesn't verify any expected outcomes. Consider adding assertions to validate that the page was loaded correctly or that specific elements are present.

 @Test
 public void testRandomLetterSoundEditPage() {
     log.info("testRandomLetterSoundEditPage");
     
     MainContentPage mainContentPage = new MainContentPage(driver);
     mainContentPage.pressLetterSoundListLink();

     LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
     letterSoundListPage.pressRandomLetterSound();

     LetterSoundEditPage letterSoundEditPage = new LetterSoundEditPage(driver);
+    // Verify that we're on the edit page
+    assertTrue(letterSoundEditPage.isPageLoaded(), "Letter sound edit page failed to load");
 }
📝 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
@Test
public void testRandomLetterSoundEditPage() {
log.info("testRandomLetterSoundEditPage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterSoundListLink();
LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
letterSoundListPage.pressRandomLetterSound();
LetterSoundEditPage letterSoundEditPage = new LetterSoundEditPage(driver);
}
@Test
public void testRandomLetterSoundEditPage() {
log.info("testRandomLetterSoundEditPage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterSoundListLink();
LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
letterSoundListPage.pressRandomLetterSound();
LetterSoundEditPage letterSoundEditPage = new LetterSoundEditPage(driver);
// Verify that we're on the edit page
assertTrue(letterSoundEditPage.isPageLoaded(), "Letter sound edit page failed to load");
}

Comment on lines 58 to 69
@Test
public void testLetterSoundCreatPage() {
log.info("testLetterSoundCreatePage");

MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterSoundListLink();

LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
letterSoundListPage.pressCreateButton();

LetterSoundCreatePage letterSoundCreatePage = new LetterSoundCreatePage(driver);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add assertions to validate test outcomes.

The test method navigates to the letter sound creation page but doesn't verify any expected outcomes. Consider adding assertions to validate that the page was loaded correctly.

 @Test
-public void testLetterSoundCreatPage() {
+public void testLetterSoundCreatePage() {
     log.info("testLetterSoundCreatePage");

     MainContentPage mainContentPage = new MainContentPage(driver);
     mainContentPage.pressLetterSoundListLink();

     LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
     letterSoundListPage.pressCreateButton();

     LetterSoundCreatePage letterSoundCreatePage = new LetterSoundCreatePage(driver);
+    // Verify that we're on the create page
+    assertTrue(letterSoundCreatePage.isPageLoaded(), "Letter sound create page failed to load");
 }
📝 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
@Test
public void testLetterSoundCreatPage() {
log.info("testLetterSoundCreatePage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterSoundListLink();
LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
letterSoundListPage.pressCreateButton();
LetterSoundCreatePage letterSoundCreatePage = new LetterSoundCreatePage(driver);
}
@Test
public void testLetterSoundCreatePage() {
log.info("testLetterSoundCreatePage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterSoundListLink();
LetterSoundListPage letterSoundListPage = new LetterSoundListPage(driver);
letterSoundListPage.pressCreateButton();
LetterSoundCreatePage letterSoundCreatePage = new LetterSoundCreatePage(driver);
// Verify that we're on the create page
assertTrue(letterSoundCreatePage.isPageLoaded(), "Letter sound create page failed to load");
}

Comment on lines 58 to 69
@Test
public void testLetterCreatPage() {
log.info("testLetterCreatePage");

MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterListLink();

LetterListPage letterListPage = new LetterListPage(driver);
letterListPage.pressCreateButton();

LetterCreatePage letterCreatePage = new LetterCreatePage(driver);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add assertions to validate test outcomes.

The test method navigates to the letter creation page but doesn't verify any expected outcomes. Consider adding assertions to validate that the page was loaded correctly.

 @Test
-public void testLetterCreatPage() {
+public void testLetterCreatePage() {
     log.info("testLetterCreatePage");

     MainContentPage mainContentPage = new MainContentPage(driver);
     mainContentPage.pressLetterListLink();

     LetterListPage letterListPage = new LetterListPage(driver);
     letterListPage.pressCreateButton();

     LetterCreatePage letterCreatePage = new LetterCreatePage(driver);
+    // Verify that we're on the create page
+    assertTrue(letterCreatePage.isPageLoaded(), "Letter create page failed to load");
 }
📝 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
@Test
public void testLetterCreatPage() {
log.info("testLetterCreatePage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterListLink();
LetterListPage letterListPage = new LetterListPage(driver);
letterListPage.pressCreateButton();
LetterCreatePage letterCreatePage = new LetterCreatePage(driver);
}
@Test
public void testLetterCreatePage() {
log.info("testLetterCreatePage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterListLink();
LetterListPage letterListPage = new LetterListPage(driver);
letterListPage.pressCreateButton();
LetterCreatePage letterCreatePage = new LetterCreatePage(driver);
// Verify that we're on the create page
assertTrue(letterCreatePage.isPageLoaded(), "Letter create page failed to load");
}

Comment on lines +45 to +56
@Test
public void testRandomLetterEditPage() {
log.info("testRandomLetterEditPage");

MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterListLink();

LetterListPage letterListPage = new LetterListPage(driver);
letterListPage.pressRandomLetter();

LetterEditPage letterEditPage = new LetterEditPage(driver);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add assertions to validate test outcomes.

The test method navigates to pages but doesn't verify any expected outcomes. Consider adding assertions to validate that the page was loaded correctly or that specific elements are present.

 @Test
 public void testRandomLetterEditPage() {
     log.info("testRandomLetterEditPage");
     
     MainContentPage mainContentPage = new MainContentPage(driver);
     mainContentPage.pressLetterListLink();

     LetterListPage letterListPage = new LetterListPage(driver);
     letterListPage.pressRandomLetter();

     LetterEditPage letterEditPage = new LetterEditPage(driver);
+    // Verify that we're on the edit page
+    assertTrue(letterEditPage.isPageLoaded(), "Letter edit page failed to load");
 }
📝 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
@Test
public void testRandomLetterEditPage() {
log.info("testRandomLetterEditPage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterListLink();
LetterListPage letterListPage = new LetterListPage(driver);
letterListPage.pressRandomLetter();
LetterEditPage letterEditPage = new LetterEditPage(driver);
}
@Test
public void testRandomLetterEditPage() {
log.info("testRandomLetterEditPage");
MainContentPage mainContentPage = new MainContentPage(driver);
mainContentPage.pressLetterListLink();
LetterListPage letterListPage = new LetterListPage(driver);
letterListPage.pressRandomLetter();
LetterEditPage letterEditPage = new LetterEditPage(driver);
// Verify that we're on the edit page
assertTrue(letterEditPage.isPageLoaded(), "Letter edit page failed to load");
}

Comment on lines 19 to 24
public void pressRandomSound() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add a check for empty list to prevent IndexOutOfBoundsException.

The pressRandomSound() method should check if the list of links is empty before attempting to select a random element.

public void pressRandomSound() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
+   if (links.isEmpty()) {
+       throw new IllegalStateException("No sound elements found with class 'editLink' on the page");
+   }
    int randomIndex = (int)(Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
    randomLink.click();
}
📝 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 void pressRandomSound() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
public void pressRandomSound() {
List<WebElement> links = driver.findElements(By.className("editLink"));
if (links.isEmpty()) {
throw new IllegalStateException("No sound elements found with class 'editLink' on the page");
}
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}

Comment on lines 19 to 24
public void pressRandomLetterSound() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for empty list of letter sounds.

The method should check if the list is empty before trying to select a random element.

public void pressRandomLetterSound() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
+   if (links.isEmpty()) {
+       throw new IllegalStateException("No letter sound elements found with class 'editLink' on the page");
+   }
    int randomIndex = (int)(Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
    randomLink.click();
}
📝 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 void pressRandomLetterSound() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
public void pressRandomLetterSound() {
List<WebElement> links = driver.findElements(By.className("editLink"));
if (links.isEmpty()) {
throw new IllegalStateException("No letter sound elements found with class 'editLink' on the page");
}
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}

Comment on lines 19 to 24
public void pressRandomLetter() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add check for empty list to prevent IndexOutOfBoundsException.

The pressRandomLetter() method should check if the list of links is empty before attempting to select a random element.

public void pressRandomLetter() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
+   if (links.isEmpty()) {
+       throw new IllegalStateException("No letter elements found with class 'editLink' on the page");
+   }
    int randomIndex = (int)(Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
    randomLink.click();
}
📝 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 void pressRandomLetter() {
List<WebElement> links = driver.findElements(By.className("editLink"));
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}
public void pressRandomLetter() {
List<WebElement> links = driver.findElements(By.className("editLink"));
if (links.isEmpty()) {
throw new IllegalStateException("No letter elements found with class 'editLink' on the page");
}
int randomIndex = (int)(Math.random() * links.size());
WebElement randomLink = links.get(randomIndex);
randomLink.click();
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/test/java/selenium/content/letter/LetterListPage.java (1)

19-24: 🛠️ Refactor suggestion

Add check for empty list to prevent IndexOutOfBoundsException.

The pressRandomLetter() method should check if the list of links is empty before attempting to select a random element.

public void pressRandomLetter() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
+   if (links.isEmpty()) {
+       throw new IllegalStateException("No letter elements found with class 'editLink' on the page");
+   }
    int randomIndex = (int) (Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
    randomLink.click();
}
🧹 Nitpick comments (7)
src/test/java/selenium/content/sound/SoundListPage.java (3)

19-24: Consider adding explicit waits for better test reliability.

Selenium tests can be flaky if elements aren't ready for interaction. Adding explicit waits ensures elements are clickable before attempting to interact with them.

+ import org.openqa.selenium.support.ui.ExpectedConditions;
+ import org.openqa.selenium.support.ui.WebDriverWait;
+ import java.time.Duration;

public void pressRandomSound() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
    if (links.isEmpty()) {
        throw new IllegalStateException("No sound elements found with class 'editLink' on the page");
    }
    int randomIndex = (int)(Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   wait.until(ExpectedConditions.elementToBeClickable(randomLink));
    randomLink.click();
}

26-29: Consider adding explicit wait for better reliability when pressing the create button.

Similar to the previous comment, adding an explicit wait before clicking the create button will make the test more reliable.

+ import org.openqa.selenium.support.ui.ExpectedConditions;
+ import org.openqa.selenium.support.ui.WebDriverWait;
+ import java.time.Duration;

public void pressCreateButton() {
    WebElement button = driver.findElement(By.id("createButton"));
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   wait.until(ExpectedConditions.elementToBeClickable(button));
    button.click();
}

1-30: Consider adding verification methods to confirm successful navigation.

After clicking elements, it's good practice to verify that the expected navigation occurred. This helps identify issues where clicks don't result in the expected page changes.

+ /**
+  * Verifies that navigation to the sound edit page was successful after clicking a random sound.
+  * 
+  * @return true if navigation was successful, false otherwise
+  */
+ public boolean isNavigatedToSoundEditPage() {
+     try {
+         // Assuming the edit page has an element with id "soundEditPage"
+         WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+         wait.until(ExpectedConditions.presenceOfElementLocated(By.id("soundEditPage")));
+         return true;
+     } catch (Exception e) {
+         return false;
+     }
+ }
+ 
+ /**
+  * Verifies that navigation to the sound creation page was successful after clicking the create button.
+  * 
+  * @return true if navigation was successful, false otherwise
+  */
+ public boolean isNavigatedToSoundCreatePage() {
+     try {
+         // Assuming the create page has an element with id "soundCreatePage"
+         WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+         wait.until(ExpectedConditions.presenceOfElementLocated(By.id("soundCreatePage")));
+         return true;
+     } catch (Exception e) {
+         return false;
+     }
+ }
src/test/java/selenium/content/number/NumberEditPage.java (1)

6-14: Page object follows best practices but lacks interaction methods.

The implementation correctly follows the Page Object Model pattern and uses constructor verification to ensure the page is loaded. However, it would be more useful to include methods that allow interaction with the elements on the page.

Consider adding methods that enable interactions with elements on the page, such as:

public void setNumberValue(String value) {
    WebElement numberValueInput = driver.findElement(By.id("numberValue"));
    numberValueInput.clear();
    numberValueInput.sendKeys(value);
}

public void submit() {
    driver.findElement(By.id("submitButton")).click();
}

public String getPageTitle() {
    return driver.getTitle();
}
src/test/java/selenium/content/number/NumberCreatePage.java (1)

6-14: Page object follows best practices but lacks interaction methods.

The implementation correctly follows the Page Object Model pattern with constructor verification. However, to make this page object more useful, it should include methods that interact with form elements on the create page.

Consider enhancing this page object with methods to interact with form elements:

public void setNumberValue(String value) {
    WebElement valueInput = driver.findElement(By.id("value"));
    valueInput.clear();
    valueInput.sendKeys(value);
}

public void setSymbol(String symbol) {
    WebElement symbolInput = driver.findElement(By.id("symbol"));
    symbolInput.clear();
    symbolInput.sendKeys(symbol);
}

public void submitForm() {
    driver.findElement(By.cssSelector("button[type='submit']")).click();
}

public NumberListPage clickCancel() {
    driver.findElement(By.linkText("Cancel")).click();
    return new NumberListPage(driver);
}
src/test/java/selenium/content/number/NumberTest.java (1)

1-69: Consider adding a comprehensive end-to-end test.

The current tests verify navigation to specific pages but don't test the full workflow of creating, editing, and potentially deleting numbers.

Consider adding a comprehensive end-to-end test that covers the complete CRUD workflow:

@Test
public void testNumberCreateEditDeleteWorkflow() {
    log.info("testNumberCreateEditDeleteWorkflow");
    
    // Navigate to create page
    MainContentPage mainContentPage = new MainContentPage(driver);
    mainContentPage.pressNumberListLink();
    
    NumberListPage numberListPage = new NumberListPage(driver);
    numberListPage.pressCreateButton();
    
    // Create a new number
    NumberCreatePage numberCreatePage = new NumberCreatePage(driver);
    String testValue = "99";
    String testSymbol = "99";
    numberCreatePage.setNumberValue(testValue);
    numberCreatePage.setSymbol(testSymbol);
    numberCreatePage.submitForm();
    
    // Verify number was created and appears in list
    numberListPage = new NumberListPage(driver);
    assertTrue(numberListPage.isNumberPresent(testValue), 
               "The created number should appear in the list");
    
    // Edit the number
    numberListPage.pressNumber(testValue);
    NumberEditPage numberEditPage = new NumberEditPage(driver);
    String updatedSymbol = "99_updated";
    numberEditPage.setSymbol(updatedSymbol);
    numberEditPage.submit();
    
    // Verify number was updated
    numberListPage = new NumberListPage(driver);
    assertTrue(numberListPage.isNumberPresent(testValue), 
               "The updated number should appear in the list");
    
    // Delete the number if applicable
    // ...
}

This test would require adding the necessary methods to the page objects.

src/test/java/selenium/content/MainContentPage.java (1)

17-35: Consider extracting repeated click logic to a helper method.

All four methods follow the same pattern of finding an element by ID and clicking it. This redundancy could be reduced by having a private helper method.

+ private void clickElementById(String id) {
+     WebElement element = driver.findElement(By.id(id));
+     element.click();
+ }

  public void pressLetterListLink() {
-     WebElement link = driver.findElement(By.id("letterListLink"));
-     link.click();
+     clickElementById("letterListLink");
  }

  public void pressSoundListLink() {
-     WebElement link = driver.findElement(By.id("soundListLink"));
-     link.click();
+     clickElementById("soundListLink");
  }

  public void pressLetterSoundListLink() {
-     WebElement link = driver.findElement(By.id("letterSoundListLink"));
-     link.click();
+     clickElementById("letterSoundListLink");
  }

  public void pressNumberListLink() {
-     WebElement link = driver.findElement(By.id("numberListLink"));
-     link.click();
+     clickElementById("numberListLink");
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 044949f and b9d39ba.

📒 Files selected for processing (14)
  • pom-dependency-tree.txt (1 hunks)
  • src/main/webapp/WEB-INF/jsp/content/main.jsp (4 hunks)
  • src/main/webapp/WEB-INF/jsp/content/number/list.jsp (2 hunks)
  • src/test/java/selenium/content/MainContentPage.java (1 hunks)
  • src/test/java/selenium/content/letter/LetterListPage.java (1 hunks)
  • src/test/java/selenium/content/letter/LetterTest.java (1 hunks)
  • src/test/java/selenium/content/letter_sound/LetterSoundListPage.java (1 hunks)
  • src/test/java/selenium/content/letter_sound/LetterSoundTest.java (1 hunks)
  • src/test/java/selenium/content/number/NumberCreatePage.java (1 hunks)
  • src/test/java/selenium/content/number/NumberEditPage.java (1 hunks)
  • src/test/java/selenium/content/number/NumberListPage.java (1 hunks)
  • src/test/java/selenium/content/number/NumberTest.java (1 hunks)
  • src/test/java/selenium/content/sound/SoundListPage.java (1 hunks)
  • src/test/java/selenium/content/sound/SoundTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • pom-dependency-tree.txt
  • src/test/java/selenium/content/sound/SoundTest.java
  • src/test/java/selenium/content/letter_sound/LetterSoundListPage.java
  • src/test/java/selenium/content/letter_sound/LetterSoundTest.java
  • src/main/webapp/WEB-INF/jsp/content/main.jsp
  • src/test/java/selenium/content/letter/LetterTest.java
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: build (windows-latest, 21)
  • GitHub Check: build (windows-latest, 17)
  • GitHub Check: build (ubuntu-latest, 21)
  • GitHub Check: test_rest_ENG
  • GitHub Check: test_ui_ENG
  • GitHub Check: build (ubuntu-latest, 17)
🔇 Additional comments (13)
src/test/java/selenium/content/sound/SoundListPage.java (2)

9-18: Good class structure following the Page Object Model pattern.

The constructor correctly initializes the WebDriver and verifies that you're on the right page by checking for the presence of an element with the ID "soundListPage". This follows good practices for page object design.


19-24: Add a check for empty list to prevent IndexOutOfBoundsException.

The pressRandomSound() method should check if the list of links is empty before attempting to select a random element.

public void pressRandomSound() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
+   if (links.isEmpty()) {
+       throw new IllegalStateException("No sound elements found with class 'editLink' on the page");
+   }
    int randomIndex = (int)(Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
    randomLink.click();
}
src/main/webapp/WEB-INF/jsp/content/number/list.jsp (2)

37-37: Good addition of class attribute for test targeting.

Adding the class="editLink" attribute to the anchor tag helps with element targeting in UI tests, making them more reliable and easier to maintain.


81-81: Good addition of ID attribute for test targeting.

Adding the id="createButton" attribute to the anchor tag provides a reliable way to target this specific element in UI tests, improving testability.

src/test/java/selenium/content/number/NumberTest.java (2)

19-36: WebDriver setup follows best practices with headless mode option.

The setup method correctly initializes the WebDriver with options for headless mode based on a system property, which is useful for CI/CD environments. The implementation follows Selenium best practices.


38-43: Proper teardown to ensure WebDriver is closed.

The tearDown method correctly ensures that the WebDriver is properly closed after each test, which is important to prevent resource leaks.

src/test/java/selenium/content/number/NumberListPage.java (3)

1-8: LGTM: Import statements are correctly included for WebDriver, WebElement, and By.

The necessary Selenium imports are present for the required functionality. The class structure follows the Page Object Model pattern, which is a good approach for organizing UI tests.


9-17: LGTM: Constructor correctly initializes the page and validates we're on the right page.

The constructor properly initializes the WebDriver instance and checks that we're on the correct page by verifying the presence of the "numberListPage" element ID. This is good practice in Page Object Model design.


26-29: LGTM: Method correctly identifies and interacts with create button.

The method properly locates the create button by its ID and performs a click action on it.

src/test/java/selenium/content/letter/LetterListPage.java (2)

1-17: LGTM: Class is well-structured and constructor verifies page identity.

The class follows the Page Object Model pattern, initializes the WebDriver and verifies we're on the correct page. This is a good approach for organizing UI tests.


26-29: LGTM: Method correctly identifies and interacts with create button.

The method properly locates the create button by its ID and performs a click action on it.

src/test/java/selenium/content/MainContentPage.java (2)

1-15: LGTM: Class and constructor are well implemented.

The class follows the Page Object Model pattern and the constructor properly initializes the WebDriver and verifies we're on the correct page. This is a good practice in Selenium testing.


1-36:

❓ Verification inconclusive

Verify the ID attributes are present in corresponding JSP files.

Ensure that all the IDs used in this class (letterListLink, soundListLink, letterSoundListLink, numberListLink, mainContentPage) are properly added to the corresponding elements in the JSP files.


🏁 Script executed:

#!/bin/bash
# Check if IDs exist in JSP files

echo "Checking for IDs used in MainContentPage..."

# Search for mainContentPage ID
echo "Searching for mainContentPage ID..."
rg -A 1 -B 1 'id="mainContentPage"' --type jsp

# Search for letterListLink ID
echo "Searching for letterListLink ID..."
rg -A 1 -B 1 'id="letterListLink"' --type jsp

# Search for soundListLink ID
echo "Searching for soundListLink ID..."
rg -A 1 -B 1 'id="soundListLink"' --type jsp

# Search for letterSoundListLink ID
echo "Searching for letterSoundListLink ID..."
rg -A 1 -B 1 'id="letterSoundListLink"' --type jsp

# Search for numberListLink ID
echo "Searching for numberListLink ID..."
rg -A 1 -B 1 'id="numberListLink"' --type jsp

echo "Search complete"

Length of output: 927


Action Required: Update JSP ID Check Command

The current script using --type jsp failed because that file type isn’t recognized. Please verify that the IDs defined in MainContentPage.java—namely, mainContentPage, letterListLink, soundListLink, letterSoundListLink, and numberListLink—are correctly present in the corresponding JSP files. To streamline this verification, update your script to search JSP files using a glob pattern (e.g., rg -g "*.jsp" 'id="mainContentPage"') or a custom type definition.

  • Consider modifying the command to:
    rg -g "*.jsp" 'id="mainContentPage"'
    rg -g "*.jsp" 'id="letterListLink"'
    rg -g "*.jsp" 'id="soundListLink"'
    rg -g "*.jsp" 'id="letterSoundListLink"'
    rg -g "*.jsp" 'id="numberListLink"'
    
  • Confirm that each ID is present in the appropriate JSP file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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)
src/test/java/selenium/content/MainContentPage.java (2)

1-41: Solid implementation of the Page Object Model pattern for UI testing.

The MainContentPage class follows the Page Object Model pattern effectively, encapsulating the interactions with the main content page. This approach improves test maintainability by separating the test logic from the page interaction details.

A few suggestions to further enhance this class:

  1. Consider adding explicit waits for the elements before clicking to improve test reliability in slower environments.
  2. Add JavaDoc comments to document the purpose of each method and the class itself.
  3. Consider implementing a method to verify the page title or other unique attributes to ensure you're on the correct page.

Example of adding explicit waits and documentation:

package selenium.content;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import java.time.Duration;

/**
 * Page object representing the main content page.
 * Provides methods to interact with various navigation links.
 */
public class MainContentPage {
    
    private WebDriver driver;
+   private WebDriverWait wait;

    public MainContentPage(WebDriver driver) {
        this.driver = driver;
+       this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));

        driver.findElement(By.id("mainContentPage"));
    }

    /**
     * Clicks on the letter list link to navigate to the letter list page.
     */
    public void pressLetterListLink() {
-       WebElement link = driver.findElement(By.id("letterListLink"));
-       link.click();
+       wait.until(ExpectedConditions.elementToBeClickable(By.id("letterListLink"))).click();
    }

13-15: Consider adding error handling for the page verification.

The current implementation assumes the page element will be found. If the element is not found, the test will fail without a clear error message.

public MainContentPage(WebDriver driver) {
    this.driver = driver;

-   driver.findElement(By.id("mainContentPage"));
+   try {
+       driver.findElement(By.id("mainContentPage"));
+   } catch (Exception e) {
+       throw new IllegalStateException("This is not the Main Content page. Unable to find element with ID 'mainContentPage'", e);
+   }
}
src/test/java/selenium/content/word/WordTest.java (1)

23-31: Enhance headless mode configuration.

The current handling of the headless mode is good, but could be improved by adding additional arguments for better headless operation.

// Read "headless" property set on the command line: 
//    mvn clean verify -P regression-test-ui -D headless=true
String headlessSystemProperty = System.getProperty("headless");
log.info("headlessSystemProperty: \"" + headlessSystemProperty + "\"");
if ("true".equals(headlessSystemProperty)) {
-   chromeOptions.addArguments("headless");
+   chromeOptions.addArguments("--headless");
+   chromeOptions.addArguments("--disable-gpu");
+   chromeOptions.addArguments("--window-size=1920,1080");
+   chromeOptions.addArguments("--no-sandbox");
+   chromeOptions.addArguments("--disable-dev-shm-usage");
}
src/test/java/selenium/content/word/WordListPage.java (2)

19-24: Consider adding error handling for empty lists.

The pressRandomWord() method works well for selecting a random word from the list, but it might throw an IndexOutOfBoundsException if the list is empty. Consider adding a check to handle this case gracefully.

public void pressRandomWord() {
    List<WebElement> links = driver.findElements(By.className("editLink"));
+   if (links.isEmpty()) {
+       throw new RuntimeException("No words found on the page to select");
+   }
    int randomIndex = (int) (Math.random() * links.size());
    WebElement randomLink = links.get(randomIndex);
    randomLink.click();
}

26-29: Consider adding explicit wait for better reliability.

To improve test reliability, especially in slower environments, consider adding an explicit wait before interacting with the button.

public void pressCreateButton() {
+   // Wait for the button to be clickable
+   WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
+   WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("createButton")));
-   WebElement button = driver.findElement(By.id("createButton"));
    button.click();
}

This would require adding these imports:

import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9d39ba and 4552535.

📒 Files selected for processing (7)
  • src/main/webapp/WEB-INF/jsp/content/main.jsp (5 hunks)
  • src/main/webapp/WEB-INF/jsp/content/word/list.jsp (2 hunks)
  • src/test/java/selenium/content/MainContentPage.java (1 hunks)
  • src/test/java/selenium/content/word/WordCreatePage.java (1 hunks)
  • src/test/java/selenium/content/word/WordEditPage.java (1 hunks)
  • src/test/java/selenium/content/word/WordListPage.java (1 hunks)
  • src/test/java/selenium/content/word/WordTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/WEB-INF/jsp/content/main.jsp
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: build (windows-latest, 21)
  • GitHub Check: build (windows-latest, 17)
  • GitHub Check: build (ubuntu-latest, 21)
  • GitHub Check: test_ui_ENG
  • GitHub Check: build (ubuntu-latest, 17)
🔇 Additional comments (3)
src/test/java/selenium/content/word/WordListPage.java (1)

9-17: Well-structured Page Object implementation!

This is a good implementation of the Page Object Model pattern for Selenium tests. The constructor correctly verifies that the page has loaded by checking for the presence of the "wordListPage" element before allowing any interactions.

src/main/webapp/WEB-INF/jsp/content/word/list.jsp (2)

46-46: Good addition of the "editLink" class for Selenium targeting.

The addition of the "editLink" class to this anchor tag enables the Selenium test to identify and interact with these elements. This aligns well with the pressRandomWord() method in the WordListPage class.


132-132: Well-placed ID for the create button.

Adding the "createButton" ID to this button enables direct targeting in Selenium tests. This corresponds directly to the pressCreateButton() method in the WordListPage class, creating a clean connection between the UI and test code.

@jo-elimu jo-elimu merged commit 73bba2f into main Mar 4, 2025
11 of 12 checks passed
@jo-elimu jo-elimu deleted the 2037-improve-ui-test-coverage branch March 4, 2025 10:33
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.

Improve UI test coverage
1 participant