-
Notifications
You must be signed in to change notification settings - Fork 784
Add "Drag And Drop Across Frames" keyword for cross-frame drag and drop support #1953
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
b-vamsipunnam
wants to merge
5
commits into
robotframework:master
Choose a base branch
from
b-vamsipunnam:feature/drag-and-drop-to-frame
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+396
−2
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
bf869a0
Add Drag And Drop To Frame keyword Updated implementation and tests
b-vamsipunnam fb7faa4
Fix acceptance tests for CI run - Drag And Drop To Frame keyword
b-vamsipunnam 3f6871d
Improve cross-frame drag and drop reliability and tests
b-vamsipunnam b76a3d9
Update docstring to clarify default content reset after execution
b-vamsipunnam 4de91cb
Simplify test fixture and refine test coverage
b-vamsipunnam File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| *** Settings *** | ||
| Documentation Tests for the custom Drag And Drop Across Frames keyword | ||
| ... in cross-frame drag-and-drop scenarios. | ||
| Resource ../resource.robot | ||
| Test Setup Go To Page "frames/draganddrop.html" | ||
|
|
||
| *** Test Cases *** | ||
| Drag And Drop Across Frames Works From Default Content | ||
| [Documentation] Verifies drag-and-drop from default content to a target inside an iframe. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Drag And Drop Across Frames id=defaultSource id=target id=targetFrame | ||
| Select Frame id=targetFrame | ||
| Element Should Contain id=target Dropped Successfully! | ||
| Unselect Frame | ||
|
|
||
| Drag And Drop Across Frames Works From Source Frame | ||
| [Documentation] Verifies drag-and-drop from a source iframe to a target iframe. | ||
| Wait Until Page Contains Element id=sourceFrame 10s | ||
| Select Frame id=sourceFrame | ||
| Wait Until Page Contains Element id=frameSource 10s | ||
| Unselect Frame | ||
| Drag And Drop Across Frames id=frameSource id=target id=targetFrame id=sourceFrame | ||
| Select Frame id=targetFrame | ||
| Element Should Contain id=target Dropped Successfully! | ||
| Unselect Frame | ||
|
|
||
| Drag And Drop Across Frames Returns To Default Content | ||
| [Documentation] Verifies that the keyword returns to default content after execution. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Drag And Drop Across Frames id=defaultSource id=target id=targetFrame | ||
| Page Should Not Contain Element id=target | ||
|
|
||
| Drag And Drop Across Frames Hides Default Source Element | ||
| [Documentation] Verifies that the default source element becomes hidden after a successful drop. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Drag And Drop Across Frames id=defaultSource id=target id=targetFrame | ||
| Element Should Not Be Visible id=defaultSource | ||
|
|
||
| Drag And Drop Across Frames Hides Frame Source Element | ||
| [Documentation] Verifies that the frame source element becomes hidden after a successful drop. | ||
| Wait Until Page Contains Element id=sourceFrame 10s | ||
| Drag And Drop Across Frames id=frameSource id=target id=targetFrame id=sourceFrame | ||
| Select Frame id=sourceFrame | ||
| Element Should Not Be Visible id=frameSource | ||
| Unselect Frame | ||
|
|
||
| Drag And Drop Across Frames Fails With Invalid Target Frame | ||
| [Documentation] Verifies that the keyword fails when the target frame locator is invalid. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Run Keyword And Expect Error | ||
| ... Element with locator 'id=missingFrame' not found. | ||
| ... Drag And Drop Across Frames | ||
| ... id=defaultSource id=target id=missingFrame | ||
|
|
||
| Drag And Drop Across Frames Fails With Invalid Target | ||
| [Documentation] Verifies that the keyword fails when the target element is not found inside the target iframe. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Run Keyword And Expect Error | ||
| ... Element with locator 'id=missingTarget' not found. | ||
| ... Drag And Drop Across Frames | ||
| ... id=defaultSource id=missingTarget id=targetFrame | ||
|
|
||
| Drag And Drop Across Frames Fails With Invalid Source Frame | ||
| [Documentation] Verifies that the keyword fails when the source frame locator is invalid. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Run Keyword And Expect Error | ||
| ... Element with locator 'id=missingSourceFrame' not found. | ||
| ... Drag And Drop Across Frames | ||
| ... id=frameSource id=target id=targetFrame id=missingSourceFrame | ||
|
|
||
| Drag And Drop Across Frames Fails With Invalid Source | ||
| [Documentation] Verifies that the keyword fails when the source element is not found. | ||
| Wait Until Page Contains Element id=defaultSource 10s | ||
| Run Keyword And Expect Error | ||
| ... Element with locator 'id=missingSource' not found. | ||
| ... Drag And Drop Across Frames | ||
| ... id=missingSource id=target id=targetFrame | ||
|
b-vamsipunnam marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,260 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <title>Drag And Drop Across Frames Test Page</title> | ||
| <style> | ||
| body { | ||
| font-family: Arial, sans-serif; | ||
| margin: 40px; | ||
| background: #f0f0f0; | ||
| } | ||
|
|
||
| .frame-wrapper { | ||
| display: flex; | ||
| gap: 40px; | ||
| margin-top: 40px; | ||
| } | ||
|
|
||
| iframe { | ||
| width: 500px; | ||
| height: 350px; | ||
| border: 3px solid #333; | ||
| background: white; | ||
| } | ||
|
|
||
| #defaultSource, | ||
| #dragGhost { | ||
| width: 150px; | ||
| height: 150px; | ||
| background: lightblue; | ||
| text-align: center; | ||
| line-height: 150px; | ||
| font-size: 20px; | ||
| cursor: grab; | ||
| user-select: none; | ||
| } | ||
|
|
||
| #dragGhost { | ||
| position: fixed; | ||
| display: none; | ||
| z-index: 10000; | ||
| border: 2px solid #333; | ||
| opacity: 0.85; | ||
| pointer-events: none; | ||
| } | ||
|
|
||
| #status { | ||
| margin-top: 20px; | ||
| font-weight: bold; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
|
|
||
| <h2>Drag And Drop Across Frames Test Page</h2> | ||
|
|
||
| <div id="defaultSource">Default Source</div> | ||
|
|
||
| <div class="frame-wrapper"> | ||
| <iframe id="sourceFrame"></iframe> | ||
| <iframe id="targetFrame"></iframe> | ||
| </div> | ||
|
|
||
| <div id="dragGhost"></div> | ||
|
|
||
| <script> | ||
| const sourceFrame = document.getElementById("sourceFrame"); | ||
| const targetFrame = document.getElementById("targetFrame"); | ||
| const defaultSource = document.getElementById("defaultSource"); | ||
| const dragGhost = document.getElementById("dragGhost"); | ||
|
|
||
| let dragging = false; | ||
| let activeSource = null; | ||
|
|
||
| sourceFrame.srcdoc = ` | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <style> | ||
| body { | ||
| margin: 40px; | ||
| font-family: Arial, sans-serif; | ||
| background: white; | ||
| } | ||
|
|
||
| #frameSource { | ||
| width: 150px; | ||
| height: 150px; | ||
| background: lightblue; | ||
| text-align: center; | ||
| line-height: 150px; | ||
| font-size: 20px; | ||
| cursor: grab; | ||
| user-select: none; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div id="frameSource">Frame Source</div> | ||
| </body> | ||
| </html> | ||
| `; | ||
|
|
||
| targetFrame.srcdoc = ` | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <style> | ||
| body { | ||
| margin: 0; | ||
| background: white; | ||
| font-family: Arial, sans-serif; | ||
| } | ||
|
|
||
| #target { | ||
| width: 350px; | ||
| height: 220px; | ||
| background: lightgreen; | ||
| margin: 60px auto; | ||
| text-align: center; | ||
| line-height: 220px; | ||
| font-size: 26px; | ||
| border: 4px dashed black; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div id="target">Drop Here</div> | ||
| </body> | ||
| </html> | ||
| `; | ||
|
|
||
| window.onload = function () { | ||
| const sourceDoc = sourceFrame.contentDocument; | ||
| const targetDoc = targetFrame.contentDocument; | ||
|
|
||
| const frameSource = sourceDoc.getElementById("frameSource"); | ||
|
|
||
| defaultSource.addEventListener("mousedown", function (event) { | ||
| startDrag("default", event.clientX, event.clientY); | ||
| event.preventDefault(); | ||
| }); | ||
|
|
||
| frameSource.addEventListener("mousedown", function (event) { | ||
| const sourceRect = sourceFrame.getBoundingClientRect(); | ||
|
|
||
| startDrag( | ||
| "frame", | ||
| sourceRect.left + event.clientX, | ||
| sourceRect.top + event.clientY | ||
| ); | ||
|
|
||
| event.preventDefault(); | ||
| }); | ||
|
|
||
| document.addEventListener("mousemove", function (event) { | ||
| if (!dragging) return; | ||
| moveGhost(event.clientX, event.clientY); | ||
| }); | ||
|
|
||
| document.addEventListener("mouseup", function (event) { | ||
| if (!dragging) return; | ||
| finishDrag(event.clientX, event.clientY); | ||
| }); | ||
|
|
||
| sourceDoc.addEventListener("mousemove", function (event) { | ||
| if (!dragging) return; | ||
|
|
||
| const rect = sourceFrame.getBoundingClientRect(); | ||
| moveGhost(rect.left + event.clientX, rect.top + event.clientY); | ||
| }); | ||
|
|
||
| sourceDoc.addEventListener("mouseup", function (event) { | ||
| if (!dragging) return; | ||
|
|
||
| const rect = sourceFrame.getBoundingClientRect(); | ||
| finishDrag(rect.left + event.clientX, rect.top + event.clientY); | ||
| }); | ||
|
|
||
| targetDoc.addEventListener("mousemove", function (event) { | ||
| if (!dragging) return; | ||
|
|
||
| const rect = targetFrame.getBoundingClientRect(); | ||
| moveGhost(rect.left + event.clientX, rect.top + event.clientY); | ||
| }); | ||
|
|
||
| targetDoc.addEventListener("mouseup", function (event) { | ||
| if (!dragging) return; | ||
|
|
||
| const rect = targetFrame.getBoundingClientRect(); | ||
| finishDrag(rect.left + event.clientX, rect.top + event.clientY); | ||
| }); | ||
| }; | ||
|
|
||
| function startDrag(source, x, y) { | ||
| dragging = true; | ||
| activeSource = source; | ||
|
|
||
| dragGhost.innerText = source === "default" ? "Default Source" : "Frame Source"; | ||
| dragGhost.style.display = "block"; | ||
|
|
||
| moveGhost(x, y); | ||
| } | ||
|
|
||
| function moveGhost(x, y) { | ||
| dragGhost.style.left = (x - 75) + "px"; | ||
| dragGhost.style.top = (y - 75) + "px"; | ||
| } | ||
|
|
||
| function finishDrag(x, y) { | ||
| if (isInsideTarget(x, y)) { | ||
| completeDrop(); | ||
| } else { | ||
| resetDrag(); | ||
| } | ||
| } | ||
|
|
||
| function isInsideTarget(x, y) { | ||
| const target = targetFrame.contentDocument.getElementById("target"); | ||
| const frameRect = targetFrame.getBoundingClientRect(); | ||
| const targetRect = target.getBoundingClientRect(); | ||
|
|
||
| const globalLeft = frameRect.left + targetRect.left; | ||
| const globalTop = frameRect.top + targetRect.top; | ||
| const globalRight = globalLeft + targetRect.width; | ||
| const globalBottom = globalTop + targetRect.height; | ||
|
|
||
| return ( | ||
| x >= globalLeft && | ||
| x <= globalRight && | ||
| y >= globalTop && | ||
| y <= globalBottom | ||
| ); | ||
| } | ||
|
|
||
| function completeDrop() { | ||
| if (activeSource === "default") { | ||
| defaultSource.style.display = "none"; | ||
| } | ||
|
|
||
| if (activeSource === "frame") { | ||
| const frameSource = sourceFrame.contentDocument.getElementById("frameSource"); | ||
| frameSource.style.display = "none"; | ||
| } | ||
|
|
||
| const target = targetFrame.contentDocument.getElementById("target"); | ||
| target.innerText = "Dropped Successfully!"; | ||
|
|
||
| resetDrag(); | ||
| } | ||
|
|
||
| function resetDrag() { | ||
| dragging = false; | ||
| activeSource = null; | ||
| dragGhost.style.display = "none"; | ||
| } | ||
| </script> | ||
|
|
||
| </body> | ||
| </html> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.