Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ Variables use `%|variable_name|%` syntax:
"%|user["name"]|%" # Dictionary access
```

Some Selenium actions, including `copy image into browser`, use a single `image file` row whose value can be a literal path or a `%|...|%` expression such as `%|var|%/whatever.png` because the framework resolves it before the action runs.

### Element Location
The unified `LocateElement.Get_Element()` supports:
- Selenium WebDriver
Expand Down
173 changes: 0 additions & 173 deletions Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1434,8 +1434,6 @@ def parse_status_codes(code_str):
"method_filter": [],
"include_body": False,
}

# Parse
for left, mid, right in step_data:
left = left.lower().strip()
if left == "capture network log":
Expand Down Expand Up @@ -5153,174 +5151,3 @@ def if_element_exists(data_set):


@logger
def copy_image_into_browser(data_set):
"""
This action will copy an image from path or a variable into browser, and later you can paste via ctrl+v or cmd+v.
Supported formats: PNG, SVG

Example 1:
Field Sub Field Value
image file input parameter %| image.png |%
copy image into browser selenium action copy image into browser

Example 2:
Field Sub Field Value
image variable input parameter %| image_var |%
copy image into browser selenium action copy image into browser
"""
sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME
global selenium_driver

try:
image_data = None
image_path = ""
variable_name = ""
mime_type = "image/png"

# Parse
for left, mid, right in data_set:
left = left.lower().replace(" ", "")
mid = mid.lower().replace(" ", "")
right = right.strip()

if left == "imagefile":
if os.path.exists(right):
image_path = right
else:
image_path = CommonUtil.path_parser(right)

elif left == "imagevariable":
if os.path.exists(right):
image_path = right
else:
variable_name = right

if image_path:
if not os.path.exists(image_path):
CommonUtil.ExecLog(
sModuleInfo, f"Image file not found: {image_path}", 3
)
return "zeuz_failed"
elif variable_name:
image_path = Shared_Resources.Get_Shared_Variables(variable_name)
if not image_path:
CommonUtil.ExecLog(
sModuleInfo,
f"Image path not found in variable: {variable_name}. Make sure you must be use '%| |%' syntax for any variable or attachment.",
3,
)
return "zeuz_failed"
else:
CommonUtil.ExecLog(
sModuleInfo, "Must provide either 'image file' or 'image variable'", 3
)
return "zeuz_failed"

if image_path.lower().endswith(".svg"):
mime_type = "image/svg+xml"
elif image_path.lower().endswith(".png"):
mime_type = "image/png"
else:
CommonUtil.ExecLog(
sModuleInfo,
"Unsupported file format. You can copy only PNG or SVG image.",
2,
)
return "zeuz_failed"

with open(image_path, "rb") as image_file:
image_data = image_file.read()

# Convert
image_b64 = base64.b64encode(image_data).decode("utf-8")

browser_name = selenium_driver.capabilities.get("browserName", "").lower()
if browser_name in ("chrome", "microsoft edge", "edge"):
try:
selenium_driver.execute_cdp_cmd(
"Browser.setClipboard", {"data": image_b64, "type": mime_type}
)
CommonUtil.ExecLog(
sModuleInfo, f"Image copied to clipboard via CDP: {image_path}", 1
)
return "passed"
except Exception as e:
CommonUtil.ExecLog(
sModuleInfo, f"CDP failed ({str(e)}). Trying fallback method", 2
)

try:
# Grant clipboard permissions via CDP if possible
try:
from urllib.parse import urlparse

parsed_uri = urlparse(selenium_driver.current_url)
origin = f"{parsed_uri.scheme}://{parsed_uri.netloc}"
selenium_driver.execute_cdp_cmd(
"Browser.grantPermissions",
{
"origin": origin,
"permissions": [
"clipboardReadWrite",
"clipboardSanitizedWrite",
],
},
)
except:
pass

async_script = """
const [base64Data, mimeType, callback] = arguments;
const byteCharacters = atob(base64Data);
const byteArrays = [];

for (let offset = 0; offset < byteCharacters.length; offset += 512) {
const slice = byteCharacters.slice(offset, offset + 512);
const byteNumbers = new Array(slice.length);

for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}

byteArrays.push(new Uint8Array(byteNumbers));
}

const blob = new Blob(byteArrays, {type: mimeType});
const item = new ClipboardItem({ [mimeType]: blob });

window.focus();
navigator.clipboard.write([item])
.then(() => {
console.log('Successfully copied image to clipboard.');
callback(true);
})
.catch(err => {
console.log('Failed to copy image to clipboard', err);
callback(false);
});
"""

selenium_driver.switch_to.window(selenium_driver.current_window_handle)
selenium_driver.execute_script("window.focus();")

success = selenium_driver.execute_async_script(
async_script, image_b64, mime_type
)
if success:
CommonUtil.ExecLog(
sModuleInfo, f"Image copied to clipboard: {image_path}", 1
)
return "passed"
CommonUtil.ExecLog(
sModuleInfo,
f"Document is not focused. Failed to copy image to clipboard: {image_path}",
3,
)
return "zeuz_failed"

except Exception as e:
CommonUtil.ExecLog(sModuleInfo, f"Fallback method failed: {str(e)}", 3)
return "zeuz_failed"

except Exception:
return CommonUtil.Exception_Handler(sys.exc_info())
80 changes: 80 additions & 0 deletions tests/test_copy_image_into_browser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import unittest
from unittest.mock import MagicMock, mock_open, patch

from Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions import (
copy_image_into_browser,
)


class CopyImageIntoBrowserTests(unittest.TestCase):
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.selenium_driver")
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.CommonUtil.ExecLog")
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.CommonUtil.path_parser")
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.os.access", return_value=True)
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.os.path.isfile", return_value=True)
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.os.path.exists", return_value=True)
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.open", new_callable=mock_open, read_data=b"fakepng")
def test_accepts_single_image_file_row_with_mixed_variable_path(
self,
mock_open_file,
mock_exists,
mock_isfile,
mock_access,
mock_path_parser,
mock_exec_log,
mock_driver,
):
mock_path_parser.return_value = "/resolved/image.png"
mock_driver.capabilities = {"browserName": "chrome"}
mock_driver.execute_cdp_cmd = MagicMock()

result = copy_image_into_browser(
[("image file", "input parameter", "%|var|%/whatever.png")]
)

self.assertEqual(result, "passed")
mock_path_parser.assert_called_once_with("%|var|%/whatever.png")
mock_driver.execute_cdp_cmd.assert_called_once()
mock_exec_log.assert_any_call(
"copy_image_into_browser : selenium", "Image copied to clipboard via CDP: /resolved/image.png", 1
)

@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.selenium_driver")
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.CommonUtil.ExecLog")
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.CommonUtil.path_parser")
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.os.access", return_value=True)
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.os.path.isfile", return_value=True)
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.os.path.exists", return_value=True)
@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.open", new_callable=mock_open, read_data=b"fakepng")
def test_accepts_single_literal_image_path_row(
self,
mock_open_file,
mock_exists,
mock_isfile,
mock_access,
mock_path_parser,
mock_exec_log,
mock_driver,
):
mock_path_parser.side_effect = lambda value: value
mock_driver.capabilities = {"browserName": "chrome"}
mock_driver.execute_cdp_cmd = MagicMock()

result = copy_image_into_browser(
[("image file", "input parameter", "/tmp/whatever.png")]
)

self.assertEqual(result, "passed")
mock_path_parser.assert_called_once_with("/tmp/whatever.png")
mock_driver.execute_cdp_cmd.assert_called_once()
mock_exec_log.assert_any_call(
"copy_image_into_browser : selenium", "Image copied to clipboard via CDP: /tmp/whatever.png", 1
)

@patch("Framework.Built_In_Automation.Web.Selenium.BuiltInFunctions.CommonUtil.ExecLog")
def test_rejects_missing_image_file_value(self, mock_exec_log):
result = copy_image_into_browser([])

self.assertEqual(result, "zeuz_failed")
mock_exec_log.assert_called_once()
self.assertIn("image file", mock_exec_log.call_args.args[1])
Loading