# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. import os import urllib from marionette_driver import By, errors from marionette_driver.marionette import HTMLElement from marionette_driver.wait import Wait from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin def inline(doc): return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc)) elements = inline("

foo

bar

") globals = set([ "atob", "Audio", "btoa", "document", "navigator", "URL", "window", ]) class TestExecuteSimpleTestContent(MarionetteTestCase): def test_stack_trace(self): try: self.marionette.execute_js_script(""" let a = 1; throwHere(); """, filename="file.js") self.assertFalse(True) except errors.JavascriptException as e: self.assertIn("throwHere is not defined", e.message) self.assertIn("@file.js:2", e.stacktrace) class TestExecuteContent(MarionetteTestCase): def assert_is_defined(self, property, sandbox="default"): self.assertTrue(self.marionette.execute_script( "return typeof arguments[0] != 'undefined'", [property], sandbox=sandbox), "property {} is undefined".format(property)) def test_return_number(self): self.assertEqual(1, self.marionette.execute_script("return 1")) self.assertEqual(1.5, self.marionette.execute_script("return 1.5")) def test_return_boolean(self): self.assertTrue(self.marionette.execute_script("return true")) def test_return_string(self): self.assertEqual("foo", self.marionette.execute_script("return 'foo'")) def test_return_array(self): self.assertEqual( [1, 2], self.marionette.execute_script("return [1, 2]")) self.assertEqual( [1.25, 1.75], self.marionette.execute_script("return [1.25, 1.75]")) self.assertEqual( [True, False], self.marionette.execute_script("return [true, false]")) self.assertEqual( ["foo", "bar"], self.marionette.execute_script("return ['foo', 'bar']")) self.assertEqual( [1, 1.5, True, "foo"], self.marionette.execute_script("return [1, 1.5, true, 'foo']")) self.assertEqual( [1, [2]], self.marionette.execute_script("return [1, [2]]")) def test_return_object(self): self.assertEqual( {"foo": 1}, self.marionette.execute_script("return {foo: 1}")) self.assertEqual( {"foo": 1.5}, self.marionette.execute_script("return {foo: 1.5}")) self.assertEqual( {"foo": True}, self.marionette.execute_script("return {foo: true}")) self.assertEqual( {"foo": "bar"}, self.marionette.execute_script("return {foo: 'bar'}")) self.assertEqual( {"foo": [1, 2]}, self.marionette.execute_script("return {foo: [1, 2]}")) self.assertEqual( {"foo": {"bar": [1, 2]}}, self.marionette.execute_script("return {foo: {bar: [1, 2]}}")) def test_no_return_value(self): self.assertIsNone(self.marionette.execute_script("true")) def test_argument_null(self): self.assertIsNone(self.marionette.execute_script("return arguments[0]", [None])) def test_argument_number(self): self.assertEqual( 1, self.marionette.execute_script("return arguments[0]", [1])) self.assertEqual( 1.5, self.marionette.execute_script("return arguments[0]", [1.5])) def test_argument_boolean(self): self.assertTrue(self.marionette.execute_script("return arguments[0]", [True])) def test_argument_string(self): self.assertEqual( "foo", self.marionette.execute_script("return arguments[0]", ["foo"])) def test_argument_array(self): self.assertEqual( [1, 2], self.marionette.execute_script("return arguments[0]", [[1, 2]])) def test_argument_object(self): self.assertEqual({"foo": 1}, self.marionette.execute_script( "return arguments[0]", [{"foo": 1}])) def test_globals(self): for property in globals: self.assert_is_defined(property) self.assert_is_defined("Components") self.assert_is_defined("window.wrappedJSObject") def test_system_globals(self): for property in globals: self.assert_is_defined(property, sandbox="system") self.assert_is_defined("Components", sandbox="system") self.assert_is_defined("window.wrappedJSObject") def test_exception(self): self.assertRaises(errors.JavascriptException, self.marionette.execute_script, "return foo") def test_stacktrace(self): with self.assertRaises(errors.JavascriptException) as cm: self.marionette.execute_script("return b") # by default execute_script pass the name of the python file self.assertIn(os.path.basename(__file__.replace(".pyc", ".py")), cm.exception.stacktrace) self.assertIn("b is not defined", cm.exception.message) self.assertIn("return b", cm.exception.stacktrace) def test_permission(self): with self.assertRaises(errors.JavascriptException): self.marionette.execute_script(""" var c = Components.classes["@mozilla.org/preferences-service;1"]; """) def test_return_web_element(self): self.marionette.navigate(elements) expected = self.marionette.find_element(By.TAG_NAME, "p") actual = self.marionette.execute_script( "return document.querySelector('p')") self.assertEqual(expected, actual) def test_return_web_element_array(self): self.marionette.navigate(elements) expected = self.marionette.find_elements(By.TAG_NAME, "p") actual = self.marionette.execute_script(""" let els = document.querySelectorAll('p') return [els[0], els[1]]""") self.assertEqual(expected, actual) # Bug 938228 identifies a problem with unmarshaling NodeList # objects from the DOM. document.querySelectorAll returns this # construct. def test_return_web_element_nodelist(self): self.marionette.navigate(elements) expected = self.marionette.find_elements(By.TAG_NAME, "p") actual = self.marionette.execute_script( "return document.querySelectorAll('p')") self.assertEqual(expected, actual) def test_sandbox_reuse(self): # Sandboxes between `execute_script()` invocations are shared. self.marionette.execute_script("this.foobar = [23, 42];") self.assertEqual(self.marionette.execute_script( "return this.foobar;", new_sandbox=False), [23, 42]) self.marionette.execute_script("global.barfoo = [42, 23];") self.assertEqual(self.marionette.execute_script( "return global.barfoo;", new_sandbox=False), [42, 23]) def test_sandbox_refresh_arguments(self): self.marionette.execute_script( "this.foobar = [arguments[0], arguments[1]]", [23, 42]) self.assertEqual(self.marionette.execute_script( "return this.foobar", new_sandbox=False), [23, 42]) def test_wrappedjsobject(self): try: self.marionette.execute_script("window.wrappedJSObject.foo = 3") self.assertEqual( self.marionette.execute_script("return window.wrappedJSObject.foo"), 3) finally: self.marionette.execute_script("delete window.wrappedJSObject.foo") def test_system_sandbox_wrappedjsobject(self): self.marionette.execute_script( "window.wrappedJSObject.foo = 4", sandbox="system") self.assertEqual(self.marionette.execute_script( "return window.wrappedJSObject.foo", sandbox="system"), 4) def test_system_dead_object(self): self.marionette.execute_script( "window.wrappedJSObject.foo = function() { return 'yo' }", sandbox="system") self.marionette.execute_script( "dump(window.wrappedJSObject.foo)", sandbox="system") self.marionette.execute_script( "window.wrappedJSObject.foo = function() { return 'yolo' }", sandbox="system") typ = self.marionette.execute_script( "return typeof window.wrappedJSObject.foo", sandbox="system") self.assertEqual("function", typ) obj = self.marionette.execute_script( "return window.wrappedJSObject.foo.toString()", sandbox="system") self.assertIn("yolo", obj) def test_lasting_side_effects(self): def send(script): return self.marionette._send_message( "executeScript", {"script": script}, key="value") send("window.foo = 1") foo = send("return window.foo") self.assertEqual(1, foo) for property in globals: exists = send("return typeof {} != 'undefined'".format(property)) self.assertTrue(exists, "property {} is undefined".format(property)) self.assertTrue(send("return typeof Components.utils == 'undefined'")) self.assertTrue(send("return typeof window.wrappedJSObject == 'undefined'")) def test_no_callback(self): self.assertTrue(self.marionette.execute_script( "return typeof arguments[0] == 'undefined'")) def test_window_set_timeout_is_not_cancelled(self): def content_timeout_triggered(mn): return mn.execute_script("return window.n", sandbox=None) > 0 # subsequent call to execute_script after this # should not cancel the setTimeout event self.marionette.navigate(inline(""" """)) # as debug builds are inherently slow, # we need to assert the event did not already fire self.assertEqual(0, self.marionette.execute_script( "return window.n", sandbox=None), "setTimeout already fired") # if event was cancelled, this will time out Wait(self.marionette, timeout=8).until( content_timeout_triggered, message="Scheduled setTimeout event was cancelled by call to execute_script") def test_privileged_code_inspection(self): # test permission denied on toString of unload event handler self.marionette.navigate(inline(""" """)) self.marionette.execute_script("", sandbox=None) # test inspection of arguments self.marionette.execute_script("__webDriverArguments.toString()") class TestExecuteChrome(WindowManagerMixin, TestExecuteContent): def setUp(self): super(TestExecuteChrome, self).setUp() self.marionette.set_context("chrome") def tearDown(self): super(TestExecuteChrome, self).tearDown() def test_permission(self): self.assertEqual(1, self.marionette.execute_script(""" var c = Components.classes["@mozilla.org/preferences-service;1"]; return 1;""")) @skip_if_mobile("New windows not supported in Fennec") def test_unmarshal_element_collection(self): def open_window_with_js(): self.marionette.execute_script( "window.open('chrome://marionette/content/test.xul', 'xul', 'chrome');") try: win = self.open_window(trigger=open_window_with_js) self.marionette.switch_to_window(win) expected = self.marionette.find_elements(By.TAG_NAME, "textbox") actual = self.marionette.execute_script( "return document.querySelectorAll('textbox')") self.assertEqual(expected, actual) finally: self.close_all_windows() def test_async_script_timeout(self): with self.assertRaises(errors.ScriptTimeoutException): self.marionette.execute_async_script(""" var cb = arguments[arguments.length - 1]; setTimeout(function() { cb() }, 250); """, script_timeout=100) @skip_if_mobile("New windows not supported in Fennec") def test_invalid_chrome_handle(self): try: win = self.open_window() self.marionette.switch_to_window(win) # Close new window and don't switch back to the original one self.marionette.close_chrome_window() self.assertNotEqual(self.start_window, win) # Call execute_script on an invalid chrome handle with self.marionette.using_context('chrome'): self.marionette.execute_script(""" return true; """) finally: self.close_all_windows() def test_lasting_side_effects(self): pass def test_return_web_element(self): pass def test_return_web_element_array(self): pass def test_return_web_element_nodelist(self): pass def test_window_set_timeout_is_not_cancelled(self): pass def test_privileged_code_inspection(self): pass class TestElementCollections(MarionetteTestCase): def assertSequenceIsInstance(self, seq, typ): for item in seq: self.assertIsInstance(item, typ) def test_array(self): self.marionette.navigate(inline("

foo

bar")) els = self.marionette.execute_script("return Array.from(document.querySelectorAll('p'))") self.assertIsInstance(els, list) self.assertEqual(2, len(els)) self.assertSequenceIsInstance(els, HTMLElement) def test_html_all_collection(self): self.marionette.navigate(inline("

foo

bar")) els = self.marionette.execute_script("return document.all") self.assertIsInstance(els, list) # , , ,

,

self.assertEqual(5, len(els)) self.assertSequenceIsInstance(els, HTMLElement) def test_html_collection(self): self.marionette.navigate(inline("

foo

bar")) els = self.marionette.execute_script("return document.getElementsByTagName('p')") self.assertIsInstance(els, list) self.assertEqual(2, len(els)) self.assertSequenceIsInstance(els, HTMLElement) def test_html_form_controls_collection(self): self.marionette.navigate(inline("

")) els = self.marionette.execute_script("return document.forms[0].elements") self.assertIsInstance(els, list) self.assertEqual(2, len(els)) self.assertSequenceIsInstance(els, HTMLElement) def test_html_options_collection(self): self.marionette.navigate(inline("")) els = self.marionette.execute_script("return document.querySelector('select').options") self.assertIsInstance(els, list) self.assertEqual(2, len(els)) self.assertSequenceIsInstance(els, HTMLElement) def test_node_list(self): self.marionette.navigate(inline("

foo

bar")) els = self.marionette.execute_script("return document.querySelectorAll('p')") self.assertIsInstance(els, list) self.assertEqual(2, len(els)) self.assertSequenceIsInstance(els, HTMLElement)