使用pytest结合Playwright实现页面元素在两个区域间拖拽功能

作者:

文章目录
  • 我们将创建一个简单的 HTML 页面,包含: Source Area: 包含一个可拖拽的区块(例如一个带颜色的 <div>)。 Target Area: 一个空的区域,用于接收被拖拽的区块。 JavaScript: 实现 HTML5 拖放 API,处理 dragstart, dragover, 和 drop 事件,以便将元素从 source 移动到 target。
  • 目录
    • 示例场景
      • 1. 创建示例 HTML 页面 (drag_drop_block.html)
      • 2. Pytest + Playwright 测试代码 (test_block_drag_drop.py)
      • 3. 运行测试

    好的,下面是使用 pytest 结合 Playwright 实现页面元素在两个区域间拖拽的完整示例。

    这个示例将创建一个包含两个区域(sourcetarget)和一个可拖拽区块的 HTML 页面,然后使用 Playwright 模拟将该区块从一个区域拖拽到另一个区域的操作。

    我们将创建一个简单的 HTML 页面,包含:

    1. Source Area: 包含一个可拖拽的区块(例如一个带颜色的 <div>)。
    2. Target Area: 一个空的区域,用于接收被拖拽的区块。
    3. JavaScript: 实现 HTML5 拖放 API,处理 dragstart, dragover, 和 drop 事件,以便将元素从 source 移动到 target

    将以下 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

    首先,确保安装了必要的库:

    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 状态(元素是否存在、是否可见等)。它具有内置的智能等待机制。

    在终端中,切换到包含 test_block_drag_drop.pydrag_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页面元素拖拽的资料请关注风君子博客其它相关文章!

    您可能感兴趣的文章:

    • python playwright–pytest-playwright、pytest-base-url插件编写用例
    • Python使用pytest-playwright的原因分析
    • python中playwright结合pytest执行用例的实现

    站内搜索