好的,下面是使用 pytest 结合 playwright 实现页面元素在两个区域间拖拽的完整示例。
这个示例将创建一个包含两个区域(source 和 target)和一个可拖拽区块的 html 页面,然后使用 playwright 模拟将该区块从一个区域拖拽到另一个区域的操作。
示例场景
我们将创建一个简单的 html 页面,包含:
- source area: 包含一个可拖拽的区块(例如一个带颜色的
<div>)。 - target area: 一个空的区域,用于接收被拖拽的区块。
- javascript: 实现 html5 拖放 api,处理
dragstart,dragover, 和drop事件,以便将元素从source移动到target。
1. 创建示例 html 页面 (drag_drop_block.html)
将以下 html 代码保存为 drag_drop_block.html 文件。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>block drag & drop example</title>
<style>
body {
font-family: arial, sans-serif;
margin: 40px;
}
.area {
width: 300px;
height: 200px;
border: 2px dashed #ccc;
display: inline-block;
vertical-align: top;
margin: 20px;
padding: 10px;
position: relative;
}
#source-area {
background-color: #e0f7fa; /* light blue */
}
#target-area {
background-color: #f3e5f5; /* light purple */
}
.draggable-block {
width: 100px;
height: 100px;
background-color: #f44336; /* red */
color: white;
text-align: center;
line-height: 100px; /* vertically center text */
cursor: move; /* show move cursor */
user-select: none; /* prevent text selection */
position: absolute; /* position within parent */
top: 30px;
left: 50px;
}
.block-content {
font-size: 12px;
}
/* optional: visual feedback during drag */
.draggable-block.dragging {
opacity: 0.5;
}
/* success indicator */
.success-indicator {
color: green;
font-weight: bold;
display: none; /* hidden initially */
}
#target-area.success .success-indicator {
display: block;
}
</style>
</head>
<body>
<h1>block drag & drop test</h1>
<div id="source-area" class="area">
<h3>source area</h3>
<div id="draggable-block" class="draggable-block" draggable="true">
<span class="block-content">drag me!</span>
</div>
</div>
<div id="target-area" class="area">
<h3>target area</h3>
<p class="success-indicator">block dropped successfully!</p>
</div>
<script>
const draggableblock = document.getelementbyid('draggable-block');
const sourcearea = document.getelementbyid('source-area');
const targetarea = document.getelementbyid('target-area');
draggableblock.addeventlistener('dragstart', function(event) {
event.datatransfer.setdata("text/plain", "block-id"); // optional: set data
// add a class for visual feedback
this.classlist.add('dragging');
});
draggableblock.addeventlistener('dragend', function(event) {
// remove visual feedback
this.classlist.remove('dragging');
});
targetarea.addeventlistener('dragover', function(event) {
event.preventdefault(); // crucial: allows dropping
});
targetarea.addeventlistener('drop', function(event) {
event.preventdefault(); // crucial: allows dropping
// move the block from source to target
// we know the block is the only draggable element in source
sourcearea.removechild(draggableblock);
targetarea.appendchild(draggableblock);
// optional: add success class to target area
targetarea.classlist.add('success');
});
// allow dropping back into source area too (for demo purposes)
sourcearea.addeventlistener('dragover', function(event) {
event.preventdefault();
});
sourcearea.addeventlistener('drop', function(event) {
event.preventdefault();
// move the block from target back to source
targetarea.removechild(draggableblock);
sourcearea.appendchild(draggableblock);
// remove success class from target area
targetarea.classlist.remove('success');
});
</script>
</body>
</html>
说明:
draggable="true": 必须在可拖拽的元素上设置此属性。- css: 设置了
position: absolute以便在容器内精确定位区块。 - javascript:
dragstart: 设置拖拽数据(可选),添加视觉反馈类。dragend: 移除视觉反馈类。dragover: 必须调用event.preventdefault(),否则drop事件不会触发。drop: 必须调用event.preventdefault()。然后执行元素的移动逻辑(removechild+appendchild)。- 为了演示双向拖拽,
source-area也监听了dragover和drop。
2. pytest + playwright 测试代码 (test_block_drag_drop.py)
首先,确保安装了必要的库:
pip install pytest playwright playwright install
然后,将以下 python 代码保存为 test_block_drag_drop.py。
# test_block_drag_drop.py
import pytest
from playwright.sync_api import page, expect
# pytest fixture to provide a fresh browser page for each test
@pytest.fixture(scope="function")
def page(context):
"""creates a new page for each test function."""
page = context.new_page()
yield page
page.close()
def test_drag_block_from_source_to_target(page: page):
"""
tests dragging a block from the source area to the target area.
"""
# 1. navigate to the html file
# update the path to point to where you saved the html file
page.goto("file:///absolute/path/to/your/drag_drop_block.html")
# 2. define selectors for the draggable block and the target area
source_area_selector = "#source-area"
target_area_selector = "#target-area"
draggable_block_selector = "#draggable-block"
# 3. verify initial state: block is in source area
expect(page.locator(source_area_selector + " " + draggable_block_selector)).to_be_attached()
expect(page.locator(target_area_selector + " " + draggable_block_selector)).not_to_be_attached()
expect(page.locator(f"{target_area_selector} .success-indicator")).not_to_be_visible()
# 4. perform the drag and drop operation
page.drag_and_drop(draggable_block_selector, target_area_selector)
# 5. verify final state: block is in target area
expect(page.locator(target_area_selector + " " + draggable_block_selector)).to_be_attached(message="block should be in target area after drop.")
expect(page.locator(source_area_selector + " " + draggable_block_selector)).not_to_be_attached(message="block should not be in source area after drop.")
expect(page.locator(f"{target_area_selector} .success-indicator")).to_be_visible(message="success indicator should be visible in target area.")
def test_drag_block_back_to_source(page: page):
"""
tests dragging the block back from the target area to the source area.
"""
# 1. navigate to the html file
page.goto("file:///absolute/path/to/your/drag_drop_block.html")
# 2. define selectors
source_area_selector = "#source-area"
target_area_selector = "#target-area"
draggable_block_selector = "#draggable-block"
# 3. first, move the block to the target area (using the previous test's logic or just do it here)
# initial state check
expect(page.locator(source_area_selector + " " + draggable_block_selector)).to_be_attached()
expect(page.locator(target_area_selector + " " + draggable_block_selector)).not_to_be_attached()
# drag to target first
page.drag_and_drop(draggable_block_selector, target_area_selector)
# confirm it's in target
expect(page.locator(target_area_selector + " " + draggable_block_selector)).to_be_attached()
expect(page.locator(source_area_selector + " " + draggable_block_selector)).not_to_be_attached()
expect(page.locator(f"{target_area_selector} .success-indicator")).to_be_visible()
# 4. now, drag the block back from target to source
page.drag_and_drop(draggable_block_selector, source_area_selector)
# 5. verify final state: block is back in source area
expect(page.locator(source_area_selector + " " + draggable_block_selector)).to_be_attached(message="block should be back in source area after second drop.")
expect(page.locator(target_area_selector + " " + draggable_block_selector)).not_to_be_attached(message="block should not be in target area after second drop.")
expect(page.locator(f"{target_area_selector} .success-indicator")).not_to_be_visible(message="success indicator should be hidden after moving block back to source.")
说明:
- fixture
page: 为每个测试函数提供一个新的浏览器页面实例,并在测试结束后自动关闭,确保测试隔离。 page.goto(): 导航到你的本地 html 文件。务必更新file:///...后面的路径为你实际存放drag_drop_block.html的绝对路径。page.drag_and_drop(source, target): playwright 提供的核心方法,用于模拟拖放操作。它会处理底层的鼠标事件序列。expect(...): playwright 的断言库,用于验证 dom 状态(元素是否存在、是否可见等)。它具有内置的智能等待机制。
3. 运行测试
在终端中,切换到包含 test_block_drag_drop.py 和 drag_drop_block.html 的目录,然后运行:
pytest test_block_drag_drop.py -v
-v选项提供更详细的输出。
如果配置正确,你应该会看到类似以下的输出,并且浏览器窗口会短暂出现以执行测试:
============================= test session starts ============================== platform linux -- python 3.x.y, pytest-x.x.x, pluggy-x.x.x rootdir: /path/to/your/test/directory collected 2 items test_block_drag_drop.py::test_drag_block_from_source_to_target passed [ 50%] test_block_drag_drop.py::test_drag_block_back_to_source passed [100%] ============================== 2 passed in 3.12s ===============================
这表明两个测试(从 source 到 target,以及从 target 回到 source)都成功通过了。
以上就是使用pytest结合playwright实现页面元素在两个区域间拖拽功能的详细内容,更多关于pytest playwright页面元素拖拽的资料请关注代码网其它相关文章!
发表评论