Skip to content

Commit 6724b42

Browse files
committed
add bidi script tests
1 parent f4ae779 commit 6724b42

File tree

1 file changed

+335
-0
lines changed

1 file changed

+335
-0
lines changed

py/test/selenium/webdriver/common/bidi_script_tests.py

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18+
import pytest
19+
1820
from selenium.webdriver.common.bidi.log import LogLevel
21+
from selenium.webdriver.common.bidi.script import RealmType, ResultOwnership
1922
from selenium.webdriver.common.by import By
2023
from selenium.webdriver.support.ui import WebDriverWait
2124

@@ -127,3 +130,335 @@ def test_removes_javascript_message_handler(driver, pages):
127130

128131
WebDriverWait(driver, 5).until(lambda _: len(log_entries2) == 2)
129132
assert len(log_entries1) == 1
133+
134+
135+
def test_add_preload_script(driver, pages):
136+
"""Test adding a preload script."""
137+
function_declaration = "() => { window.preloadExecuted = true; }"
138+
139+
script_id = driver.script.add_preload_script(function_declaration)
140+
assert script_id is not None
141+
assert isinstance(script_id, str)
142+
143+
# Navigate to a page to trigger the preload script
144+
pages.load("blank.html")
145+
146+
# Check if the preload script was executed
147+
result = driver.script.evaluate(
148+
"window.preloadExecuted", {"context": driver.current_window_handle}, await_promise=False
149+
)
150+
assert result.result["value"] is True
151+
152+
153+
def test_add_preload_script_with_arguments(driver, pages):
154+
"""Test adding a preload script with channel arguments."""
155+
function_declaration = "(channelFunc) => { channelFunc('test_value'); window.preloadValue = 'received'; }"
156+
157+
arguments = [{"type": "channel", "value": {"channel": "test-channel", "ownership": "root"}}]
158+
159+
script_id = driver.script.add_preload_script(function_declaration, arguments=arguments)
160+
assert script_id is not None
161+
162+
pages.load("blank.html")
163+
164+
result = driver.script.evaluate(
165+
"window.preloadValue", {"context": driver.current_window_handle}, await_promise=False
166+
)
167+
assert result.result["value"] == "received"
168+
169+
170+
def test_add_preload_script_with_contexts(driver, pages):
171+
"""Test adding a preload script with specific contexts."""
172+
function_declaration = "() => { window.contextSpecific = true; }"
173+
contexts = [driver.current_window_handle]
174+
175+
script_id = driver.script.add_preload_script(function_declaration, contexts=contexts)
176+
assert script_id is not None
177+
178+
pages.load("blank.html")
179+
180+
result = driver.script.evaluate(
181+
"window.contextSpecific", {"context": driver.current_window_handle}, await_promise=False
182+
)
183+
assert result.result["value"] is True
184+
185+
186+
def test_add_preload_script_invalid_arguments(driver):
187+
"""Test that providing both contexts and user_contexts raises an error."""
188+
function_declaration = "() => {}"
189+
190+
with pytest.raises(ValueError, match="Cannot specify both contexts and user_contexts"):
191+
driver.script.add_preload_script(function_declaration, contexts=["context1"], user_contexts=["user1"])
192+
193+
194+
def test_remove_preload_script(driver, pages):
195+
"""Test removing a preload script."""
196+
function_declaration = "() => { window.removableScript = true; }"
197+
198+
script_id = driver.script.add_preload_script(function_declaration)
199+
driver.script.remove_preload_script(script_id=script_id)
200+
201+
# Navigate to a page after removing the script
202+
pages.load("blank.html")
203+
204+
# The script should not have executed
205+
result = driver.script.evaluate(
206+
"typeof window.removableScript", {"context": driver.current_window_handle}, await_promise=False
207+
)
208+
assert result.result["value"] == "undefined"
209+
210+
211+
def test_evaluate_expression(driver, pages):
212+
"""Test evaluating a simple expression."""
213+
pages.load("blank.html")
214+
215+
result = driver.script.evaluate("1 + 2", {"context": driver.current_window_handle}, await_promise=False)
216+
217+
assert result.realm is not None
218+
assert result.result["type"] == "number"
219+
assert result.result["value"] == 3
220+
assert result.exception_details is None
221+
222+
223+
def test_evaluate_with_await_promise(driver, pages):
224+
"""Test evaluating an expression that returns a promise."""
225+
pages.load("blank.html")
226+
227+
result = driver.script.evaluate(
228+
"Promise.resolve(42)", {"context": driver.current_window_handle}, await_promise=True
229+
)
230+
231+
assert result.result["type"] == "number"
232+
assert result.result["value"] == 42
233+
234+
235+
def test_evaluate_with_exception(driver, pages):
236+
"""Test evaluating an expression that throws an exception."""
237+
pages.load("blank.html")
238+
239+
result = driver.script.evaluate(
240+
"throw new Error('Test error')", {"context": driver.current_window_handle}, await_promise=False
241+
)
242+
243+
assert result.exception_details is not None
244+
assert "Test error" in str(result.exception_details)
245+
246+
247+
def test_call_function(driver, pages):
248+
"""Test calling a function."""
249+
pages.load("blank.html")
250+
251+
result = driver.script.call_function(
252+
"(a, b) => a + b",
253+
await_promise=False,
254+
target={"context": driver.current_window_handle},
255+
arguments=[{"type": "number", "value": 5}, {"type": "number", "value": 3}],
256+
)
257+
258+
assert result.result["type"] == "number"
259+
assert result.result["value"] == 8
260+
261+
262+
def test_call_function_with_this(driver, pages):
263+
"""Test calling a function with a specific 'this' value."""
264+
pages.load("blank.html")
265+
266+
# First set up an object
267+
driver.script.evaluate(
268+
"window.testObj = { value: 10 }", {"context": driver.current_window_handle}, await_promise=False
269+
)
270+
271+
result = driver.script.call_function(
272+
"function() { return this.value; }",
273+
await_promise=False,
274+
target={"context": driver.current_window_handle},
275+
this={"type": "object", "value": [["value", {"type": "number", "value": 20}]]},
276+
)
277+
278+
assert result.result["type"] == "number"
279+
assert result.result["value"] == 20
280+
281+
282+
def test_call_function_with_user_activation(driver, pages):
283+
"""Test calling a function with user activation."""
284+
pages.load("blank.html")
285+
286+
result = driver.script.call_function(
287+
"() => navigator.userActivation ? navigator.userActivation.isActive : false",
288+
await_promise=False,
289+
target={"context": driver.current_window_handle},
290+
user_activation=True,
291+
)
292+
293+
# Note: The actual behavior depends on browser implementation
294+
assert result.result is not None
295+
296+
297+
def test_get_realms(driver, pages):
298+
"""Test getting all realms."""
299+
pages.load("blank.html")
300+
301+
realms = driver.script.get_realms()
302+
303+
assert len(realms) > 0
304+
assert all(hasattr(realm, "realm") for realm in realms)
305+
assert all(hasattr(realm, "origin") for realm in realms)
306+
assert all(hasattr(realm, "type") for realm in realms)
307+
308+
309+
def test_get_realms_filtered_by_context(driver, pages):
310+
"""Test getting realms filtered by context."""
311+
pages.load("blank.html")
312+
313+
realms = driver.script.get_realms(context=driver.current_window_handle)
314+
315+
assert len(realms) > 0
316+
# All realms should be associated with the specified context
317+
for realm in realms:
318+
if realm.context is not None:
319+
assert realm.context == driver.current_window_handle
320+
321+
322+
def test_get_realms_filtered_by_type(driver, pages):
323+
"""Test getting realms filtered by type."""
324+
pages.load("blank.html")
325+
326+
realms = driver.script.get_realms(type=RealmType.WINDOW)
327+
328+
assert len(realms) > 0
329+
# All realms should be of the specified type
330+
for realm in realms:
331+
assert realm.type == RealmType.WINDOW
332+
333+
334+
def test_disown_handles(driver, pages):
335+
"""Test disowning handles."""
336+
pages.load("blank.html")
337+
338+
# First create some handles by evaluating an object
339+
result = driver.script.evaluate(
340+
"({ test: 'value' })",
341+
{"context": driver.current_window_handle},
342+
await_promise=False,
343+
result_ownership=ResultOwnership.ROOT,
344+
)
345+
346+
# Extract handle from result (this would be implementation specific)
347+
if "handle" in result.result:
348+
handle = result.result["handle"]
349+
350+
# Disown the handle
351+
driver.script.disown(handles=[handle], target={"context": driver.current_window_handle})
352+
353+
# The disown operation should complete without error
354+
# Note: We can't easily test the actual garbage collection behavior, try something
355+
356+
357+
def test_evaluate_with_result_ownership(driver, pages):
358+
"""Test evaluating with different result ownership settings."""
359+
pages.load("blank.html")
360+
361+
# Test with ROOT ownership
362+
result = driver.script.evaluate(
363+
"({ test: 'value' })",
364+
{"context": driver.current_window_handle},
365+
await_promise=False,
366+
result_ownership=ResultOwnership.ROOT,
367+
)
368+
369+
assert result.result is not None
370+
371+
# Test with NONE ownership
372+
result = driver.script.evaluate(
373+
"({ test: 'value' })",
374+
{"context": driver.current_window_handle},
375+
await_promise=False,
376+
result_ownership=ResultOwnership.NONE,
377+
)
378+
379+
assert result.result is not None
380+
381+
382+
def test_evaluate_with_serialization_options(driver, pages):
383+
"""Test evaluating with serialization options."""
384+
pages.load("blank.html")
385+
386+
serialization_options = {"maxDomDepth": 1, "maxObjectDepth": 1}
387+
388+
result = driver.script.evaluate(
389+
"document.body",
390+
{"context": driver.current_window_handle},
391+
await_promise=False,
392+
serialization_options=serialization_options,
393+
)
394+
395+
assert result.result is not None
396+
397+
398+
def test_call_function_with_serialization_options(driver, pages):
399+
"""Test calling a function with serialization options."""
400+
pages.load("blank.html")
401+
402+
serialization_options = {"maxDomDepth": 1, "maxObjectDepth": 1}
403+
404+
result = driver.script.call_function(
405+
"() => document.body",
406+
await_promise=False,
407+
target={"context": driver.current_window_handle},
408+
serialization_options=serialization_options,
409+
)
410+
411+
assert result.result is not None
412+
413+
414+
def test_add_preload_script_with_sandbox(driver, pages):
415+
"""Test adding a preload script with sandbox."""
416+
function_declaration = "() => { window.sandboxScript = true; }"
417+
418+
script_id = driver.script.add_preload_script(function_declaration, sandbox="test-sandbox")
419+
assert script_id is not None
420+
421+
pages.load("blank.html")
422+
423+
# The script should execute in the sandbox, have a check to verify this
424+
425+
426+
def test_evaluate_with_user_activation(driver, pages):
427+
"""Test evaluating with user activation."""
428+
pages.load("blank.html")
429+
430+
result = driver.script.evaluate(
431+
"navigator.userActivation ? navigator.userActivation.isActive : false",
432+
{"context": driver.current_window_handle},
433+
await_promise=False,
434+
user_activation=True,
435+
)
436+
437+
assert result.result is not None
438+
# try to verify user_activation
439+
440+
441+
def test_call_function_with_exception(driver, pages):
442+
"""Test calling a function that throws an exception."""
443+
pages.load("blank.html")
444+
445+
result = driver.script.call_function(
446+
"() => { throw new Error('Function error'); }",
447+
await_promise=False,
448+
target={"context": driver.current_window_handle},
449+
)
450+
451+
assert result.exception_details is not None
452+
assert "Function error" in str(result.exception_details)
453+
454+
455+
def test_call_function_with_await_promise(driver, pages):
456+
"""Test calling a function that returns a promise."""
457+
pages.load("blank.html")
458+
459+
result = driver.script.call_function(
460+
"() => Promise.resolve('async result')", await_promise=True, target={"context": driver.current_window_handle}
461+
)
462+
463+
assert result.result["type"] == "string"
464+
assert result.result["value"] == "async result"

0 commit comments

Comments
 (0)