fixtures_http.py (8252B)
1 import base64 2 3 import pytest 4 from webdriver.error import NoSuchAlertException, NoSuchWindowException 5 6 from tests.support.image import png_dimensions, ImageDifference 7 from tests.support.sync import Poll 8 9 10 @pytest.fixture 11 def add_event_listeners(): 12 """Register listeners for tracked events on element.""" 13 def add_event_listeners(element, tracked_events): 14 element.session.execute_script(""" 15 const element = arguments[0]; 16 const trackedEvents = arguments[1]; 17 18 if (!("events" in window)) { 19 window.events = []; 20 } 21 22 for (let i = 0; i < trackedEvents.length; i++) { 23 element.addEventListener(trackedEvents[i], function (event) { 24 window.events.push(event.type); 25 }); 26 } 27 """, args=(element, tracked_events)) 28 return add_event_listeners 29 30 31 @pytest.fixture 32 def closed_frame(session, url): 33 """Create a frame and remove it after switching to it. 34 35 The removed frame will be kept selected, which allows to test for invalid 36 browsing context references. 37 """ 38 original_handle = session.window_handle 39 new_handle = session.new_window() 40 41 session.window_handle = new_handle 42 43 session.url = url("/webdriver/tests/support/html/frames.html") 44 45 subframe = session.find.css("#sub-frame", all=False) 46 session.switch_to_frame(subframe) 47 48 deleteframe = session.find.css("#delete-frame", all=False) 49 session.switch_to_frame(deleteframe) 50 51 button = session.find.css("#remove-parent", all=False) 52 button.click() 53 54 yield 55 56 session.window.close() 57 assert new_handle not in session.handles, "Unable to close window {}".format(new_handle) 58 59 session.window_handle = original_handle 60 61 62 @pytest.fixture 63 def closed_window(session, inline): 64 """Create a window and close it immediately. 65 66 The window handle will be kept selected, which allows to test for invalid 67 top-level browsing context references. 68 """ 69 original_handle = session.window_handle 70 new_handle = session.new_window() 71 72 session.window_handle = new_handle 73 session.url = inline("<input id='a' value='b'>") 74 element = session.find.css("input", all=False) 75 76 session.window.close() 77 assert new_handle not in session.handles, "Unable to close window {}".format(new_handle) 78 79 yield (original_handle, element) 80 81 session.window_handle = original_handle 82 83 84 @pytest.fixture 85 def create_cookie(session, url): 86 """Create a cookie.""" 87 def create_cookie(name, value, **kwargs): 88 if kwargs.get("path", None) is not None: 89 session.url = url(kwargs["path"]) 90 91 session.set_cookie(name, value, **kwargs) 92 return session.cookies(name) 93 94 return create_cookie 95 96 97 @pytest.fixture 98 def create_dialog(session): 99 """Create a dialog (one of "alert", "prompt", or "confirm"). 100 101 Also it provides a function to validate that the dialog has been "handled" 102 (either accepted or dismissed) by returning some value. 103 """ 104 def create_dialog(dialog_type, text=None): 105 assert dialog_type in ("alert", "confirm", "prompt"), ( 106 "Invalid dialog type: '%s'" % dialog_type) 107 108 if text is None: 109 text = "" 110 111 assert isinstance(text, str), "`text` parameter must be a string" 112 113 # Script completes itself when the user prompt has been opened. 114 # For prompt() dialogs, add a value for the 'default' argument, 115 # as some user agents (IE, for example) do not produce consistent 116 # values for the default. 117 session.execute_async_script(""" 118 let dialog_type = arguments[0]; 119 let text = arguments[1]; 120 121 setTimeout(function() { 122 if (dialog_type == 'prompt') { 123 window.dialog_return_value = window[dialog_type](text, ''); 124 } else { 125 window.dialog_return_value = window[dialog_type](text); 126 } 127 }, 0); 128 """, args=(dialog_type, text)) 129 130 def check_alert_text(s): 131 assert s.alert.text == text, f"No user prompt with text '{text}' detected" 132 133 wait = Poll(session, timeout=15, 134 ignored_exceptions=NoSuchAlertException) 135 wait.until(check_alert_text) 136 137 return create_dialog 138 139 140 @pytest.fixture 141 def create_frame(session): 142 """Create an `iframe` element. 143 144 The element will be inserted into the document of the current browsing 145 context. Return a reference to the newly-created element. 146 """ 147 def create_frame(): 148 append = """ 149 var frame = document.createElement('iframe'); 150 document.body.appendChild(frame); 151 return frame; 152 """ 153 return session.execute_script(append) 154 155 return create_frame 156 157 158 @pytest.fixture 159 def http_new_tab(session): 160 """Create a new tab to run the test isolated.""" 161 original_handle = session.window_handle 162 new_handle = session.new_window(type_hint="tab") 163 164 session.window_handle = new_handle 165 166 yield 167 168 try: 169 # Make sure to close the correct tab that we opened before. 170 session.window_handle = new_handle 171 session.window.close() 172 except NoSuchWindowException: 173 pass 174 175 session.window_handle = original_handle 176 177 178 @pytest.fixture 179 def stale_element(current_session, get_test_page): 180 """Create a stale element reference 181 182 The document will be loaded in the top-level or child browsing context. 183 Before the requested element or its shadow root is returned the element 184 is removed from the document's DOM. 185 """ 186 def stale_element(css_value, as_frame=False, want_shadow_root=False): 187 current_session.url = get_test_page(as_frame=as_frame) 188 189 if as_frame: 190 frame = current_session.find.css("iframe", all=False) 191 current_session.switch_to_frame(frame) 192 193 element = current_session.find.css(css_value, all=False) 194 shadow_root = element.shadow_root if want_shadow_root else None 195 196 current_session.execute_script("arguments[0].remove();", args=[element]) 197 198 return shadow_root if want_shadow_root else element 199 200 return stale_element 201 202 203 @pytest.fixture 204 def load_pdf_http(current_session, test_page_with_pdf_js): 205 """Load a PDF document in the browser using pdf.js""" 206 def load_pdf_http(encoded_pdf_data): 207 current_session.url = test_page_with_pdf_js(encoded_pdf_data) 208 209 return load_pdf_http 210 211 212 @pytest.fixture 213 def render_pdf_to_png_http(current_session, url): 214 """Render a PDF document to png""" 215 216 def render_pdf_to_png_http( 217 encoded_pdf_data, page=1 218 ): 219 current_session.url = url(path="/print_pdf_runner.html") 220 result = current_session.execute_async_script(f"""arguments[0](window.render("{encoded_pdf_data}"))""") 221 index = page - 1 222 223 assert 0 <= index < len(result) 224 225 image_string = result[index] 226 image_string_without_data_type = image_string[image_string.find(",") + 1:] 227 228 return base64.b64decode(image_string_without_data_type) 229 230 return render_pdf_to_png_http 231 232 233 @pytest.fixture 234 def compare_png_http(current_session, url): 235 def compare_png_http(img1, img2): 236 """Calculate difference statistics between two PNG images. 237 238 :param img1: Bytes of first PNG image 239 :param img2: Bytes of second PNG image 240 :returns: ImageDifference representing the total number of different pixels, 241 and maximum per-channel difference between the images. 242 """ 243 if img1 == img2: 244 return ImageDifference(0, 0) 245 246 width, height = png_dimensions(img1) 247 assert (width, height) == png_dimensions(img2) 248 249 current_session.url = url("/webdriver/tests/support/html/render.html") 250 result = current_session.execute_async_script( 251 "const callback = arguments[arguments.length - 1]; callback(compare(arguments[0], arguments[1], arguments[2], arguments[3]))", 252 args=[base64.encodebytes(img1).decode(), base64.encodebytes(img2).decode(), width, height], 253 ) 254 255 assert "maxDifference" in result 256 assert "totalPixels" in result 257 258 return ImageDifference(result["totalPixels"], result["maxDifference"]) 259 260 return compare_png_http