Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end Selenium tests and refactors parts of the chat UI/API integration, while also introducing Mongo repositories for roles/users and bootstrapping initial role/admin data at application startup. It additionally adds initial Docker packaging and a placeholder GitHub Actions workflow.
Changes:
- Add Selenium-based UI tests for login and chat pages.
- Refactor frontend JS to introduce an
APIClient, improve message rendering, and add “leave chat room” UI behaviors. - Add
RoleRepository/UserRepositoryusage in services and bootstrap roles + an admin user on startup; add Dockerfile and WIP CI workflow.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 24 comments.
Show a summary per file
| File | Description |
|---|---|
src/test/java/com/example/selenium/LoginPageTest.java |
Adds Selenium login/logout E2E tests. |
src/test/java/com/example/selenium/ChatPageTest.java |
Adds Selenium chat E2E test scaffolding. |
src/test/java/com/example/demo/ChatApplicationTests.java |
Renames/cleans up Spring Boot context test class. |
src/main/resources/templates/login.html |
Adds element IDs and updates login error text; reformats markup. |
src/main/resources/templates/index.html |
Disables “Leave” button by default. |
src/main/resources/templates/fragments/header.html |
Adds id="logout-button" for Selenium targeting. |
src/main/resources/static/js/utils/apiClient.js |
Introduces fetch wrapper + API client for chat/user endpoints. |
src/main/resources/static/js/ui.js |
Refactors message rendering; adds leave/talk-to button helpers. |
src/main/resources/static/js/index.js |
Switches to APIClient calls; refactors chat room row handling and leave flow. |
src/main/resources/static/js/class/ChatRooms.js |
Adjusts current chat room state storage and message append logic. |
src/main/java/com/example/demo/service/UserService.java |
Adds role/user repository usage; enforces unique email; adds admin creation + role-based lookup. |
src/main/java/com/example/demo/service/ChatMessageService.java |
Removes unused query methods; formatting and DTO conversion cleanup. |
src/main/java/com/example/demo/security/UserDetailsServiceImpl.java |
Updates repository usage to Optional and improves lookup flow. |
src/main/java/com/example/demo/repository/UserRepository.java |
Changes findUserByEmail to return Optional; adds username lookup + existsByEmail. |
src/main/java/com/example/demo/repository/RoleRepository.java |
Converts Role repository into a Spring Data MongoRepository. |
src/main/java/com/example/demo/repository/ChatRepository.java |
Removes unused custom query method. |
src/main/java/com/example/demo/model/UserDTO.java |
Renames DTO field from name to username. |
src/main/java/com/example/demo/model/User.java |
Adds @Email validation and introduces username. |
src/main/java/com/example/demo/model/Role.java |
Adds constructor and formatting cleanup. |
src/main/java/com/example/demo/model/ChatMessage.java |
Formatting/annotation ordering cleanup. |
src/main/java/com/example/demo/controller/MessageController.java |
Formatting cleanup and prepares for future Kafka integration (commented). |
src/main/java/com/example/demo/controller/ChatRestController.java |
Changes leave endpoint to DELETE and reformats. |
src/main/java/com/example/demo/config/SecurityConfig.java |
Formatting cleanup; no functional policy change intended. |
src/main/java/com/example/demo/ChatApplication.java |
Adds startup bootstrapping for roles and an admin user. |
pom.xml |
Adds Selenium + Kafka deps; enables resource filtering config. |
Dockerfile |
Adds multi-stage Docker build for the app jar. |
.github/workflows/docker.yml |
Adds a placeholder workflow (WIP). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <version>4.9.1</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.seleniumhq.selenium</groupId> | ||
| <artifactId>selenium-support</artifactId> | ||
| <version>4.9.1</version> |
There was a problem hiding this comment.
Selenium dependencies are added without <scope>test</scope>, which will package them into the production artifact unnecessarily and increase build size/supply-chain surface area. These should be test-scoped since they’re only used under src/test.
| <version>4.9.1</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.seleniumhq.selenium</groupId> | |
| <artifactId>selenium-support</artifactId> | |
| <version>4.9.1</version> | |
| <version>4.9.1</version> | |
| <scope>test</scope> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.seleniumhq.selenium</groupId> | |
| <artifactId>selenium-support</artifactId> | |
| <version>4.9.1</version> | |
| <scope>test</scope> |
| User admin = new User(); | ||
| admin.setUsername("admin"); | ||
| admin.setEmail("admin@localhost"); | ||
| admin.setPassword("111"); | ||
| userService.createAdmin(admin); |
There was a problem hiding this comment.
initAdminUserData bootstraps a default admin user with a hard-coded, weak password ("111"). This creates a predictable privileged account and is a critical security risk if it ever runs outside a local/dev environment. Gate this behind a dev profile, require credentials via environment variables/secrets, or remove automatic admin creation entirely.
| User admin = new User(); | |
| admin.setUsername("admin"); | |
| admin.setEmail("admin@localhost"); | |
| admin.setPassword("111"); | |
| userService.createAdmin(admin); | |
| String adminPassword = System.getenv("CHAT_ADMIN_INITIAL_PASSWORD"); | |
| if (adminPassword != null && !adminPassword.isBlank()) { | |
| User admin = new User(); | |
| admin.setUsername("admin"); | |
| admin.setEmail("admin@localhost"); | |
| admin.setPassword(adminPassword); | |
| userService.createAdmin(admin); | |
| } |
| CommandLineRunner initAdminUserData( | ||
| UserRepository userRepository, | ||
| UserService userService | ||
| ) { |
There was a problem hiding this comment.
The userRepository parameter is not used inside this CommandLineRunner bean. This adds noise and can confuse readers about intended behavior; remove the unused dependency (or use it if it was meant for the existence check).
| <head class="text-center"> | ||
| <title>Please Log In</title> | ||
| </head> |
There was a problem hiding this comment.
The HTML uses a <head> element inside the <body> to display the page title. This is invalid HTML and can cause inconsistent rendering. Use a semantic container element (e.g., header/div) for in-body headings; keep <head> only at the document root.
| @Test | ||
| void testLoginWithValidCredentials() { | ||
| try { | ||
| driver.get(LOGIN_PAGE_URL); | ||
|
|
||
| driver.findElement(By.id(EMAIL_INPUT_ID)).sendKeys(VALID_USER_EMAIL); | ||
| driver | ||
| .findElement(By.id(PASSWORD_INPUT_ID)) | ||
| .sendKeys(VALID_USER_PASSWORD); | ||
|
|
||
| driver.findElement(By.id(LOGIN_BUTTON_ID)).click(); | ||
|
|
||
| Thread.sleep(2000); | ||
|
|
||
| String expectedUrl = "http://localhost:" + PORT + "/index"; |
There was a problem hiding this comment.
These Selenium tests depend on an externally running server at http://localhost:8080 and use Thread.sleep(...) for timing, which makes the test suite brittle and likely to fail in CI (and slows local runs). Consider starting the Spring Boot app in the test (e.g., @SpringBootTest(webEnvironment=DEFINED_PORT/RANDOM_PORT)), using WebDriver waits instead of sleeps, and/or marking these as @Disabled or moving them to a separate profile/module so they don’t run on every mvn test.
| System.setProperty( | ||
| "webdriver.chrome.driver", | ||
| "/Users/joonwoolee/chromedriver_mac_arm64/chromedriver" | ||
| ); |
There was a problem hiding this comment.
The ChromeDriver path is hard-coded to a developer-specific absolute path, which will break for other contributors and CI runners. Make the driver location configurable or use a driver manager library instead of an absolute path.
| @Test | ||
| void testSendMessageInChatRoom() {} |
There was a problem hiding this comment.
testSendMessageInChatRoom is an empty @Test, so it will always pass without exercising any behavior. Either implement assertions for message sending, or mark it @Disabled/remove it to avoid giving a false sense of coverage.
| public UserDTO createUser(User user) { | ||
| if (userRepository.existsByEmail(user.getEmail())) { | ||
| throw new RuntimeException("Email already exists"); | ||
| } |
There was a problem hiding this comment.
createUser throws a raw RuntimeException when the email already exists. In the current flow (AuthController.submitForm), this will surface as a 500 error rather than a user-friendly validation message. Consider reporting this through BindingResult/UserValidator, or throw a typed exception that the controller maps to an appropriate response/view.
| leaveButton.addEventListener("click", callback); | ||
| } | ||
|
|
||
| export function eanbleTalkToButton() { |
There was a problem hiding this comment.
The exported function name eanbleTalkToButton is misspelled. This makes the API easy to misuse and hard to discover via autocomplete. Rename it to enableTalkToButton (and update any imports/usages accordingly).
| export function eanbleTalkToButton() { | |
| export function enableTalkToButton() { |
| get: (url) => { | ||
| return fetch(url) | ||
| .then((res) => { | ||
| if (res.ok) { | ||
| return res.json(); | ||
| } | ||
| }) |
There was a problem hiding this comment.
HTTPClient.get/post/delete return undefined when res.ok is false, without throwing. Callers then fail later (e.g., returnedChatRooms.forEach), and you lose the HTTP status/body context. Consider throwing on non-2xx responses (include res.status/res.statusText, and possibly response text) so callers can handle errors deterministically.
No description provided.