Skip to content

Conversation

@cgoldberg
Copy link
Member

@cgoldberg cgoldberg commented Dec 12, 2025

User description

🔗 Related Issues

Similar to #16725 for Ruby
Python implementation of #14116

💥 What does this PR do?

This PR adds support for full page screenshots for Chrome and Edge via session/:session_id/screenshot/full endpoint (like Firefox already has).

🔧 Implementation Notes

I just copied the Firefox methods into the Chromium WebDriver class and added tests.

💡 Additional Considerations

I haven't even tried functionality or ran the tests yet, but let's see if CI passes.

🔄 Types of changes

  • New feature (non-breaking change which adds functionality and tests!)

PR Type

Enhancement


Description

  • Add full page screenshot methods to Chromium WebDriver

  • Implement four screenshot methods with different output formats

  • Add comprehensive tests for Chrome and Edge browsers

  • Methods support base64, PNG binary, and file output formats


Diagram Walkthrough

flowchart LR
  A["Chromium WebDriver"] -->|"add methods"| B["get_full_page_screenshot_as_base64"]
  A -->|"add methods"| C["get_full_page_screenshot_as_png"]
  A -->|"add methods"| D["get_full_page_screenshot_as_file"]
  A -->|"add methods"| E["save_full_page_screenshot"]
  B -->|"decode"| C
  C -->|"write to file"| D
  D -->|"alias"| E
  F["Chrome Tests"] -->|"verify"| B
  F -->|"verify"| C
  G["Edge Tests"] -->|"verify"| B
  G -->|"verify"| C
Loading

File Walkthrough

Relevant files
Enhancement
webdriver.py
Add four full page screenshot methods to Chromium               

py/selenium/webdriver/chromium/webdriver.py

  • Add imports for base64 and warnings modules
  • Implement get_full_page_screenshot_as_base64() method to retrieve full
    page screenshot as base64-encoded string
  • Implement get_full_page_screenshot_as_png() method to decode base64 to
    binary PNG data
  • Implement get_full_page_screenshot_as_file() method to save screenshot
    to file with validation
  • Implement save_full_page_screenshot() as alias method for file saving
+67/-0   
Formatting
webdriver.py
Minor formatting adjustment                                                           

py/selenium/webdriver/firefox/webdriver.py

  • Add blank line after license header for consistency
+1/-0     
Tests
chrome_takes_full_page_screenshots_tests.py
Add Chrome full page screenshot tests                                       

py/test/selenium/webdriver/chrome/chrome_takes_full_page_screenshots_tests.py

  • Create new test file for Chrome full page screenshots
  • Add test for get_full_page_screenshot_as_base64() method
  • Add test for get_full_page_screenshot_as_png() method
  • Verify returned data is valid PNG format using filetype library
+34/-0   
edge_takes_full_page_screenshots_tests.py
Add Edge full page screenshot tests                                           

py/test/selenium/webdriver/edge/edge_takes_full_page_screenshots_tests.py

  • Create new test file for Edge full page screenshots
  • Add test for get_full_page_screenshot_as_base64() method
  • Add test for get_full_page_screenshot_as_png() method
  • Verify returned data is valid PNG format using filetype library
+34/-0   

@selenium-ci selenium-ci added the C-py Python Bindings label Dec 12, 2025
@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No auditing: The new screenshot methods perform actions without emitting any audit logs, but WebDriver
libraries typically avoid logging at this level and may rely on higher-level frameworks,
so applicability needs human review.

Referred Code
def get_full_page_screenshot_as_file(self, filename) -> bool:
    """Save a full document screenshot of the current window to a PNG image file.

    Args:
        filename: The full path you wish to save your screenshot to. This
            should end with a `.png` extension.

    Returns:
        False if there is any IOError, else returns True. Use full paths in your filename.

    Example:
        driver.get_full_page_screenshot_as_file("/Screenshots/foo.png")
    """
    if not filename.lower().endswith(".png"):
        warnings.warn(
            "name used for saved screenshot does not match file type. It should end with a `.png` extension",
            UserWarning,
        )
    png = self.get_full_page_screenshot_as_png()
    try:
        with open(filename, "wb") as f:


 ... (clipped 44 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Narrow errors: File write errors only return False without conveying context, and base64 decode or
command execution errors are not explicitly handled, which may be acceptable for parity
with existing drivers but merits review.

Referred Code
    if not filename.lower().endswith(".png"):
        warnings.warn(
            "name used for saved screenshot does not match file type. It should end with a `.png` extension",
            UserWarning,
        )
    png = self.get_full_page_screenshot_as_png()
    try:
        with open(filename, "wb") as f:
            f.write(png)
    except OSError:
        return False
    finally:
        del png
    return True

def save_full_page_screenshot(self, filename) -> bool:
    """Save a full document screenshot of the current window to a PNG image file.

    Args:
        filename: The full path you wish to save your screenshot to. This
            should end with a `.png` extension.


 ... (clipped 20 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Avoid code duplication across drivers

To avoid code duplication with the Firefox driver, move the generic full-page
screenshot helper methods from the ChromiumDriver to the RemoteWebDriver base
class. This centralizes the logic and improves maintainability.

Examples:

py/selenium/webdriver/chromium/webdriver.py [222-285]
    def get_full_page_screenshot_as_file(self, filename) -> bool:
        """Save a full document screenshot of the current window to a PNG image file.

        Args:
            filename: The full path you wish to save your screenshot to. This
                should end with a `.png` extension.

        Returns:
            False if there is any IOError, else returns True. Use full paths in your filename.


 ... (clipped 54 lines)

Solution Walkthrough:

Before:

# In py/selenium/webdriver/chromium/webdriver.py
class ChromiumDriver(RemoteWebDriver):
    def get_full_page_screenshot_as_file(self, filename):
        # ... logic to save file from png
        png = self.get_full_page_screenshot_as_png()
        # ...
    
    def get_full_page_screenshot_as_png(self) -> bytes:
        return base64.b64decode(self.get_full_page_screenshot_as_base64().encode("ascii"))

    def get_full_page_screenshot_as_base64(self) -> str:
        return self.execute("FULL_PAGE_SCREENSHOT")["value"]

# A similar implementation exists in the Firefox driver, causing duplication.

After:

# In py/selenium/webdriver/remote/webdriver.py (base class)
class RemoteWebDriver:
    def get_full_page_screenshot_as_file(self, filename):
        # ... logic to save file from png
        png = self.get_full_page_screenshot_as_png()
        # ...
    
    def get_full_page_screenshot_as_png(self) -> bytes:
        return base64.b64decode(self.get_full_page_screenshot_as_base64().encode("ascii"))

    def get_full_page_screenshot_as_base64(self) -> str:
        # This assumes the command is standardized.
        return self.execute(Command.FULL_PAGE_SCREENSHOT)["value"]

# In py/selenium/webdriver/chromium/webdriver.py
class ChromiumDriver(RemoteWebDriver):
    # Inherits the screenshot methods, no need for re-implementation.
    pass
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies significant code duplication and proposes a valid architectural improvement by moving common logic to a base class, which enhances maintainability.

Medium
General
Use a command constant instead of a string

Replace the hardcoded string "FULL_PAGE_SCREENSHOT" with a constant from the
Command enum, such as Command.FULL_PAGE_SCREENSHOT, to improve code
maintainability and consistency.

py/selenium/webdriver/chromium/webdriver.py [276-285]

 def get_full_page_screenshot_as_base64(self) -> str:
     """Get the full document screenshot of the current window as a base64-encoded string.
 
     Returns:
         Base64 encoded string of the screenshot.
 
     Example:
         driver.get_full_page_screenshot_as_base64()
     """
-    return self.execute("FULL_PAGE_SCREENSHOT")["value"]
+    return self.execute(Command.FULL_PAGE_SCREENSHOT)["value"]
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies the use of a magic string for a command and recommends using a Command enum constant, which significantly improves maintainability and aligns with existing codebase patterns.

Medium
Simplify code by removing unnecessary cleanup

Refactor get_full_page_screenshot_as_file by removing the unnecessary finally
block containing del png and moving return True inside the try block for
cleaner, more idiomatic code.

py/selenium/webdriver/chromium/webdriver.py [222-248]

 def get_full_page_screenshot_as_file(self, filename) -> bool:
     """Save a full document screenshot of the current window to a PNG image file.
 
     Args:
         filename: The full path you wish to save your screenshot to. This
             should end with a `.png` extension.
 
     Returns:
         False if there is any IOError, else returns True. Use full paths in your filename.
 
     Example:
         driver.get_full_page_screenshot_as_file("/Screenshots/foo.png")
     """
     if not filename.lower().endswith(".png"):
         warnings.warn(
             "name used for saved screenshot does not match file type. It should end with a `.png` extension",
             UserWarning,
         )
     png = self.get_full_page_screenshot_as_png()
     try:
         with open(filename, "wb") as f:
             f.write(png)
+        return True
     except OSError:
         return False
-    finally:
-        del png
-    return True
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies an un-pythonic use of del and a finally block, proposing a cleaner implementation that improves code readability and relies on standard Python garbage collection.

Low
Learned
best practice
Enforce and sanitize filename input

Validate filename input more defensively: enforce non-empty string, ensure .png
extension by appending when missing, and raise a clear error for invalid types.
This prevents invalid paths and silent mismatches.

py/selenium/webdriver/chromium/webdriver.py [222-248]

 def get_full_page_screenshot_as_file(self, filename) -> bool:
-    """Save a full document screenshot of the current window to a PNG image file.
-...
+    """Save a full document screenshot of the current window to a PNG image file."""
+    if not isinstance(filename, str) or not filename.strip():
+        raise ValueError("filename must be a non-empty string ending with .png")
+    filename = filename.strip()
     if not filename.lower().endswith(".png"):
-        warnings.warn(
-            "name used for saved screenshot does not match file type. It should end with a `.png` extension",
-            UserWarning,
-        )
+        filename = f"{filename}.png"
     png = self.get_full_page_screenshot_as_png()
     try:
         with open(filename, "wb") as f:
             f.write(png)
+        return True
     except OSError:
         return False
-    finally:
-        del png
-    return True

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Validate and sanitize external inputs; enforce expected formats and handle errors explicitly.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants