| import pytest |
| import base64 |
| import os |
| import pytest_asyncio |
|
|
| from playwright.async_api import ( |
| async_playwright, |
| Browser, |
| BrowserContext, |
| ) |
|
|
| from magentic_ui.tools import PlaywrightController |
|
|
| FAKE_HTML = """ |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Fake Page</title> |
| <script> |
| window.clickCount = 0; |
| function incrementClickCount() { |
| window.clickCount++; |
| } |
| </script> |
| </head> |
| <body> |
| <h1 id="header">Welcome to the Fake Page</h1> |
| <a href="#" id="new-page-link" __elementId="26">Open New Page</a> |
| <button id="click-me" __elementId="10" onclick="incrementClickCount()">Click Me</button> |
| <button id="disabled-button" __elementId="11" disabled>Disabled Button</button> |
| <button id="hidden-button" __elementId="12" style="display:none;">Hidden Button</button> |
| <input type="text" id="input-box" __elementId="13" /> |
| <select id="dropdown" __elementId="14"> |
| <option __elementId="15" value="one">Option One</option> |
| <option __elementId="16" value="two">Option Two</option> |
| </select> |
| <select id="multi-dropdown" __elementId="17" multiple> |
| <option __elementId="18" value="red">Red</option> |
| <option __elementId="19" value="blue">Blue</option> |
| <option __elementId="20" value="green">Green</option> |
| </select> |
| <div class="custom-dropdown" id="expandable-dropdown" __elementId="21"> |
| <button class="dropdown-button" __elementId="22">Select an option ▼</button> |
| <div class="dropdown-content" style="display: none;"> |
| <div class="dropdown-item" __elementId="23" data-value="alpha">Alpha</div> |
| <div class="dropdown-item" __elementId="24" data-value="beta">Beta</div> |
| <div class="dropdown-item" __elementId="25" data-value="gamma">Gamma</div> |
| </div> |
| </div> |
| <script> |
| // Add dropdown functionality |
| document.querySelector('.dropdown-button').addEventListener('click', function() { |
| const content = document.querySelector('.dropdown-content'); |
| content.style.display = content.style.display === 'none' ? 'block' : 'none'; |
| }); |
| |
| document.querySelectorAll('.dropdown-item').forEach(item => { |
| item.addEventListener('click', function() { |
| document.querySelector('.dropdown-button').textContent = this.textContent; |
| document.querySelector('.dropdown-content').style.display = 'none'; |
| }); |
| }); |
| |
| // Fixed new page link functionality: |
| document.getElementById('new-page-link').addEventListener('click', function(e) { |
| e.preventDefault(); |
| const newWindow = window.open("", "_blank"); |
| newWindow.document.write(`<!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>New Page</title> |
| </head> |
| <body> |
| <h1>New Page</h1> |
| </body> |
| </html>`); |
| newWindow.document.close(); |
| }); |
| </script> |
| </body> |
| </html> |
| """ |
|
|
|
|
| @pytest_asyncio.fixture(scope="function") |
| async def browser(): |
| """ |
| Launch a headless browser for each test function. |
| """ |
| async with async_playwright() as pw: |
| browser = await pw.chromium.launch(headless=True) |
| yield browser |
| await browser.close() |
|
|
|
|
| @pytest_asyncio.fixture |
| async def context(browser: Browser): |
| """ |
| Create a fresh BrowserContext for each test. |
| """ |
| ctx = await browser.new_context() |
| yield ctx |
| await ctx.close() |
|
|
|
|
| @pytest_asyncio.fixture |
| async def page(context: BrowserContext, controller): |
| """ |
| Provide a new Page with FAKE_HTML loaded and the controller. |
| Returns a tuple of (page, controller). |
| """ |
| p = await context.new_page() |
| await p.set_content(FAKE_HTML) |
| yield (p, controller) |
| await p.close() |
|
|
|
|
| @pytest.fixture |
| def controller(tmp_path): |
| """ |
| Return an instance of the PlaywrightController. |
| """ |
| downloads_folder = str(tmp_path / "downloads") |
| os.makedirs(downloads_folder, exist_ok=True) |
|
|
| |
| |
| ctrl = PlaywrightController( |
| downloads_folder=downloads_folder, |
| animate_actions=False, |
| viewport_width=800, |
| viewport_height=600, |
| to_resize_viewport=True, |
| timeout_load=2, |
| sleep_after_action=1, |
| single_tab_mode=True, |
| ) |
| return ctrl |
|
|
|
|
| @pytest.mark.asyncio |
| class TestPlaywrightController: |
| async def test_get_interactive_rects(self, page): |
| page_obj, pc = page |
| rects = await pc.get_interactive_rects(page_obj) |
| |
| assert isinstance(rects, dict) |
| assert "10" in rects |
| assert "13" in rects |
| |
| |
| |
| if "12" in rects: |
| |
| |
| pass |
|
|
| async def test_get_focused_rect_id(self, page): |
| page_obj, pc = page |
| |
| await page_obj.click("#input-box") |
| focused_id = await pc.get_focused_rect_id(page_obj) |
| assert focused_id == "13" |
|
|
| async def test_get_page_metadata(self, page): |
| page_obj, pc = page |
| metadata = await pc.get_page_metadata(page_obj) |
| |
| |
| assert isinstance(metadata, dict) |
|
|
| async def test_go_back_and_go_forward(self, page): |
| """ |
| This is a contrived example: |
| We'll do 2 navigations (fake), then check go_back/go_forward. |
| In practice, you'd do real URLs or data URLs. |
| """ |
| page_obj, pc = page |
|
|
| |
| |
| await pc.visit_page( |
| page_obj, |
| "data:text/html;base64," + base64.b64encode(FAKE_HTML.encode()).decode(), |
| ) |
| |
| back_ok = await pc.go_back(page_obj) |
| |
| |
| forward_ok = await pc.go_forward(page_obj) |
|
|
| |
| assert isinstance(back_ok, bool) |
| assert isinstance(forward_ok, bool) |
|
|
| async def test_visit_page(self, page): |
| page_obj, pc = page |
| reset_prior, reset_last = await pc.visit_page( |
| page_obj, |
| "data:text/html;base64," + base64.b64encode(FAKE_HTML.encode()).decode(), |
| ) |
| assert ( |
| reset_prior is True |
| ) |
| |
| assert reset_last is False |
|
|
| async def test_refresh_page(self, page): |
| page_obj, pc = page |
| |
| original_url = page_obj.url |
| await pc.refresh_page(page_obj) |
| assert page_obj.url == original_url |
|
|
| async def test_page_down_and_up(self, page): |
| page_obj, pc = page |
| |
| await pc.page_down(page_obj) |
| await pc.page_up(page_obj) |
|
|
| async def test_add_remove_cursor_box(self, page): |
| page_obj, pc = page |
| |
| await pc.add_cursor_box(page_obj, "10") |
| |
| |
| await pc.remove_cursor_box(page_obj, "10") |
|
|
| async def test_click_id(self, context, page): |
| page_obj, pc = page |
|
|
| |
| initial_clicks = await page_obj.evaluate("() => window.clickCount") |
| assert initial_clicks == 0 |
|
|
| |
| new_page = await pc.click_id(context, page_obj, "10") |
| |
| |
| assert new_page is None |
|
|
| |
| final_clicks = await page_obj.evaluate("() => window.clickCount") |
| assert final_clicks == 1, "Button click was not registered" |
|
|
| |
| await pc.click_id(context, page_obj, "10", button="right") |
| right_clicks = await page_obj.evaluate("() => window.clickCount") |
| assert ( |
| right_clicks == final_clicks |
| ), "Right click should not increment clickCount" |
|
|
| |
| await pc.click_id(context, page_obj, "10", hold=0.2) |
| held_clicks = await page_obj.evaluate("() => window.clickCount") |
| assert ( |
| held_clicks == right_clicks + 1 |
| ), "Held left click should increment clickCount by 1" |
|
|
| |
| |
| try: |
| await pc.click_id(context, page_obj, "11") |
| except Exception: |
| |
| pass |
|
|
| async def test_hover_id(self, page): |
| page_obj, pc = page |
| |
| await pc.hover_id(page_obj, "10") |
| |
|
|
| async def test_fill_id(self, page): |
| page_obj, pc = page |
| |
| await pc.fill_id(page_obj, "13", "Hello world", press_enter=False) |
| |
| value = await page_obj.evaluate( |
| "() => document.querySelector('#input-box').value" |
| ) |
| assert value == "Hello world" |
|
|
| async def test_scroll_id(self, page): |
| page_obj, pc = page |
| |
| |
| await pc.scroll_id(page_obj, "14", "down") |
| await pc.scroll_id(page_obj, "14", "up") |
|
|
| async def test_select_option(self, context, page): |
| page_obj, pc = page |
| |
| await pc.select_option(context, page_obj, "16") |
| |
| selected_value = await page_obj.evaluate( |
| "() => document.querySelector('#dropdown').value" |
| ) |
| assert selected_value == "two" |
|
|
| async def test_get_tabs_information(self, context, page): |
| page_obj, pc = page |
| tabs_info = await pc.get_tabs_information(context, page_obj) |
| assert len(tabs_info) > 0 |
| assert isinstance(tabs_info, list) |
| |
| assert "index" in tabs_info[0] |
| assert "title" in tabs_info[0] |
| assert "url" in tabs_info[0] |
|
|
| async def test_switch_tab_and_close_tab(self, context, page): |
| page_obj, pc = page |
|
|
| |
| page2 = await context.new_page() |
| await page2.set_content("<html><body><p>Another page</p></body></html>") |
| |
| switched_page = await pc.switch_tab(context, 1) |
| assert switched_page == page2 |
|
|
| |
| |
| new_active_page = await pc.close_tab(context, 1) |
| assert new_active_page == page_obj |
|
|
| async def test_create_new_tab(self, context, page): |
| page_obj, pc = page |
| new_tab = await pc.create_new_tab( |
| context, |
| "data:text/html;base64," + base64.b64encode(FAKE_HTML.encode()).decode(), |
| ) |
| assert new_tab is not None |
| |
| await new_tab.wait_for_selector("#header") |
|
|
| async def test_get_all_webpage_text(self, page): |
| page_obj, pc = page |
| text = await pc.get_all_webpage_text(page_obj, n_lines=10) |
| assert "Welcome to the Fake Page" in text |
|
|
| async def test_get_visible_text(self, page): |
| page_obj, pc = page |
| visible_text = await pc.get_visible_text(page_obj) |
| assert "Welcome to the Fake Page" in visible_text |
| |
| assert "Hidden Button" not in visible_text |
|
|
| async def test_get_page_markdown(self, page): |
| page_obj, pc = page |
| |
| try: |
| markdown = await pc.get_page_markdown(page_obj, max_tokens=1000) |
| assert "Welcome to the Fake Page" in markdown |
| except ImportError: |
| pytest.skip("MarkItDown library not installed; skipping markdown test.") |
|
|
| async def test_describe_page(self, page): |
| page_obj, pc = page |
| message, screenshot_bytes, metadata_hash = await pc.describe_page( |
| page_obj, get_screenshot=True |
| ) |
| assert "Fake Page" in message |
| assert metadata_hash |
| assert screenshot_bytes is not None |
| assert len(screenshot_bytes) > 0 |
|
|
| async def test_select_multiple_options(self, context, page): |
| page_obj, pc = page |
| |
| await pc.select_option(context, page_obj, "20") |
|
|
| |
| selected_values = await page_obj.evaluate( |
| "() => Array.from(document.querySelector('#multi-dropdown').selectedOptions).map(opt => opt.value)" |
| ) |
| assert "green" in selected_values |
| assert len(selected_values) == 1 |
|
|
| async def test_expand_and_select_dropdown(self, context, page): |
| page_obj, pc = page |
|
|
| |
| await pc.click_id(context, page_obj, "22") |
|
|
| |
| is_visible = await page_obj.evaluate( |
| "() => document.querySelector('.dropdown-content').style.display === 'block'" |
| ) |
| assert is_visible, "Dropdown content should be visible after clicking" |
|
|
| |
| await pc.click_id(context, page_obj, "24") |
|
|
| |
| button_text = await page_obj.evaluate( |
| "() => document.querySelector('.dropdown-button').textContent" |
| ) |
| assert "Beta" in button_text, "Dropdown button should show selected option" |
|
|
| |
| is_hidden = await page_obj.evaluate( |
| "() => document.querySelector('.dropdown-content').style.display === 'none'" |
| ) |
| assert is_hidden, "Dropdown content should be hidden after selection" |
|
|
| @pytest.mark.parametrize("single_tab_mode", [False]) |
| async def test_new_page_button(self, browser, context, tmp_path, single_tab_mode): |
| """Test behavior of a button that opens a new page in both single-tab and multi-tab modes.""" |
|
|
| |
| downloads_folder = str(tmp_path / "downloads") |
| os.makedirs(downloads_folder, exist_ok=True) |
| pc = PlaywrightController( |
| downloads_folder=downloads_folder, |
| animate_actions=False, |
| viewport_width=800, |
| viewport_height=600, |
| to_resize_viewport=True, |
| timeout_load=2, |
| sleep_after_action=1, |
| single_tab_mode=single_tab_mode, |
| ) |
| |
| page = await context.new_page() |
| await page.set_content(FAKE_HTML) |
| await pc.on_new_page(page) |
|
|
| |
| initial_tabs = len(context.pages) |
|
|
| |
| new_page = await pc.click_id(context, page, "26") |
|
|
| |
| final_tabs = len(context.pages) |
|
|
| if single_tab_mode: |
| |
| |
| |
| assert new_page is None |
| assert final_tabs == initial_tabs |
|
|
| |
| current_content = await page.content() |
| assert "New Page" in current_content |
|
|
| else: |
| |
| |
| |
| assert final_tabs == initial_tabs + 1 |
| assert new_page is not None |
|
|
| |
| new_page_content = await new_page.content() |
| assert "New Page" in new_page_content |
|
|
| |
| original_content = await page.content() |
| assert "Welcome to the Fake Page" in original_content |
|
|
| async def test_download_file(self, browser, context, tmp_path): |
| """Test downloading a file and saving it to the downloads folder.""" |
| |
| downloads_folder = str(tmp_path / "downloads") |
| os.makedirs(downloads_folder, exist_ok=True) |
| pc = PlaywrightController( |
| downloads_folder=downloads_folder, |
| animate_actions=False, |
| viewport_width=800, |
| viewport_height=600, |
| to_resize_viewport=True, |
| timeout_load=2, |
| sleep_after_action=1, |
| single_tab_mode=False, |
| ) |
|
|
| |
| page = await context.new_page() |
| await pc.on_new_page(page) |
|
|
| |
| download_html = """ |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>Download Test</title> |
| <script> |
| window.clickCount = 0; |
| function incrementClickCount() { |
| window.clickCount++; |
| console.log('Click count:', window.clickCount); |
| } |
| </script> |
| </head> |
| <body> |
| <a href="data:text/plain;base64,SGVsbG8gV29ybGQ=" |
| download="test.txt" |
| id="download-link" |
| onclick="incrementClickCount()" |
| __elementId="1">Download Text File</a> |
| </body> |
| </html> |
| """ |
| await page.set_content(download_html) |
|
|
| |
| initial_clicks = await page.evaluate("() => window.clickCount") |
| assert initial_clicks == 0 |
|
|
| |
| _ = await pc.click_id(context, page, "1") |
|
|
| |
| final_clicks = await page.evaluate("() => window.clickCount") |
| assert final_clicks == 1, "Download link was not clicked" |
|
|
| |
| downloaded_files = os.listdir(downloads_folder) |
| assert len(downloaded_files) == 1, "Expected one downloaded file" |
| assert downloaded_files[0] == "test.txt", "Expected file named test.txt" |
|
|
| |
| with open(os.path.join(downloads_folder, "test.txt"), "r") as f: |
| content = f.read() |
| assert content == "Hello World", "Expected file content to be 'Hello World'" |
|
|
| |
| await page.close() |
|
|
| async def test_upload_file(self, browser, context, tmp_path): |
| """Test uploading a file to a file input element.""" |
| |
| downloads_folder = str(tmp_path / "downloads") |
| os.makedirs(downloads_folder, exist_ok=True) |
| pc = PlaywrightController( |
| downloads_folder=downloads_folder, |
| animate_actions=False, |
| viewport_width=800, |
| viewport_height=600, |
| to_resize_viewport=True, |
| timeout_load=2, |
| sleep_after_action=1, |
| single_tab_mode=False, |
| ) |
|
|
| |
| page = await context.new_page() |
| await pc.on_new_page(page) |
|
|
| |
| upload_html = """ |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>File Upload Test</title> |
| <script> |
| function displayFileName() { |
| const fileInput = document.getElementById('file-input'); |
| const fileDisplay = document.getElementById('file-display'); |
| if (fileInput.files.length > 0) { |
| fileDisplay.textContent = 'Selected file: ' + fileInput.files[0].name; |
| } else { |
| fileDisplay.textContent = 'No file selected'; |
| } |
| } |
| </script> |
| </head> |
| <body> |
| <h1>File Upload Test</h1> |
| <input type="file" id="file-input" __elementId="30" onchange="displayFileName()"> |
| <div id="file-display">No file selected</div> |
| </body> |
| </html> |
| """ |
| await page.set_content(upload_html) |
|
|
| |
| test_file_path = os.path.join(tmp_path, "test_upload.txt") |
| with open(test_file_path, "w") as f: |
| f.write("This is a test file for upload") |
|
|
| |
| await pc.upload_file(page, "30", test_file_path) |
|
|
| |
| file_display_text = await page.evaluate( |
| "() => document.getElementById('file-display').textContent" |
| ) |
| assert "test_upload.txt" in file_display_text, "File was not properly uploaded" |
|
|
| |
| await page.close() |
|
|
| async def test_double_click_coords(self, page): |
| page_obj, pc = page |
| |
| await page_obj.evaluate(""" |
| window.doubleClickCount = 0; |
| document.addEventListener('dblclick', () => { |
| window.doubleClickCount++; |
| }); |
| """) |
|
|
| |
| button = await page_obj.query_selector("#click-me") |
| box = await button.bounding_box() |
| x = box["x"] + box["width"] / 2 |
| y = box["y"] + box["height"] / 2 |
|
|
| |
| await pc.double_click_coords(page_obj, x, y) |
|
|
| |
| double_clicks = await page_obj.evaluate("() => window.doubleClickCount") |
| assert double_clicks == 1, "Double click was not registered" |
|
|
| async def test_scroll_coords(self, page): |
| page_obj, pc = page |
| |
| await page_obj.evaluate(""" |
| const div = document.createElement('div'); |
| div.style.height = '2000px'; |
| div.textContent = 'Tall content'; |
| document.body.appendChild(div); |
| """) |
|
|
| |
| initial_scroll = await page_obj.evaluate("() => window.scrollY") |
|
|
| |
| await pc.scroll_coords(page_obj, 0, 0, 0, 100) |
|
|
| |
| new_scroll = await page_obj.evaluate("() => window.scrollY") |
| assert new_scroll > initial_scroll, "Page did not scroll down" |
|
|
| async def test_scroll_mousewheel(self, page): |
| page_obj, pc = page |
| |
| await page_obj.evaluate(""" |
| const div = document.createElement('div'); |
| div.style.height = '3000px'; |
| div.textContent = 'Very tall content for mousewheel scrolling test'; |
| document.body.appendChild(div); |
| """) |
|
|
| |
| initial_scroll = await page_obj.evaluate("() => window.scrollY") |
| assert initial_scroll == 0, "Page should start at top" |
|
|
| |
| await pc.scroll_mousewheel(page_obj, "down") |
| after_down_scroll = await page_obj.evaluate("() => window.scrollY") |
| assert after_down_scroll > initial_scroll, "Page should scroll down" |
| assert ( |
| after_down_scroll >= 400 |
| ), f"Page should scroll at least 400 pixels, got {after_down_scroll}" |
|
|
| |
| await pc.scroll_mousewheel(page_obj, "down", 200) |
| after_custom_down = await page_obj.evaluate("() => window.scrollY") |
| assert after_custom_down > after_down_scroll, "Page should scroll down more" |
| expected_scroll = after_down_scroll + 200 |
| assert ( |
| abs(after_custom_down - expected_scroll) <= 10 |
| ), f"Expected scroll ~{expected_scroll}, got {after_custom_down}" |
|
|
| |
| await pc.scroll_mousewheel(page_obj, "up") |
| after_up_scroll = await page_obj.evaluate("() => window.scrollY") |
| assert after_up_scroll < after_custom_down, "Page should scroll up" |
| expected_up_scroll = after_custom_down - 400 |
| assert ( |
| abs(after_up_scroll - expected_up_scroll) <= 10 |
| ), f"Expected scroll ~{expected_up_scroll}, got {after_up_scroll}" |
|
|
| |
| await pc.scroll_mousewheel(page_obj, "up", 200) |
| final_scroll = await page_obj.evaluate("() => window.scrollY") |
| assert final_scroll < after_up_scroll, "Page should scroll up more" |
| expected_final = max( |
| 0, after_up_scroll - 200 |
| ) |
| assert ( |
| abs(final_scroll - expected_final) <= 10 |
| ), f"Expected scroll ~{expected_final}, got {final_scroll}" |
|
|
| |
| current_scroll = await page_obj.evaluate("() => window.scrollY") |
| await pc.scroll_mousewheel(page_obj, "DOWN", 100) |
| after_case_test = await page_obj.evaluate("() => window.scrollY") |
| assert after_case_test > current_scroll, "Uppercase 'DOWN' should work" |
|
|
| |
| await pc.scroll_mousewheel(page_obj, "up", 5000) |
| top_scroll = await page_obj.evaluate("() => window.scrollY") |
| assert top_scroll == 0, "Should not scroll beyond top of page" |
|
|
| async def test_type_direct(self, page): |
| page_obj, pc = page |
| |
| input_box = await page_obj.query_selector("#input-box") |
| await input_box.focus() |
|
|
| |
| test_text = "Hello World" |
| await pc.type_direct(page_obj, test_text) |
|
|
| |
| value = await page_obj.evaluate( |
| "() => document.querySelector('#input-box').value" |
| ) |
| assert value == test_text, "Text was not typed correctly" |
|
|
| async def test_hover_coords(self, page): |
| page_obj, pc = page |
| |
| await page_obj.evaluate(""" |
| window.isHovered = false; |
| document.querySelector('#click-me').addEventListener('mouseover', () => { |
| window.isHovered = true; |
| }); |
| document.querySelector('#click-me').addEventListener('mouseout', () => { |
| window.isHovered = false; |
| }); |
| """) |
|
|
| |
| button = await page_obj.query_selector("#click-me") |
| box = await button.bounding_box() |
| x = box["x"] + box["width"] / 2 |
| y = box["y"] + box["height"] / 2 |
|
|
| |
| await pc.hover_coords(page_obj, x, y) |
|
|
| |
| is_hovered = await page_obj.evaluate("() => window.isHovered") |
| assert is_hovered, "Hover was not detected" |
|
|
| async def test_keypress(self, page): |
| page_obj, pc = page |
| |
| input_box = await page_obj.query_selector("#input-box") |
| await input_box.focus() |
|
|
| |
| |
| await pc.keypress(page_obj, ["a", "b", "c"]) |
| value = await page_obj.evaluate( |
| "() => document.querySelector('#input-box').value" |
| ) |
| assert "abc" in value, "Single key press not registered" |
|
|
| async def test_drag_coords(self, page): |
| page_obj, pc = page |
| |
| await page_obj.evaluate(""" |
| window.dragPath = []; |
| document.addEventListener('mousedown', (e) => { |
| window.dragPath = [{x: e.clientX, y: e.clientY}]; |
| }); |
| document.addEventListener('mousemove', (e) => { |
| if (e.buttons === 1) { // Left button is being pressed |
| window.dragPath.push({x: e.clientX, y: e.clientY}); |
| } |
| }); |
| """) |
|
|
| |
| drag_path = [ |
| {"x": 100, "y": 100}, |
| {"x": 200, "y": 200}, |
| ] |
|
|
| |
| await pc.drag_coords(page_obj, drag_path) |
|
|
| |
| path_length = await page_obj.evaluate("() => window.dragPath.length") |
| assert path_length > 0, "Drag path was not recorded" |
|
|
| |
| start_point = await page_obj.evaluate("() => window.dragPath[0]") |
| end_point = await page_obj.evaluate( |
| "() => window.dragPath[window.dragPath.length - 1]" |
| ) |
| assert ( |
| abs(start_point["x"] - drag_path[0]["x"]) < 5 |
| ), "Drag didn't start at correct X coordinate" |
| assert ( |
| abs(start_point["y"] - drag_path[0]["y"]) < 5 |
| ), "Drag didn't start at correct Y coordinate" |
| assert ( |
| abs(end_point["x"] - drag_path[-1]["x"]) < 5 |
| ), "Drag didn't end at correct X coordinate" |
| assert ( |
| abs(end_point["y"] - drag_path[-1]["y"]) < 5 |
| ), "Drag didn't end at correct Y coordinate" |
|
|
| async def test_click_coords(self, context, page): |
| page_obj, pc = page |
| |
| button = await page_obj.query_selector("#click-me") |
| box = await button.bounding_box() |
| x = box["x"] + box["width"] / 2 |
| y = box["y"] + box["height"] / 2 |
|
|
| |
| initial_clicks = await page_obj.evaluate("() => window.clickCount") |
| await pc.click_coords(page_obj, x, y, "left") |
| final_clicks = await page_obj.evaluate("() => window.clickCount") |
| assert final_clicks == initial_clicks + 1, "Left click not registered" |
|
|
| |
| await pc.click_coords(page_obj, x, y, "right") |
| |
|
|
| |
| await pc.click_coords(page_obj, x, y, "wheel") |
| |
|
|