Skip to content

fix: optimize refresh logic to prevent redundant fetches #28

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

mlopezFC
Copy link
Member

@mlopezFC mlopezFC commented May 24, 2025

Previously, several setters in the RssItems component would trigger an immediate refresh of the RSS feed, leading to unnecessary network requests
and processing. Additionally, constructors could cause multiple refreshes.

This change optimizes the behavior by:

  • Removing direct calls to refreshUrl() from property setters.
  • Introducing a public refresh() method for manual control.
  • Ensuring setUrl() correctly triggers a refresh.
  • Modifying constructors to ensure the feed is refreshed only once.

Unit tests have been added to verify the new refresh behavior. The RssItems.java class was also refactored for better testability (protected no-arg constructor, changed visibility of some internal methods
and constants).

Closes #21

Summary by CodeRabbit

  • New Features
    • Added a public method to manually refresh RSS feeds.
  • Bug Fixes
    • Changing display settings (such as title or excerpt length) no longer automatically reloads the RSS feed; only URL changes or manual refresh do.
  • Tests
    • Introduced comprehensive automated tests to verify correct RSS feed refresh behavior.
  • Chores
    • Added a new testing library to improve test reliability.

Previously, several setters in the RssItems component would trigger an
immediate refresh of the RSS feed, leading to unnecessary network
requests
and processing. Additionally, constructors could cause multiple
refreshes.

This change optimizes the behavior by:
- Removing direct calls to `refreshUrl()` from property setters.
- Introducing a public `refresh()` method for manual control.
- Ensuring `setUrl()` correctly triggers a refresh.
- Modifying constructors to ensure the feed is refreshed only once.

Unit tests have been added to verify the new refresh behavior.
The `RssItems.java` class was also refactored for better testability
(protected no-arg constructor, changed visibility of some internal
methods
and constants).

Closes #21
@mlopezFC mlopezFC requested a review from javier-godoy May 24, 2025 21:11
Copy link

coderabbitai bot commented May 24, 2025

"""

Walkthrough

The changes introduce a test dependency on Mockito, adjust the visibility and refresh logic in the RssItems class, and add a comprehensive unit test. The refresh mechanism is deferred and scheduled before the next client response rather than called immediately by setters, with explicit refresh capability added. Several constants and methods are made more accessible.

Changes

Files/Paths Change Summary
pom.xml Added Mockito as a test-scoped dependency.
src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java Changed constant/method visibility, deferred refresh scheduling replacing immediate calls, added explicit refresh method, and a test constructor.
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java Added new JUnit test class with Mockito-based tests verifying deferred refresh scheduling and setter behavior.

Assessment against linked issues

Objective (Issue #) Addressed Explanation
Every call to a setter results in a call to refreshUrl (#21) Setters no longer call refreshUrl() directly but schedule a deferred refresh instead, so the objective is not met as stated.
"""
✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

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

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 generate sequence diagram to generate a sequence diagram of the changes in 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

@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: 4

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e4b6613 and d4a1e5e.

📒 Files selected for processing (3)
  • pom.xml (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java (6 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Java CI with Maven
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java

[error] 25-124: Compilation errors: cannot find symbol 'Element' class in package com.vaadin.flow.component; also cannot find symbol method 'argThat'. Multiple occurrences at lines 25, 36, 110, and 124.

🔇 Additional comments (10)
src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java (7)

57-79: LGTM! Constants made public for testing support.

Making these constants public enables their use in unit tests, which is appropriate for this refactoring.


114-118: LGTM! Protected constructor enables testing.

The protected no-argument constructor properly supports unit testing by allowing test frameworks to create instances without triggering immediate RSS fetches.


120-128: LGTM! Method visibility changed to support testing.

Making refreshUrl() protected allows for controlled testing while maintaining encapsulation from external callers.


130-132: LGTM! Protected visibility enables mocking in tests.

Making invokeXmlToItems() protected properly supports unit testing by allowing method stubbing.


134-147: LGTM! Protected visibility supports dependency injection in tests.

Making obtainRss() protected enables mocking HTTP calls in unit tests, which is essential for reliable testing.


161-183: LGTM! Property setters correctly decoupled from refresh logic.

The removal of refreshUrl() calls from these setters achieves the main objective of preventing redundant fetches when multiple properties are updated.


189-200: LGTM! Centralized refresh logic implemented correctly.

The changes successfully centralize refresh control:

  • setUrl() appropriately triggers refresh since URL changes require new data
  • New refresh() method provides manual control
  • This design prevents redundant fetches from property setters
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java (3)

42-60: LGTM! Test setup properly configured.

The test setup correctly:

  • Creates spy instances for controlled testing
  • Mocks Vaadin component dependencies
  • Stubs network calls to avoid external dependencies
  • Establishes baseline state for subsequent tests

62-88: LGTM! Property setter tests verify decoupled refresh logic.

These tests correctly verify that property setters (setMaxTitleLength, setMaxExcerptLength, setMax, setExtractImageFromDescription) do not trigger additional RSS fetches, confirming the successful decoupling of refresh logic.


90-103: LGTM! URL and refresh tests verify correct trigger behavior.

These tests properly verify that:

  • setUrl() triggers a new RSS fetch with the new URL
  • refresh() triggers an additional fetch with the current URL
  • Call counts are tracked accurately

Comment on lines 1 to 14
package com.flowingcode.vaadin.addons.rssitems;

import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add missing import for argThat matcher.

The argThat method used on line 124 requires an additional import.

Apply this diff to add the missing import:

 import static org.mockito.Mockito.verify;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
📝 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
package com.flowingcode.vaadin.addons.rssitems;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
package com.flowingcode.vaadin.addons.rssitems;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at the
beginning of the file (lines 1 to 14), add the missing import statement for the
Mockito argThat matcher. This requires adding 'import static
org.mockito.ArgumentMatchers.argThat;' among the existing static imports to
ensure the argThat method is recognized and can be used in the test code.

Copy link
Member

@javier-godoy javier-godoy left a comment

Choose a reason for hiding this comment

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

I have a couple of points I'd like to discuss regarding the current approach in this PR:

Breaking Change & Alternative Approach:
It appears these modifications introduce a breaking change for existing users. Specifically, if users were previously relying on automatic refreshes after certain operations (e.g., calling specific setters), they will now be required to explicitly call refresh() to update the feed. This is a significant shift in behavior that could lead to unexpected issues for users upgrading the addon if they aren't prepared for this new requirement.

This will likely necessitate clear documentation in release notes, migration guidance, and potentially a major version bump for the addon to signal this change.

On this note, I had previously proposed an alternative approach in issue #21 (comment) that aimed to address the refresh optimization without introducing a breaking change. Perhaps that approach, or elements of it, could be revisited as a way to achieve the optimization goals while maintaining backward compatibility?

Member Visibility for Testing:
I also noticed that some members which were previously private seem to have been made public (or package-private) primarily to facilitate testing. While this can make it easier to test internal state, it does have a few potential downsides, such as:

Increasing the public API surface beyond what's intended for regular use, which can weaken encapsulation.
Coupling tests more tightly to internal implementation details, potentially making future refactoring of the class internals more brittle.
Would it be feasible to achieve the desired test coverage by focusing on testing through the component's existing public API? If direct testing of internal logic is essential, perhaps alternatives like dependency injection or using package-private helper/test classes could be explored to avoid altering the visibility of core component members.

Commit message:
Two minor suggestions regarding the commit message associated with this PR:

  • The commit message contains Markdown formatting and arbitrary line breaks.
  • It seems this change would best fit the perf type.

I'm raising these points to ensure the addon remains as robust and user-friendly as possible. Happy to discuss these further!

Thanks!

Addresses feedback from PR #28 (especially from javier-godoy)
regarding breaking changes and member visibility.

Key changes:
- I replaced immediate refresh calls in setters with a debounced mechanism
  using `UI.beforeClientResponse()`. This ensures that multiple property
  changes within a single request cycle result in only one RSS feed fetch,
  maintaining the original non-breaking behavior for you.
- The `setUrl()` method now also uses this debounced refresh.
- The public `refresh()` method now cancels any pending scheduled refresh
  and triggers an immediate fetch.
- Constructors correctly leverage the debounced refresh via setters,
  resulting in a single fetch after initialization.
- I reviewed member visibility: `refreshUrl()` and `invokeXmlToItems()` are
  now `private`. `obtainRss()` remains `protected` for test mocking.
  Constants remain `public static final`.
- I significantly updated unit tests in `RssItemsTest.java` to:
    - Use static mocking for `UI.getCurrent()`.
    - Capture and execute the `SerializableConsumer` from
      `beforeClientResponse`.
    - Verify the debounced refresh logic for setters, `setUrl`, and
      constructors.
    - Verify the immediate refresh logic for the public `refresh()` method,
      including cancellation of pending refreshes.

This approach optimizes performance by preventing redundant fetches while
avoiding the breaking change introduced in the previous iteration.

Closes #21
Copy link

Copy link

@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

♻️ Duplicate comments (1)
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java (1)

31-31: Fix Element import - use correct Vaadin Element class.

The current import is correct, but based on pipeline failures, the Element class from com.vaadin.flow.dom doesn't have a getUI() method.

This issue was already identified in previous reviews.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d4a1e5e and 20fd9b1.

📒 Files selected for processing (3)
  • pom.xml (1 hunks)
  • src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java (10 hunks)
  • src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pom.xml
  • src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java
🧰 Additional context used
🪛 GitHub Actions: Java CI with Maven
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java

[error] 65-65: Compilation error: cannot find symbol method getUI() in variable elementMock of type com.vaadin.flow.dom.Element


[error] 71-71: Compilation error: invokeXmlToItems(java.lang.String) has private access in com.flowingcode.vaadin.addons.rssitems.RssItems


[error] 78-78: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 111-111: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 157-160: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 173-173: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 189-189: Compilation error: cannot find symbol class ExecutionRegistration in class com.flowingcode.vaadin.addons.rssitems.RssItemsTest


[error] 190-190: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 216-216: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 224-224: Compilation error: cannot find symbol method getUI() in variable localElementMock of type com.vaadin.flow.dom.Element


[error] 229-229: Compilation error: invokeXmlToItems(java.lang.String) has private access in com.flowingcode.vaadin.addons.rssitems.RssItems

🔇 Additional comments (2)
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java (2)

117-251:

❌ Incorrect review comment

Improve test structure and add missing imports.

The tests are well-structured and comprehensive, but several critical compilation issues need to be resolved. Consider adding the missing static import mentioned in past reviews.

Add the missing import for argThat:

 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;

The test logic is sound and properly verifies the deferred refresh scheduling mechanism, but the type mismatches and method access issues must be fixed first.


🏁 Script executed:

#!/bin/bash
rg 'argThat' -n src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java || echo "No argThat usage found"

Length of output: 141


Remove unnecessary argThat import suggestion – no argThat usage detected

I searched the test file and found no references to argThat, so adding its static import isn’t required. The existing imports in RssItemsTest.java already cover all used matchers.

Likely an incorrect or invalid review comment.

🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 157-160: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 173-173: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 189-189: Compilation error: cannot find symbol class ExecutionRegistration in class com.flowingcode.vaadin.addons.rssitems.RssItemsTest


[error] 190-190: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 216-216: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>


[error] 224-224: Compilation error: cannot find symbol method getUI() in variable localElementMock of type com.vaadin.flow.dom.Element


[error] 229-229: Compilation error: invokeXmlToItems(java.lang.String) has private access in com.flowingcode.vaadin.addons.rssitems.RssItems


229-229:

❓ Verification inconclusive

Fix private method access issue.

Same issue as line 71 - invokeXmlToItems has private access.

This suggests the method visibility wasn't changed as mentioned in the PR summary, or the test is trying to access the wrong method.


🏁 Script executed:

#!/bin/bash
# Check if there are any protected or package-private methods for XML processing in RssItems
ast-grep --pattern 'protected $_ invokeXmlToItems($_) {
  $$$
}'

ast-grep --pattern '$_ invokeXmlToItems($_) {
  $$$
}' | head -5

Length of output: 133


#!/bin/bash
# Locate all occurrences of invokeXmlToItems to inspect its visibility and signature
rg -n "invokeXmlToItems" -g "*.java"

#!/bin/bash
# Search for all definitions and usages of invokeXmlToItems in Java source and test files
rg -n "invokeXmlToItems" -g "src/**/*.java"

#!/bin/bash
# Inspect invokeXmlToItems in both production and test code to confirm its visibility
echo "=== Production sources ==="
rg -n "invokeXmlToItems" -g "src/main/java/**/*.java" -C3 || true
echo "=== Test sources ==="
rg -n "invokeXmlToItems" -g "src/test/java/**/*.java" -C3 -C3 || true

Verify private method access in RssItems
The test at src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java:229 is stubbing invokeXmlToItems(anyString()), but that method remains private in RssItems. As noted in the PR summary, its visibility should be relaxed—or the test should use a supported way to stub private methods (e.g. PowerMockito’s when(spy, "invokeXmlToItems", …)) or validate behavior via the public API instead.

Points to confirm:

  • RssItems.invokeXmlToItems(...) is declared as protected or package-private
  • Test uses a compatible stubbing approach for private methods or avoids direct stubbing

Please verify and update the code or test accordingly.

🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 229-229: Compilation error: invokeXmlToItems(java.lang.String) has private access in com.flowingcode.vaadin.addons.rssitems.RssItems

Comment on lines +52 to +53
@Mock
private StateTree.ExecutionRegistration mockExecutionRegistration;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ExecutionRegistration import.

The StateTree.ExecutionRegistration class reference is incorrect based on the pipeline failure.

+import com.vaadin.flow.internal.StateTree.ExecutionRegistration;

And update the field declaration:

-    @Mock
-    private StateTree.ExecutionRegistration mockExecutionRegistration;
+    @Mock
+    private ExecutionRegistration mockExecutionRegistration;
📝 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
@Mock
private StateTree.ExecutionRegistration mockExecutionRegistration;
// … other imports …
+import com.vaadin.flow.internal.StateTree.ExecutionRegistration;
public class RssItemsTest {
@Mock
- private StateTree.ExecutionRegistration mockExecutionRegistration;
+ private ExecutionRegistration mockExecutionRegistration;
// … rest of the test class …
}
🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java around
lines 52 to 53, the import for StateTree.ExecutionRegistration is incorrect and
causing pipeline failures. Correct the import statement to reference the proper
ExecutionRegistration class from the correct package. Then update the field
declaration to use the corrected class reference accordingly.

runLastScheduledRefresh(consumerCaptor); // Run refresh from initial setUrl
Mockito.clearInvocations(rssItemsSpy, uiMock, mockExecutionRegistration);

ExecutionRegistration localSpecificMockRegistration = mock(StateTree.ExecutionRegistration.class);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ExecutionRegistration class reference.

Use the correct import for ExecutionRegistration.

-        ExecutionRegistration localSpecificMockRegistration = mock(StateTree.ExecutionRegistration.class);
+        ExecutionRegistration localSpecificMockRegistration = mock(ExecutionRegistration.class);
📝 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
ExecutionRegistration localSpecificMockRegistration = mock(StateTree.ExecutionRegistration.class);
ExecutionRegistration localSpecificMockRegistration = mock(ExecutionRegistration.class);
🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 189-189: Compilation error: cannot find symbol class ExecutionRegistration in class com.flowingcode.vaadin.addons.rssitems.RssItemsTest

🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at
line 189, the class ExecutionRegistration is referenced incorrectly. Update the
import statements to use the correct ExecutionRegistration class from the
appropriate package to ensure the mock creation works as intended.

verify(constructorTestSpy, never()).obtainRss(anyString());

if (!ctorConsumerCaptor.getAllValues().isEmpty()) {
ctorConsumerCaptor.getValue().accept(localConstructorUiMock);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix consumer execution parameter.

The consumer should accept ExecutionContext, not UI.

-                ctorConsumerCaptor.getValue().accept(localConstructorUiMock);
+                ctorConsumerCaptor.getValue().accept(mock(ExecutionContext.class));
📝 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
ctorConsumerCaptor.getValue().accept(localConstructorUiMock);
ctorConsumerCaptor.getValue().accept(mock(ExecutionContext.class));
🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at
line 245, the consumer is incorrectly called with a UI parameter. Change the
argument passed to the consumer's accept method to be an ExecutionContext
instance instead of localConstructorUiMock, ensuring the consumer receives the
correct parameter type.

when(elementMock.setProperty(anyString(), anyBoolean())).thenReturn(elementMock);
when(elementMock.setProperty(anyString(), anyInt())).thenReturn(elementMock);

doNothing().when(rssItemsSpy).invokeXmlToItems(anyString());
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Fix method visibility issue.

The invokeXmlToItems method has private access and cannot be mocked directly.

Based on the PR summary mentioning that method visibility was changed for testability, this method should now be protected. Verify the actual visibility in the main class.


🏁 Script executed:

#!/bin/bash
# Check the visibility of invokeXmlToItems method in RssItems class
ast-grep --pattern 'invokeXmlToItems($_) {
  $$$
}'

Length of output: 53


🏁 Script executed:

#!/bin/bash
# Search for invokeXmlToItems usage and definition across the codebase
rg -n "invokeXmlToItems" -C3

Length of output: 3322


Incorrect method visibility in RssItems.java

The invokeXmlToItems(String) method is still declared as private in src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java (line 170), so Mockito cannot stub it on a spy. You’ll need to:

  • Change its visibility to protected (or package‐private) to allow doNothing().when(rssItemsSpy).invokeXmlToItems(...) in your tests.
  • Or, if you must keep it private, switch to a framework that supports private‐method stubbing (e.g. PowerMock).

Please update the method declaration and adjust tests accordingly.

🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 71-71: Compilation error: invokeXmlToItems(java.lang.String) has private access in com.flowingcode.vaadin.addons.rssitems.RssItems

🤖 Prompt for AI Agents
In src/main/java/com/flowingcode/vaadin/addons/rssitems/RssItems.java at line
170, change the visibility of the method invokeXmlToItems(String) from private
to protected or package-private to allow Mockito to stub it in tests. Then, in
src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java around
line 71, keep the doNothing().when(rssItemsSpy).invokeXmlToItems(anyString())
call as is, since the method is now accessible for mocking. Alternatively, if
you must keep the method private, switch to a mocking framework that supports
private method stubbing like PowerMock and update the test accordingly.

UI localConstructorUiMock = mock(UI.class, Answers.RETURNS_DEEP_STUBS);
staticUiForCtor.when(UI::getCurrent).thenReturn(localConstructorUiMock);

ArgumentCaptor<SerializableConsumer<UI>> ctorConsumerCaptor = ArgumentCaptor.forClass(SerializableConsumer.class);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ArgumentCaptor type parameter.

Same issue with SerializableConsumer type parameter.

-            ArgumentCaptor<SerializableConsumer<UI>> ctorConsumerCaptor = ArgumentCaptor.forClass(SerializableConsumer.class);
+            ArgumentCaptor<SerializableConsumer<ExecutionContext>> ctorConsumerCaptor = ArgumentCaptor.forClass(SerializableConsumer.class);
📝 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
ArgumentCaptor<SerializableConsumer<UI>> ctorConsumerCaptor = ArgumentCaptor.forClass(SerializableConsumer.class);
- ArgumentCaptor<SerializableConsumer<UI>> ctorConsumerCaptor = ArgumentCaptor.forClass(SerializableConsumer.class);
+ ArgumentCaptor<SerializableConsumer<ExecutionContext>> ctorConsumerCaptor = ArgumentCaptor.forClass(SerializableConsumer.class);
🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at
line 214, the ArgumentCaptor is declared without the proper generic type
parameter for SerializableConsumer. Fix this by specifying the correct generic
type parameter for SerializableConsumer in the ArgumentCaptor declaration to
ensure type safety and avoid unchecked assignment warnings.

Comment on lines +96 to +100
private void runLastScheduledRefresh(ArgumentCaptor<SerializableConsumer<UI>> captor) {
if (!captor.getAllValues().isEmpty()) {
captor.getValue().accept(uiMock);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix consumer parameter type in helper method.

The parameter type needs to match the corrected ExecutionContext type.

-    private void runLastScheduledRefresh(ArgumentCaptor<SerializableConsumer<UI>> captor) {
+    private void runLastScheduledRefresh(ArgumentCaptor<SerializableConsumer<ExecutionContext>> captor) {
         if (!captor.getAllValues().isEmpty()) {
-             captor.getValue().accept(uiMock); 
+             captor.getValue().accept(mock(ExecutionContext.class)); 
         }
     }
📝 Committable suggestion

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

Suggested change
private void runLastScheduledRefresh(ArgumentCaptor<SerializableConsumer<UI>> captor) {
if (!captor.getAllValues().isEmpty()) {
captor.getValue().accept(uiMock);
}
}
private void runLastScheduledRefresh(ArgumentCaptor<SerializableConsumer<ExecutionContext>> captor) {
if (!captor.getAllValues().isEmpty()) {
captor.getValue().accept(mock(ExecutionContext.class));
}
}
🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java around
lines 96 to 100, the helper method runLastScheduledRefresh has a parameter type
ArgumentCaptor<SerializableConsumer<UI>> that does not match the corrected
ExecutionContext type. Update the parameter type to
ArgumentCaptor<SerializableConsumer<ExecutionContext>> to align with the
corrected type usage throughout the code.


Element localElementMock = mock(Element.class);
when(constructorTestSpy.getElement()).thenReturn(localElementMock);
when(localElementMock.getUI()).thenReturn(Optional.of(localConstructorUiMock));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix Element getUI() method call.

Same issue as line 65 - Element doesn't have getUI() method.

-            when(localElementMock.getUI()).thenReturn(Optional.of(localConstructorUiMock)); 
+            when(constructorTestSpy.getUI()).thenReturn(Optional.of(localConstructorUiMock));
📝 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
when(localElementMock.getUI()).thenReturn(Optional.of(localConstructorUiMock));
when(constructorTestSpy.getUI()).thenReturn(Optional.of(localConstructorUiMock));
🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 224-224: Compilation error: cannot find symbol method getUI() in variable localElementMock of type com.vaadin.flow.dom.Element

🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at
line 224, the call to localElementMock.getUI() is incorrect because the Element
class does not have a getUI() method. Replace this call with the correct method
or approach used at line 65 to obtain the UI instance from the Element mock,
ensuring consistency and correctness in mocking the UI retrieval.

Comment on lines +78 to +79
when(uiMock.beforeClientResponse(any(RssItems.class), consumerCaptor.capture()))
.thenReturn(mockExecutionRegistration);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix beforeClientResponse parameter type.

The SerializableConsumer<UI> type is incompatible with the method signature.

-        when(uiMock.beforeClientResponse(any(RssItems.class), consumerCaptor.capture()))
+        when(uiMock.beforeClientResponse(any(Component.class), consumerCaptor.capture()))

And update the captor parameter type as mentioned in the earlier comment.

📝 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
when(uiMock.beforeClientResponse(any(RssItems.class), consumerCaptor.capture()))
.thenReturn(mockExecutionRegistration);
when(uiMock.beforeClientResponse(any(Component.class), consumerCaptor.capture()))
.thenReturn(mockExecutionRegistration);
🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 78-78: Compilation error: incompatible types - com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.component.UI> cannot be converted to com.vaadin.flow.function.SerializableConsumer<com.vaadin.flow.internal.ExecutionContext>

🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java around
lines 78 to 79, the parameter type passed to beforeClientResponse is incorrect
because it expects a SerializableConsumer<UI> but currently receives a different
type. Change the argument type to match SerializableConsumer<UI> and update the
consumerCaptor's generic type accordingly to capture SerializableConsumer<UI>
instances.

rssItemsSpy = spy(realRssItems);

when(rssItemsSpy.getElement()).thenReturn(elementMock);
when(elementMock.getUI()).thenReturn(Optional.of(uiMock));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix Element mock configuration.

The Element class from com.vaadin.flow.dom doesn't have a getUI() method. You need to mock the component's getUI() method instead.

-        when(elementMock.getUI()).thenReturn(Optional.of(uiMock));
+        when(rssItemsSpy.getUI()).thenReturn(Optional.of(uiMock));
📝 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
when(elementMock.getUI()).thenReturn(Optional.of(uiMock));
- when(elementMock.getUI()).thenReturn(Optional.of(uiMock));
+ when(rssItemsSpy.getUI()).thenReturn(Optional.of(uiMock));
🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 65-65: Compilation error: cannot find symbol method getUI() in variable elementMock of type com.vaadin.flow.dom.Element

🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at
line 65, the mock setup incorrectly calls getUI() on an Element instance, which
does not have this method. Change the mock configuration to call getUI() on the
component mock instead of the element mock, ensuring the correct object is
stubbed for getUI() to return the expected Optional of UI.

Comment on lines +49 to +50
@Captor
private ArgumentCaptor<SerializableConsumer<UI>> consumerCaptor;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix SerializableConsumer type parameter.

The SerializableConsumer<UI> type is incompatible with what UI.beforeClientResponse() expects. Based on pipeline failures, it should be SerializableConsumer<ExecutionContext>.

-    @Captor
-    private ArgumentCaptor<SerializableConsumer<UI>> consumerCaptor;
+    @Captor  
+    private ArgumentCaptor<SerializableConsumer<ExecutionContext>> consumerCaptor;

Also add the missing import:

+import com.vaadin.flow.internal.ExecutionContext;
📝 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
@Captor
private ArgumentCaptor<SerializableConsumer<UI>> consumerCaptor;
// At the top of the file, alongside your other imports:
import com.vaadin.flow.internal.ExecutionContext;
@Captor
private ArgumentCaptor<SerializableConsumer<ExecutionContext>> consumerCaptor;
🤖 Prompt for AI Agents
In src/test/java/com/flowingcode/vaadin/addons/rssitems/RssItemsTest.java at
lines 49-50, the ArgumentCaptor is declared with the wrong generic type
SerializableConsumer<UI>, which is incompatible with UI.beforeClientResponse().
Change the type parameter to SerializableConsumer<ExecutionContext> to match the
expected type. Also, add the missing import statement for ExecutionContext to
resolve compilation errors.

Copy link
Member

@javier-godoy javier-godoy left a comment

Choose a reason for hiding this comment

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

This is a partial review, since there are substantial observation in the proposed implementation.

The following is just feedback on the quality of the solution provided by Jules, and how it adheres to our current conventions:

  • CodeRabbit. The developer will handle comments generated by automatic tools (e.g., CodeRabbit) just as they would handle comments from human reviewers (from addons/pr-process.md).

  • Member visibility for testing. We don't have a policy of polluting the API "just for testing purposes". Such changes require project-level discussion and approval.

  • Commit granularity. See https://github.com/FlowingCode/TechnicalDocs/blob/master/addons/pr-process.md#workflow-for-commits-in-all-pull-requests

  • Commit messages. Ensure commit messages comply with the Flowing Code Commit Message Guidelines. The following prompt may be useful, but you may have to rebase yourself:

    • The commit message must be perf: phrase in imperative
    • There must be a lowercase after the colon
    • There must be no (scope) after perf
    • The commit message must not contain Markdown formatting

@@ -117,7 +121,43 @@ public RssItems(String url) {
protected RssItems() {
}

protected void refreshUrl() {
private void scheduleRefresh() {
UI ui = UI.getCurrent();
Copy link
Member

Choose a reason for hiding this comment

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

  • The check is not where there is a current UI, but whether the component is attached (refreshUrl calls invokeXmlToItems which calls this.getElement().executeJs which requires the element to be attached).
  • If the component is not attached, scheduleRefresh will do nothing.
  • Call scheduleRefresh on attach.


// Schedule refreshUrl to be called before the client response.
// The lambda uiParam -> refreshUrl() is used because the consumer takes the UI as a parameter.
pendingRefreshRegistration = ui.beforeClientResponse(this, uiParam -> refreshUrl());
Copy link
Member

Choose a reason for hiding this comment

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

Schedule in the UI to which the component is attached.

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.

Every call to a setter results in a call to refreshUrl
2 participants