from time import sleep import pytest import webview from .util import run_test @pytest.fixture def window(): return webview.create_window( 'DOM test', html="""
DUDE
""", ) def test_element(window): run_test(webview, window, element_test) def test_classes(window): run_test(webview, window, classes_test) def test_attributes(window): run_test(webview, window, attributes_test) def test_style(window): run_test(webview, window, style_test) def test_traversal(window): run_test(webview, window, traversal_test) def test_visibility(window): run_test(webview, window, visibility_test) def test_focus(window): run_test(webview, window, focus_test) def test_manipulation(window): run_test(webview, window, manipulation_test) def test_manipulation_modes(window): run_test(webview, window, manipulation_mode_test) def test_events(window): run_test(webview, window, events_test) def test_special_char_attributes(window): run_test(webview, window, special_char_attributes_test) def element_test(window): child1 = window.dom.get_element('#child1') assert child1.id == 'child1' assert child1.tag == 'div' assert child1.tabindex == 3 assert child1.text == 'DUDE' child1.text = 'WOW' assert child1.text == 'WOW' child1.tabindex = 10 assert child1.tabindex == 10 input = window.dom.get_element('#input') assert input.value == 'pizdec' input.value = 'tisok' assert input.value == 'tisok' def classes_test(window): child1 = window.dom.get_element('#child1') assert list(child1.classes) == ['test'] child1.classes.append('test2') assert list(child1.classes) == ['test', 'test2'] child1.classes.toggle('test') assert list(child1.classes) == ['test2'] child1.classes.toggle('test') assert list(child1.classes) == ['test2', 'test'] child1.classes = ['woah'] assert list(child1.classes) == ['woah'] child1.classes.clear() assert len(child1.classes) == 0 def attributes_test(window): child1 = window.dom.get_element('#child1') assert dict(child1.attributes) == { 'class': 'test', 'id': 'child1', 'data-id': 'blz', 'tabindex': '3', } assert child1.attributes['class'] == 'test' assert set(child1.attributes.keys()) == {'class', 'id', 'data-id', 'tabindex'} assert set(child1.attributes.values()) == {'test', 'child1', 'blz', '3'} assert set(child1.attributes.items()) == { ('class', 'test'), ('id', 'child1'), ('data-id', 'blz'), ('tabindex', '3'), } assert child1.attributes.get('class') == 'test' assert child1.attributes.get('class2') is None assert child1.attributes['class2'] is None del child1.attributes['class'] assert dict(child1.attributes) == {'id': 'child1', 'data-id': 'blz', 'tabindex': '3'} child1.attributes['data-test'] = 'test2' assert dict(child1.attributes) == { 'id': 'child1', 'data-id': 'blz', 'tabindex': '3', 'data-test': 'test2', } child1.attributes = {'data-test': 'test3'} assert child1.attributes['data-test'] == 'test3' child1.attributes.clear() assert dict(child1.attributes) == {} def style_test(window): child3 = window.dom.get_element('#child3') assert child3.style['display'] == 'none' assert child3.style['background-color'] == 'rgb(255, 0, 0)' child3.style['display'] = 'flex' child3.style['background-color'] = 'rgb(0, 0, 255)' assert child3.style['display'] == 'flex' assert child3.style['background-color'] == 'rgb(0, 0, 255)' child3.style.clear() assert child3.style['display'] == 'block' assert child3.style['background-color'] == 'rgba(0, 0, 0, 0)' def visibility_test(window): child3 = window.dom.get_element('#child3') assert not child3.visible child3.show() assert child3.visible child3.hide() assert not child3.visible child3.toggle() assert child3.visible child3.toggle() assert not child3.visible def focus_test(window): input = window.dom.get_element('#input') assert not input.focused input.focus() assert input.focused input.blur() assert not input.focused def traversal_test(window): child2 = window.dom.get_element('#child2') assert child2.parent.id == 'container' assert child2.next.id == 'child3' assert child2.previous.id == 'child1' children = window.dom.get_element('#container').children assert len(children) == 3 assert children[0].id == 'child1' assert children[1].id == 'child2' assert children[2].id == 'child3' def manipulation_test(window): container = window.dom.get_element('#container') container2 = window.dom.get_element('#container2') assert len(container.children) == 3 container.empty() assert container.children == [] container.append('
') assert len(container.children) == 1 assert container.children[0].id == 'child1' child2 = window.dom.create_element( '
CHILD
', container ) assert len(container.children) == 2 assert container.children[1].id == 'child2' assert child2.parent.id == 'container' assert child2.id == 'child2' child3 = child2.copy(container2) assert len(container2.children) == 3 assert container2.children[2].text == 'CHILD' assert list(child3.classes) == ['child-class'] assert child3.id == '' assert child2._node_id != child3._node_id child4 = child2.copy() child4.parent.id = 'container' assert len(container.children) == 3 child4.move(container2) assert len(container.children) == 2 assert len(container2.children) == 4 container.children[0].remove() assert len(container.children) == 1 assert container.children[0].id == 'child2' def manipulation_mode_test(window): child1 = window.dom.get_element('#child1') child2 = window.dom.get_element('#child2') child3 = window.dom.get_element('#child3') container2 = window.dom.get_element('#container2') child1.move(container2, mode=webview.dom.ManipulationMode.FirstChild) assert container2.children[0].id == 'child1' child2.move(container2, mode=webview.dom.ManipulationMode.LastChild) assert container2.children[-1].id == 'child2' child3.move(child1, mode=webview.dom.ManipulationMode.Before) assert container2.children[0].id == 'child3' child1.move(child2, mode=webview.dom.ManipulationMode.After) assert container2.children[-1].id == 'child1' child2.move(container2, mode=webview.dom.ManipulationMode.Replace) assert window.dom.get_element('#container2') is None assert child2.parent.tag == 'body' def events_test(window): def click_handler(event): nonlocal button_value assert event['target']['id'] == 'button' button_value = True button_value = False button = window.dom.get_element('#button') button.events.click += click_handler window.evaluate_js('document.getElementById("button").click()') assert button_value button.events.click -= click_handler button_value = False window.evaluate_js('document.getElementById("button").click()') sleep(0.1) assert not button_value assert window.evaluate_js('Object.keys(pywebview._eventHandlers).length === 0') def special_char_attributes_test(window): """Test attributes containing special characters like single quotes and backslashes""" child1 = window.dom.get_element('#child1') # Test setting and getting attributes with double quotes (should work with JSON) child1.attributes['data-double-quote'] = 'value with "double quotes"' assert child1.attributes['data-double-quote'] == 'value with "double quotes"' # Test setting and getting attributes with backslashes (JSON escapes these) child1.attributes['data-backslash'] = 'value with \\backslash' assert child1.attributes['data-backslash'] == 'value with \\backslash' # Test setting and getting attributes with newlines and tabs child1.attributes['data-whitespace'] = 'value with\nnewline and\ttab' assert child1.attributes['data-whitespace'] == 'value with\nnewline and\ttab' # Test setting and getting attributes with HTML entities child1.attributes['data-html'] = 'value with <tags> and & symbols' assert child1.attributes['data-html'] == 'value with <tags> and & symbols' # Test setting and getting attributes with Unicode characters child1.attributes['data-unicode'] = 'value with unicode: ñáéíóú 中文 🚀' assert child1.attributes['data-unicode'] == 'value with unicode: ñáéíóú 中文 🚀' # Test setting and getting attributes with forward slashes child1.attributes['data-slashes'] = 'value/with/forward/slashes' assert child1.attributes['data-slashes'] == 'value/with/forward/slashes' # Test that all special character attributes are preserved special_attrs = {k: v for k, v in child1.attributes.items() if k.startswith('data-')} expected_attrs = { 'data-id': 'blz', # original attribute 'data-double-quote': 'value with "double quotes"', 'data-backslash': 'value with \\backslash', 'data-whitespace': 'value with\nnewline and\ttab', 'data-html': 'value with <tags> and & symbols', 'data-unicode': 'value with unicode: ñáéíóú 中文 🚀', 'data-slashes': 'value/with/forward/slashes', } for key, expected_value in expected_attrs.items(): assert key in special_attrs, f'Attribute {key} not found' assert ( special_attrs[key] == expected_value ), f'Attribute {key} value mismatch: expected {expected_value}, got {special_attrs[key]}' # Test clearing special character attributes for key in [ 'data-double-quote', 'data-backslash', 'data-whitespace', 'data-html', 'data-unicode', 'data-slashes', ]: del child1.attributes[key] assert child1.attributes[key] is None