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

Smart sync Action Playwright support #4044

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

Conversation

GokulBothe99
Copy link
Contributor

@GokulBothe99 GokulBothe99 commented Dec 26, 2024

Thank you for your contribution.
Before submitting this PR, please make sure:

  • PR description and commit message should describe the changes done in this PR
  • Verify the PR is pointing to correct branch i.e. Release or Beta branch if the code fix is for specific release , else point it to master
  • Latest Code from master or specific release branch is merged to your branch
  • No unwanted\commented\junk code is included
  • No new warning upon build solution
  • Code Summary\Comments are added to my code which explains what my code is doing
  • Existing unit test cases are passed
  • New Unit tests are added for your development
  • Sanity Tests are successfully executed for New and Existing Functionality
  • Verify that changes are compatible with all relevant browsers and platforms.
  • After creating pull request there should not be any conflicts
  • Resolve all Codacy comments
  • Builds and checks are passed before PR is sent for review
  • Resolve code review comments
  • Update the Help Library document to match any feature changes

Summary by CodeRabbit

  • New Features

    • Introduced smart synchronization handling for web elements.
    • Enhanced PlaywrightDriver to support smart synchronization actions.
  • Bug Fixes

    • Improved error handling for unsupported actions in PlaywrightDriver.
    • Enhanced error handling for custom locator processing in DriverBase.
  • Documentation

    • Updated method visibility for better accessibility in DriverBase.
  • Chores

    • Updated regex declarations in DriverBase for improved syntax.

Copy link
Contributor

coderabbitai bot commented Dec 26, 2024

Walkthrough

This pull request introduces a new ActSmartSyncHandler class to manage smart synchronization actions for web elements asynchronously. The changes enhance the Playwright driver's capabilities by adding support for ActSmartSync actions and updating the DriverBase class with improved method visibility and error handling. The implementation allows for checking element visibility and existence with configurable timeouts, refining the synchronization mechanism for web automation.

Changes

File Change Summary
Ginger/.../ActSmartSyncHandler.cs New class added to handle smart synchronization actions with async methods for element retrieval and synchronization.
Ginger/.../Playwright/PlaywrightDriver.cs Updated RunAction and IsActionSupported methods to include ActSmartSync action handling.
Ginger/.../DriverBase.cs Modified GetMaxTimeout method visibility to public, updated regex declarations, and improved error handling in locator processing.

Possibly related PRs

Suggested reviewers

  • Maheshkale447

Poem

🐰 Sync, wait, and see,
A rabbit's web automation glee!
Elements dance to our command,
Playwright's magic at hand,
Smart actions, smooth as can be! 🕸️


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. (Beta)
  • @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 or @coderabbitai title 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: 0

🧹 Nitpick comments (7)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (6)

10-16: Consider clarifying comment or renaming private fields.
Your constructor sets internal fields _actSmartSync, _browserTab, and _elementLocator. It might be clearer to rename these fields or add short doc comments that indicate their purpose and responsibilities.


40-53: Address possible race condition when element becomes unavailable.
In the WaitUntilDisplay loop, you repeatedly retrieve the element and check IsVisibleAsync() and IsEnabledAsync(). If the element is removed between these checks, you could see unexpected exceptions or incomplete waits. Consider handling the scenario where the element might disappear mid-loop.


45-49: Improve error specificity.
When the timeout is exceeded, the error message is quite generic. Consider expanding the message or providing more contextual information (e.g., the locator used) to help troubleshoot.


52-52: Use short-circuit evaluation.
The conditions element == null || !await element.IsVisibleAsync() || !await element.IsEnabledAsync() are checked every cycle. You might consider evaluating each separately to clarify which condition failed.


55-67: Typo in WaitUntilDisapear.
Recommend renaming WaitUntilDisapear to WaitUntilDisappear to match standard spelling and improve readability.

-case ActSmartSync.eSmartSyncAction.WaitUntilDisapear:
+case ActSmartSync.eSmartSyncAction.WaitUntilDisappear:

79-84: Potential performance optimization via caching.
GetFirstMatchingElementAsync() fetches all matching elements and returns only the first one. If you frequently need only the first match, consider adding a dedicated FindFirstElementAsync() method to the IBrowserElementLocator interface to avoid fetching all.

Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)

254-268: Be mindful of synchronous blocking while calling asynchronous APIs.
Wrapping everything in Task.Run(...).Wait() can create thread-pool consumption or potential deadlocks, especially if called in certain synchronization contexts. This approach is acceptable if you must maintain a synchronous RunAction as per your codebase constraints, but consider documenting these implications.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b521e50 and f748983.

📒 Files selected for processing (3)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (1 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (2 hunks)
  • Ginger/GingerCoreNET/RunLib/DriverBase.cs (2 hunks)
🧰 Additional context used
📓 Learnings (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#3783
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs:129-129
Timestamp: 2024-11-12T02:45:14.501Z
Learning: User IamRanjeetSingh has indicated that the `RunAction` method in the `PlaywrightDriver` class should remain synchronous due to current constraints in the codebase.
🔇 Additional comments (4)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (1)

29-33: Validate or handle negative timeouts.
Before starting the synchronization loop, consider validating that MaxTimeout is non-negative; otherwise, you may want to bail early or handle it as an error.

Ginger/GingerCoreNET/RunLib/DriverBase.cs (2)

303-304: Good use of compiled Regex.
Using RegexOptions.Compiled is beneficial for performance, especially if you rely on these regexes heavily and repeatedly.


382-382: Validate default wait time alignment.
The GetMaxTimeout method defaults to 5 seconds if none is provided. Ensure that 5 seconds aligns with your driver or environment defaults (some test frameworks use 30 seconds by default). If there's a mismatch, it could cause unexpected action timeouts.

Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)

280-280: Good approach to broaden support for additional actions.
Adding ActSmartSync to the supported actions ensures the driver handles new synchronization logic. Be sure to maintain alignment with any future ActSmartSync updates or new actions requiring special validation.

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

🧹 Nitpick comments (2)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (2)

12-15: Maintain consistent naming conventions for private fields

The field mAct uses a different naming convention (Hungarian notation) compared to other private fields which use underscore prefix. Consider renaming it to _act for consistency.

-        private Act mAct;
+        private Act _act;

76-81: Simplify GetFirstMatchingElementAsync method

The method can be simplified by removing the intermediate variable and directly returning the result of FirstOrDefault().

 private async Task<IBrowserElement> GetFirstMatchingElementAsync()
 {
-    IEnumerable<IBrowserElement> elements = await _elementLocator.FindMatchingElements(mAct.LocateBy, mAct.LocateValue);
-    IBrowserElement? firstElement = elements.FirstOrDefault();
-    return firstElement;
+    return (await _elementLocator.FindMatchingElements(_act.LocateBy, _act.LocateValue)).FirstOrDefault();
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f748983 and 86e1aa4.

📒 Files selected for processing (1)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (1 hunks)
🔇 Additional comments (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (1)

10-10: Verify integration with PlaywrightDriver

Let's verify how this handler is integrated with PlaywrightDriver.

✅ Verification successful

Let me gather more context about the integration.


Let me check the ActSmartSync class and handler implementation.


Integration with PlaywrightDriver is properly implemented

The verification shows that ActSmartSyncHandler is correctly integrated:

  • It's properly instantiated in PlaywrightDriver with required dependencies (browser tab and element locator)
  • The class is internal which matches its usage scope within the Web drivers
  • It's part of the action handling system alongside other handlers like accessibility testing
  • The implementation follows the same pattern as other action handlers in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of ActSmartSyncHandler in PlaywrightDriver
rg -A 5 "ActSmartSyncHandler" "Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/"

Length of output: 878


Script:

#!/bin/bash
# Get the context around the usage
rg -B 10 -A 10 "ActSmartSyncHandler" "Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs"

# Check the implementation of ActSmartSync
ast-grep --pattern 'class ActSmartSync {
  $$$
}'

Length of output: 7265


Script:

#!/bin/bash
# Find ActSmartSync class definition
rg -B 5 -A 10 "class ActSmartSync" 

# Find ActSmartSyncHandler implementation
rg -B 5 -A 10 "class ActSmartSyncHandler" "Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/"

Length of output: 7064

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: 1

🧹 Nitpick comments (3)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (2)

30-34: Standardize field naming convention

The field mAct doesn't follow the same naming convention as other fields which use the underscore prefix. Consider renaming for consistency.

-        private Act mAct;
+        private Act _act;

96-101: Simplify element retrieval logic

The FirstOrDefault() call is redundant as the elements are already enumerable.

         private async Task<IBrowserElement> GetFirstMatchingElementAsync()
         {
             IEnumerable<IBrowserElement> elements = await _elementLocator.FindMatchingElements(mAct.LocateBy, mAct.LocateValue);
-            IBrowserElement? firstElement = elements.FirstOrDefault();
-            return firstElement;
+            return elements.FirstOrDefault();
         }
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)

269-286: Improve timeout handling

The timeout handling could be improved:

  1. Store the original timeout before modification
  2. Ensure timeout is always restored in finally block
  3. Use TimeSpan for clearer time unit handling
-            float? driverDefaultTimeout = browserOptions.Timeout;
+            var originalTimeout = browserOptions.Timeout;
             try
             {
-                int smartSyncTimeout = DriverBase.GetMaxTimeout(actSmartSync) * 1000;
-                if (smartSyncTimeout != browserOptions.Timeout)
+                var smartSyncTimeout = TimeSpan.FromSeconds(DriverBase.GetMaxTimeout(actSmartSync));
+                var timeoutMilliseconds = (int)smartSyncTimeout.TotalMilliseconds;
+                if (timeoutMilliseconds != browserOptions.Timeout)
                 {
-                    browserOptions.Timeout = smartSyncTimeout;
+                    browserOptions.Timeout = timeoutMilliseconds;
                 }
-                actSmartSyncHandler.HandleAsync(act, smartSyncTimeout).Wait();
+                actSmartSyncHandler.HandleAsync(act, timeoutMilliseconds).Wait();
             }
             catch (Exception ex)
             {
                 act.Error = ex.Message;
             }
             finally
             {
-                browserOptions.Timeout = driverDefaultTimeout;
+                browserOptions.Timeout = originalTimeout;
             }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 86e1aa4 and c161a9c.

📒 Files selected for processing (2)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (1 hunks)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (4 hunks)
🧰 Additional context used
📓 Learnings (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#3783
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs:129-129
Timestamp: 2024-11-12T02:45:14.501Z
Learning: User IamRanjeetSingh has indicated that the `RunAction` method in the `PlaywrightDriver` class should remain synchronous due to current constraints in the codebase.
🔇 Additional comments (3)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/ActionHandlers/ActSmartSyncHandler.cs (2)

35-40: 🛠️ Refactor suggestion

Add parameter validation in constructor

The constructor should validate input parameters to prevent null reference exceptions.

 internal ActSmartSyncHandler(ActSmartSync actSmartSync, IBrowserTab browserTab, IBrowserElementLocator elementLocator)
 {
+    ArgumentNullException.ThrowIfNull(actSmartSync);
+    ArgumentNullException.ThrowIfNull(browserTab);
+    ArgumentNullException.ThrowIfNull(elementLocator);
+
     _actSmartSync = actSmartSync;
     _browserTab = browserTab;
     _elementLocator = elementLocator;
 }

Likely invalid or redundant comment.


47-91: 🛠️ Refactor suggestion

Refactor duplicate timeout logic and add cancellation support

The timeout and delay logic is duplicated between the two sync actions. Consider:

  1. Extracting common timeout logic
  2. Adding cancellation support
  3. Making the delay interval configurable
+        private const int DEFAULT_POLLING_INTERVAL = 100; // milliseconds
+
+        internal async Task HandleAsync(Act act, CancellationToken cancellationToken = default)
         {
-            mAct = act;
+            _act = act;
-            Stopwatch st = new Stopwatch();
+            var stopwatch = Stopwatch.StartNew();
             try
             {
-                st.Start();
                 IBrowserElement element;
+                var pollingInterval = TimeSpan.FromMilliseconds(DEFAULT_POLLING_INTERVAL);
 
                 if (_actSmartSync.SmartSyncAction == ActSmartSync.eSmartSyncAction.WaitUntilDisplay)
                 {
                     do
                     {
-                        if (st.ElapsedMilliseconds > timeout)
+                        cancellationToken.ThrowIfCancellationRequested();
+                        if (stopwatch.ElapsedMilliseconds > timeout)
                         {
-                            mAct.Error = "Smart Sync of WaitUntilDisplay is timeout";
+                            _act.Error = "Smart Sync of WaitUntilDisplay timed out";
                             break;
                         }
-                        await Task.Delay(100);
+                        await Task.Delay(pollingInterval, cancellationToken);
                         element = await GetFirstMatchingElementAsync();
                     } while (element == null || !await element.IsVisibleAsync() || !await element.IsEnabledAsync());
                 }
                 else if (_actSmartSync.SmartSyncAction == ActSmartSync.eSmartSyncAction.WaitUntilDisapear)
                 {
                     do
                     {
-                        if (st.ElapsedMilliseconds > timeout)
+                        cancellationToken.ThrowIfCancellationRequested();
+                        if (stopwatch.ElapsedMilliseconds > timeout)
                         {
-                            mAct.Error = "Smart Sync of WaitUntilDisapear is timeout";
+                            _act.Error = "Smart Sync of WaitUntilDisappear timed out";
                             break;
                         }
-                        await Task.Delay(100);
+                        await Task.Delay(pollingInterval, cancellationToken);
                         element = await GetFirstMatchingElementAsync();
                     } while (element != null);
                 }
             }

Likely invalid or redundant comment.

Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)

299-299: LGTM: ActSmartSync support added to IsActionSupported

The addition of ActSmartSync to the supported actions list is correct.

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: 0

🧹 Nitpick comments (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)

269-283: Enhance timeout handling and error handling

Consider the following improvements:

  1. Document the milliseconds conversion for better maintainability
  2. Use more specific exception handling to provide better error messages
 float? driverDefaultTimeout = browserOptions.Timeout;
 try
 {
-    int smartSyncTimeout = DriverBase.GetMaxTimeout(actSmartSync) * 1000;
+    // Convert timeout from seconds to milliseconds
+    int smartSyncTimeout = DriverBase.GetMaxTimeout(actSmartSync) * 1000;
     browserOptions.Timeout = smartSyncTimeout;
     actSmartSyncHandler.HandleAsync(act, smartSyncTimeout).Wait();
 }
-catch (Exception ex)
+catch (AggregateException ex) when (ex.InnerException != null)
 {
-    act.Error = ex.Message;
+    act.Error = $"Smart sync action failed: {ex.InnerException.Message}";
+}
+catch (Exception ex)
+{
+    act.Error = $"Unexpected error during smart sync: {ex.Message}";
 }
 finally
 {
     browserOptions.Timeout = driverDefaultTimeout;
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c161a9c and cad2dff.

📒 Files selected for processing (1)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (4 hunks)
🧰 Additional context used
📓 Learnings (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (1)
Learnt from: IamRanjeetSingh
PR: Ginger-Automation/Ginger#3783
File: Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs:129-129
Timestamp: 2024-11-12T02:45:14.501Z
Learning: User IamRanjeetSingh has indicated that the `RunAction` method in the `PlaywrightDriver` class should remain synchronous due to current constraints in the codebase.
🔇 Additional comments (3)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Playwright/PlaywrightDriver.cs (3)

34-34: LGTM!

The added import is necessary for accessing the DriverBase class used in the smart sync implementation.


256-284: LGTM - Smart sync action handling maintains synchronous execution

The implementation correctly maintains synchronous execution as required, while properly managing the browser context, timeouts, and cleanup.


296-296: LGTM!

The addition of ActSmartSync to the list of supported actions is correct and follows the existing pattern.

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.

2 participants