| // <copyright file="ExecutingJavascriptTest.cs" company="Selenium Committers"> |
| // Licensed to the Software Freedom Conservancy (SFC) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The SFC licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // </copyright> |
| |
| using NUnit.Framework; |
| using System; |
| using System.Collections.Generic; |
| using System.Collections.ObjectModel; |
| using System.Threading.Tasks; |
| |
| namespace OpenQA.Selenium; |
| |
| [TestFixture] |
| public class ExecutingJavascriptTest : DriverTestFixture |
| { |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnAString() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = xhtmlTestPage; |
| |
| object result = ExecuteScript("return document.title;"); |
| |
| Assert.That(result, Is.InstanceOf<string>()); |
| Assert.That(result, Is.EqualTo("XHTML Test Page")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnALong() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = xhtmlTestPage; |
| |
| object result = ExecuteScript("return document.title.length;"); |
| |
| Assert.That(result, Is.InstanceOf<long>()); |
| Assert.That((long)result, Is.EqualTo((long)"XHTML Test Page".Length)); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnAWebElement() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = xhtmlTestPage; |
| |
| object result = ExecuteScript("return document.getElementById('id1');"); |
| |
| Assert.That(result, Is.Not.Null); |
| Assert.That(result, Is.InstanceOf<IWebElement>()); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnABoolean() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = xhtmlTestPage; |
| |
| object result = ExecuteScript("return true;"); |
| |
| Assert.That(result, Is.Not.Null); |
| Assert.That(result, Is.InstanceOf<bool>()); |
| Assert.That((bool)result, Is.True); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnAStringArray() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| List<object> expectedResult = new List<object>(); |
| expectedResult.Add("zero"); |
| expectedResult.Add("one"); |
| expectedResult.Add("two"); |
| object result = ExecuteScript("return ['zero', 'one', 'two'];"); |
| Assert.That(result, Is.InstanceOf<ReadOnlyCollection<object>>()); |
| ReadOnlyCollection<object> list = (ReadOnlyCollection<object>)result; |
| Assert.That(list, Is.EqualTo(expectedResult.AsReadOnly())); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnAnArray() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| List<object> expectedResult = new List<object>(); |
| expectedResult.Add("zero"); |
| List<object> subList = new List<object>(); |
| subList.Add(true); |
| subList.Add(false); |
| expectedResult.Add(subList.AsReadOnly()); |
| object result = ExecuteScript("return ['zero', [true, false]];"); |
| Assert.That(result, Is.InstanceOf<ReadOnlyCollection<object>>()); |
| ReadOnlyCollection<object> list = (ReadOnlyCollection<object>)result; |
| Assert.That(result, Is.EqualTo(expectedResult.AsReadOnly())); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteJavascriptAndReturnABasicObjectLiteral() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| |
| object result = ExecuteScript("return {abc: '123', tired: false};"); |
| Assert.That(result, Is.InstanceOf<Dictionary<string, object>>()); |
| Dictionary<string, object> map = (Dictionary<string, object>)result; |
| |
| Dictionary<string, object> expected = new Dictionary<string, object>(); |
| expected.Add("abc", "123"); |
| expected.Add("tired", false); |
| |
| Assert.That(map, Has.Count.EqualTo(expected.Count), "Expected:<" + expected.Count + ">, but was:<" + map.Count + ">"); |
| foreach (string expectedKey in expected.Keys) |
| { |
| Assert.That(map, Does.ContainKey(expectedKey)); |
| Assert.That(map[expectedKey], Is.EqualTo(expected[expectedKey])); |
| } |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnAnObjectLiteral() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| |
| Dictionary<string, object> expectedPerson = new Dictionary<string, object>(); |
| expectedPerson.Add("first", "John"); |
| expectedPerson.Add("last", "Doe"); |
| Dictionary<string, object> expectedResult = new Dictionary<string, object>(); |
| expectedResult.Add("foo", "bar"); |
| List<object> subList = new List<object>() { "a", "b", "c" }; |
| expectedResult.Add("baz", subList.AsReadOnly()); |
| expectedResult.Add("person", expectedPerson); |
| |
| object result = ExecuteScript( |
| "return {foo:'bar', baz: ['a', 'b', 'c'], " + |
| "person: {first: 'John',last: 'Doe'}};"); |
| Assert.That(result, Is.InstanceOf<Dictionary<string, object>>()); |
| |
| Dictionary<string, object> map = (Dictionary<string, object>)result; |
| Assert.That(map, Has.Count.EqualTo(3)); |
| foreach (string expectedKey in expectedResult.Keys) |
| { |
| Assert.That(map, Does.ContainKey(expectedKey)); |
| } |
| |
| Assert.That(map["foo"], Is.EqualTo("bar")); |
| Assert.That((ReadOnlyCollection<object>)map["baz"], Is.EqualTo((ReadOnlyCollection<object>)expectedResult["baz"])); |
| |
| Dictionary<string, object> person = (Dictionary<string, object>)map["person"]; |
| Assert.That(person, Has.Count.EqualTo(2)); |
| Assert.That(person["first"], Is.EqualTo("John")); |
| Assert.That(person["last"], Is.EqualTo("Doe")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteSimpleJavascriptAndReturnAComplexObject() |
| { |
| driver.Url = javascriptPage; |
| |
| object result = ExecuteScript("return window.location;"); |
| |
| Assert.That(result, Is.InstanceOf<Dictionary<string, object>>()); |
| Dictionary<string, object> map = (Dictionary<string, object>)result; |
| Assert.That(map["protocol"], Is.EqualTo("http:")); |
| Assert.That(map["href"], Is.EqualTo(javascriptPage)); |
| } |
| |
| [Test] |
| public void PassingAndReturningALongShouldReturnAWholeNumber() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| long expectedResult = 1L; |
| object result = ExecuteScript("return arguments[0];", expectedResult); |
| Assert.That(result, Is.InstanceOf<int>().Or.InstanceOf<long>()); |
| Assert.That(result, Is.EqualTo((long)expectedResult)); |
| } |
| |
| [Test] |
| public void PassingAndReturningADoubleShouldReturnADecimal() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| double expectedResult = 1.2; |
| object result = ExecuteScript("return arguments[0];", expectedResult); |
| Assert.That(result, Is.InstanceOf<float>().Or.InstanceOf<double>()); |
| Assert.That(result, Is.EqualTo((double)expectedResult)); |
| } |
| |
| [Test] |
| public void ShouldThrowAnExceptionWhenTheJavascriptIsBad() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = xhtmlTestPage; |
| Assert.That(() => ExecuteScript("return squiggle();"), Throws.InstanceOf<WebDriverException>()); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.Chrome, ".NET language bindings do not properly parse JavaScript stack trace")] |
| [IgnoreBrowser(Browser.Edge, ".NET language bindings do not properly parse JavaScript stack trace")] |
| [IgnoreBrowser(Browser.Firefox, ".NET language bindings do not properly parse JavaScript stack trace")] |
| [IgnoreBrowser(Browser.IE, ".NET language bindings do not properly parse JavaScript stack trace")] |
| [IgnoreBrowser(Browser.Safari, ".NET language bindings do not properly parse JavaScript stack trace")] |
| public void ShouldThrowAnExceptionWithMessageAndStacktraceWhenTheJavascriptIsBad() |
| { |
| driver.Url = xhtmlTestPage; |
| string js = "function functionB() { throw Error('errormessage'); };" |
| + "function functionA() { functionB(); };" |
| + "functionA();"; |
| |
| Assert.That( |
| () => ExecuteScript(js), |
| Throws.InstanceOf<WebDriverException>() |
| .With.Message.Contains("errormessage") |
| .And.Property(nameof(WebDriverException.StackTrace)).Contains("functionB")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToCallFunctionsDefinedOnThePage() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| ExecuteScript("displayMessage('I like cheese');"); |
| string text = driver.FindElement(By.Id("result")).Text; |
| |
| Assert.That(text.Trim(), Is.EqualTo("I like cheese")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassAStringAsAnArgument() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| string text = (string)ExecuteScript("return arguments[0] == 'Hello!' ? 'Hello!' : 'Goodbye!';", "Hello!"); |
| Assert.That(text, Is.EqualTo("Hello!")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassABooleanAsAnArgument() |
| { |
| |
| string function = "return arguments[0] == true ? true : false;"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| bool result = (bool)ExecuteScript(function, true); |
| Assert.That(result, Is.True); |
| |
| result = (bool)ExecuteScript(function, false); |
| Assert.That(result, Is.False); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassANumberAsAnArgument() |
| { |
| string functionTemplate = "return arguments[0] == {0} ? {0} : 0;"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| string function = string.Format(functionTemplate, 3); |
| long result = (long)ExecuteScript(function, 3); |
| Assert.That(result, Is.EqualTo(3)); |
| |
| function = string.Format(functionTemplate, -3); |
| result = (long)ExecuteScript(function, -3); |
| Assert.That(result, Is.EqualTo(-3)); |
| |
| function = string.Format(functionTemplate, 2147483647); |
| result = (long)ExecuteScript(function, 2147483647); |
| Assert.That(result, Is.EqualTo(2147483647)); |
| |
| function = string.Format(functionTemplate, -2147483647); |
| result = (long)ExecuteScript(function, -2147483647); |
| Assert.That(result, Is.EqualTo(-2147483647)); |
| } |
| |
| [Test] |
| |
| public void ShouldBeAbleToPassAWebElementAsArgument() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| IWebElement button = driver.FindElement(By.Id("plainButton")); |
| string value = (string)ExecuteScript("arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble'];", button); |
| |
| Assert.That(value, Is.EqualTo("plainButton")); |
| } |
| |
| [Test] |
| public void PassingArrayAsOnlyArgumentShouldFlattenArray() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| object[] array = new object[] { "zero", 1, true, 3.14159 }; |
| long length = (long)ExecuteScript("return arguments[0].length", array); |
| Assert.That(length, Is.EqualTo(array.Length)); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassAnArrayAsAdditionalArgument() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| object[] array = new object[] { "zero", 1, true, 3.14159, false }; |
| long length = (long)ExecuteScript("return arguments[1].length", "string", array); |
| Assert.That(length, Is.EqualTo(array.Length)); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassACollectionAsArgument() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| List<object> collection = new List<object>(); |
| collection.Add("Cheddar"); |
| collection.Add("Brie"); |
| collection.Add(7); |
| long length = (long)ExecuteScript("return arguments[0].length", collection); |
| Assert.That(length, Is.EqualTo(collection.Count)); |
| } |
| |
| [Test] |
| public void ShouldThrowAnExceptionIfAnArgumentIsNotValid() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| Assert.That( |
| () => ExecuteScript("return arguments[0];", driver), |
| Throws.ArgumentException.With.Message.StartsWith("Argument is of an illegal type: ")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassInMoreThanOneArgument() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| { |
| return; |
| } |
| |
| driver.Url = javascriptPage; |
| string result = (string)ExecuteScript("return arguments[0] + arguments[1];", "one", "two"); |
| |
| Assert.That(result, Is.EqualTo("onetwo")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToGrabTheBodyOfFrameOnceSwitchedTo() |
| { |
| driver.Url = richTextPage; |
| |
| driver.SwitchTo().Frame("editFrame"); |
| IWebElement body = (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript("return document.body"); |
| |
| Assert.That(body.Text, Is.Empty); |
| } |
| |
| // This is a duplicate test of ShouldBeAbleToExecuteScriptAndReturnElementsList. |
| // It's here and commented only to make comparison with the Java language bindings |
| // tests easier. |
| //[Test] |
| //public void testShouldBeAbleToReturnAnArrayOfWebElements() |
| //{ |
| // driver.Url = formsPage; |
| |
| // ReadOnlyCollection<IWebElement> items = (ReadOnlyCollection<IWebElement>)((IJavaScriptExecutor)driver) |
| // .ExecuteScript("return document.getElementsByName('snack');"); |
| |
| // Assert.That(items.Count, Is.Not.EqualTo(0)); |
| //} |
| |
| [Test] |
| public void JavascriptStringHandlingShouldWorkAsExpected() |
| { |
| driver.Url = javascriptPage; |
| |
| string value = (string)ExecuteScript("return '';"); |
| Assert.That(value, Is.Empty); |
| |
| value = (string)ExecuteScript("return undefined;"); |
| Assert.That(value, Is.Null); |
| |
| value = (string)ExecuteScript("return ' '"); |
| Assert.That(value, Is.EqualTo(" ")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteABigChunkOfJavascriptCode() |
| { |
| driver.Url = javascriptPage; |
| string path = System.IO.Path.Combine(Environment.EnvironmentManager.Instance.CurrentDirectory, ".." + System.IO.Path.DirectorySeparatorChar + ".."); |
| string[] fileList = System.IO.Directory.GetFiles(path, "jquery-1.2.6.min.js", System.IO.SearchOption.AllDirectories); |
| if (fileList.Length > 0) |
| { |
| string jquery = System.IO.File.ReadAllText(fileList[0]); |
| Assert.That(jquery, Has.Length.GreaterThan(50000)); |
| ExecuteScript(jquery, null); |
| } |
| } |
| |
| [Test] |
| [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")] |
| [IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Chrome DevTools Protocol")] |
| [IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")] |
| public async Task ShouldBeAbleToPinJavascriptCodeAndExecuteRepeatedly() |
| { |
| using IJavaScriptEngine jsEngine = new JavaScriptEngine(driver); |
| |
| driver.Url = xhtmlTestPage; |
| |
| PinnedScript script = await jsEngine.PinScript("return document.title;"); |
| for (int i = 0; i < 5; i++) |
| { |
| object result = ((IJavaScriptExecutor)driver).ExecuteScript(script); |
| |
| Assert.That(result, Is.InstanceOf<string>()); |
| Assert.That(result, Is.EqualTo("XHTML Test Page")); |
| } |
| |
| await jsEngine.UnpinScript(script); |
| |
| Assert.That( |
| () => ((IJavaScriptExecutor)driver).ExecuteScript(script), |
| Throws.TypeOf<JavaScriptException>()); |
| } |
| |
| [Test] |
| [NeedsFreshDriver(IsCreatedAfterTest = true)] |
| [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")] |
| [IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Chrome DevTools Protocol")] |
| [IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")] |
| public async Task ShouldBeAbleToAddInitializationScriptAndExecuteOnNewDocument() |
| { |
| const string ScriptValue = "alert('notice')"; |
| const string ScriptName = "AlertScript"; |
| |
| using IJavaScriptEngine jsEngine = new JavaScriptEngine(driver); |
| |
| var initScript = await jsEngine.AddInitializationScript(ScriptName, ScriptValue); |
| |
| Assert.That(initScript, Is.Not.Null); |
| Assert.That(initScript.ScriptSource, Is.EqualTo(ScriptValue)); |
| Assert.That(initScript.ScriptName, Is.EqualTo(ScriptName)); |
| Assert.That(initScript.ScriptId, Is.Not.Null); |
| |
| await jsEngine.StartEventMonitoring(); |
| |
| driver.Navigate().Refresh(); |
| driver.SwitchTo().Alert().Accept(); |
| |
| Assert.That(jsEngine.InitializationScripts, Does.Contain(initScript)); |
| await jsEngine.RemoveInitializationScript(ScriptName); |
| |
| driver.Navigate().Refresh(); |
| Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>()); |
| |
| Assert.That(jsEngine.InitializationScripts, Does.Not.Contain(initScript)); |
| |
| await jsEngine.AddInitializationScript(ScriptName, ScriptValue); |
| |
| driver.Navigate().Refresh(); |
| driver.SwitchTo().Alert().Accept(); |
| Assert.That(jsEngine.InitializationScripts, Does.Contain(initScript)); |
| |
| await jsEngine.ClearInitializationScripts(); |
| |
| driver.Navigate().Refresh(); |
| Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>()); |
| Assert.That(jsEngine.InitializationScripts, Is.Empty); |
| |
| await jsEngine.AddInitializationScript(ScriptName, ScriptValue); |
| driver.Navigate().Refresh(); |
| driver.SwitchTo().Alert().Accept(); |
| |
| await jsEngine.ClearAll(); |
| driver.Navigate().Refresh(); |
| Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>()); |
| Assert.That(jsEngine.InitializationScripts, Is.Empty); |
| } |
| |
| [Test] |
| [NeedsFreshDriver(IsCreatedAfterTest = true)] |
| [IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")] |
| [IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Chrome DevTools Protocol")] |
| [IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")] |
| public async Task ShouldBeAbleToAddAndRemoveScriptCallbackBinding() |
| { |
| const string ScriptValue = "alert('Hello world')"; |
| const string ScriptName = "alert"; |
| |
| using IJavaScriptEngine jsEngine = new JavaScriptEngine(driver); |
| |
| var executedBindings = new List<string>(); |
| jsEngine.JavaScriptCallbackExecuted += AddToList; |
| await jsEngine.AddInitializationScript(ScriptName, ScriptValue); |
| await jsEngine.StartEventMonitoring(); |
| |
| driver.Navigate().Refresh(); |
| driver.SwitchTo().Alert().Accept(); |
| |
| await jsEngine.AddScriptCallbackBinding(ScriptName); |
| |
| driver.Navigate().Refresh(); |
| Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>()); |
| |
| Assert.That(executedBindings, Does.Contain(ScriptName)); |
| int oldCount = executedBindings.Count; |
| driver.Navigate().Refresh(); |
| |
| Assert.That(executedBindings, Has.Count.GreaterThan(oldCount)); |
| Assert.That(jsEngine.ScriptCallbackBindings, Does.Contain(ScriptName)); |
| oldCount = executedBindings.Count; |
| |
| await jsEngine.RemoveScriptCallbackBinding(ScriptName); |
| Assert.That(jsEngine.ScriptCallbackBindings, Is.Empty); |
| await jsEngine.AddScriptCallbackBinding(ScriptName); |
| Assert.That(jsEngine.ScriptCallbackBindings, Does.Contain(ScriptName)); |
| await jsEngine.ClearScriptCallbackBindings(); |
| Assert.That(jsEngine.ScriptCallbackBindings, Is.Empty); |
| |
| jsEngine.JavaScriptCallbackExecuted -= AddToList; |
| driver.Navigate().Refresh(); |
| Assert.That(executedBindings, Has.Count.EqualTo(oldCount)); |
| |
| void AddToList(object sender, JavaScriptCallbackExecutedEventArgs e) => executedBindings.Add(e.BindingName); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToExecuteScriptAndReturnElementsList() |
| { |
| driver.Url = formsPage; |
| String scriptToExec = "return document.getElementsByName('snack');"; |
| |
| object resultObject = ((IJavaScriptExecutor)driver).ExecuteScript(scriptToExec); |
| |
| ReadOnlyCollection<IWebElement> resultsList = (ReadOnlyCollection<IWebElement>)resultObject; |
| |
| Assert.That(resultsList, Is.Not.Empty); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToCreateAPersistentValue() |
| { |
| driver.Url = formsPage; |
| |
| ExecuteScript("document.alerts = []"); |
| ExecuteScript("document.alerts.push('hello world');"); |
| string text = (string)ExecuteScript("return document.alerts.shift()"); |
| |
| Assert.That(text, Is.EqualTo("hello world")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToHandleAnArrayOfElementsAsAnObjectArray() |
| { |
| driver.Url = formsPage; |
| |
| ReadOnlyCollection<IWebElement> forms = driver.FindElements(By.TagName("form")); |
| object[] args = new object[] { forms }; |
| |
| string name = (string)((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0][0].tagName", args); |
| |
| Assert.That(name, Is.EqualTo("form").IgnoreCase); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassADictionaryAsAParameter() |
| { |
| driver.Url = simpleTestPage; |
| |
| List<int> nums = new List<int>() { 1, 2 }; |
| Dictionary<string, object> args = new Dictionary<string, object>(); |
| args["bar"] = "test"; |
| args["foo"] = nums; |
| |
| object res = ((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0]['foo'][1]", args); |
| |
| Assert.That((long)res, Is.EqualTo(2)); |
| } |
| |
| [Test] |
| public void ShouldThrowAnExceptionWhenArgumentsWithStaleElementPassed() |
| { |
| IJavaScriptExecutor executor = driver as IJavaScriptExecutor; |
| if (executor == null) |
| { |
| return; |
| } |
| |
| driver.Url = simpleTestPage; |
| |
| IWebElement el = driver.FindElement(By.Id("oneline")); |
| |
| driver.Url = simpleTestPage; |
| |
| Dictionary<string, object> args = new Dictionary<string, object>(); |
| args["key"] = new object[] { "a", new object[] { "zero", 1, true, 3.14159, false, el }, "c" }; |
| Assert.That( |
| () => executor.ExecuteScript("return undefined;", args), |
| Throws.TypeOf<StaleElementReferenceException>()); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.Chrome, "Browser does not return Date object.")] |
| [IgnoreBrowser(Browser.Edge, "Browser does not return Date object.")] |
| public void ShouldBeAbleToReturnADateObject() |
| { |
| driver.Url = simpleTestPage; |
| |
| string date = (string)ExecuteScript("return new Date();"); |
| DateTime.Parse(date); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.Chrome, "Driver returns object that allows getting text.")] |
| [IgnoreBrowser(Browser.Edge, "Driver returns object that allows getting text.")] |
| [IgnoreBrowser(Browser.Firefox, "Driver does not return the documentElement object.")] |
| [IgnoreBrowser(Browser.IE, "Driver does not return the documentElement object.")] |
| [IgnoreBrowser(Browser.Safari, "Driver does not return the documentElement object.")] |
| public void ShouldReturnDocumentElementIfDocumentIsReturned() |
| { |
| driver.Url = simpleTestPage; |
| |
| object value = ExecuteScript("return document"); |
| |
| Assert.That(value, Is.InstanceOf<IWebElement>()); |
| Assert.That(((IWebElement)value).Text, Does.Contain("A single line of text")); |
| } |
| |
| [Test] |
| public void ShouldHandleObjectThatThatHaveToJSONMethod() |
| { |
| driver.Url = simpleTestPage; |
| |
| object value = ExecuteScript("return window.performance.timing"); |
| |
| Assert.That(value, Is.InstanceOf<Dictionary<string, object>>()); |
| } |
| |
| [Test] |
| public void ShouldHandleRecursiveStructures() |
| { |
| driver.Url = simpleTestPage; |
| |
| Assert.That( |
| () => ExecuteScript( |
| """ |
| var obj1 = {}; |
| var obj2 = {}; |
| obj1['obj2'] = obj2; |
| obj2['obj1'] = obj1; |
| return obj1 |
| """ |
| ), |
| Throws.TypeOf<JavaScriptException>()); |
| } |
| |
| //------------------------------------------------------------------ |
| // Tests below here are not included in the Java test suite |
| //------------------------------------------------------------------ |
| [Test] |
| [NeedsFreshDriver(IsCreatedBeforeTest = true, IsCreatedAfterTest = true)] |
| [Ignore("Reason for ignore: Failure indicates hang condition, which would break the test suite. Really needs a timeout set.")] |
| public void ShouldThrowExceptionIfExecutingOnNoPage() |
| { |
| Assert.That( |
| () => ((IJavaScriptExecutor)driver).ExecuteScript("return 1;"), |
| Throws.InstanceOf<WebDriverException>()); |
| } |
| |
| [Test] |
| public void ExecutingLargeJavaScript() |
| { |
| string script = """ |
| // stolen from injectableSelenium.js in WebDriver |
| var browserbot = { |
| |
| triggerEvent: function(element, eventType, canBubble, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) { |
| canBubble = (typeof(canBubble) == undefined) ? true : canBubble; |
| |
| if (element.fireEvent && element.ownerDocument && element.ownerDocument.createEventObject) { |
| // IE |
| var evt = this.createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown); |
| element.fireEvent('on' + eventType,evt); |
| } else { |
| var evt = document.createEvent('HTMLEvents'); |
| |
| try { |
| evt.shiftKey = shiftKeyDown; |
| evt.metaKey = metaKeyDown; |
| evt.altKey = altKeyDown; |
| evt.ctrlKey = controlKeyDown; |
| } catch(e) { |
| // Nothing sane to do |
| } |
| |
| evt.initEvent(eventType, canBubble, true); |
| return element.dispatchEvent(evt); |
| } |
| }, |
| |
| getVisibleText: function() { |
| var selection = getSelection(); |
| var range = document.createRange(); |
| range.selectNodeContents(document.documentElement); |
| selection.addRange(range); |
| |
| var string = selection.toString(); |
| selection.removeAllRanges(); |
| |
| return string; |
| }, |
| |
| getOuterHTML: function(element) { |
| if(element.outerHTML) { |
| return element.outerHTML; |
| } else if(typeof(XMLSerializer) != undefined) { |
| return new XMLSerializer().serializeToString(element); |
| } else { |
| throw "can't get outerHTML in this browser"; |
| } |
| } |
| }; |
| |
| return browserbot.getOuterHTML.apply(browserbot, arguments); |
| """; |
| |
| driver.Url = javascriptPage; |
| IWebElement element = driver.FindElement(By.TagName("body")); |
| object x = ExecuteScript(script, element); |
| } |
| |
| [Test] |
| |
| public void ShouldBeAbleToPassMoreThanOneStringAsArguments() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| string text = (string)ExecuteScript("return arguments[0] + arguments[1] + arguments[2] + arguments[3];", "Hello,", " ", "world", "!"); |
| |
| Assert.That(text, Is.EqualTo("Hello, world!")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassMoreThanOneBooleanAsArguments() |
| { |
| |
| string function = "return (arguments[0] ? 'True' : 'False') + (arguments[1] ? 'True' : 'False');"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| string text = (string)ExecuteScript(function, true, true); |
| Assert.That(text, Is.EqualTo("TrueTrue")); |
| |
| text = (string)ExecuteScript(function, false, true); |
| Assert.That(text, Is.EqualTo("FalseTrue")); |
| |
| text = (string)ExecuteScript(function, true, false); |
| Assert.That(text, Is.EqualTo("TrueFalse")); |
| |
| text = (string)ExecuteScript(function, false, false); |
| Assert.That(text, Is.EqualTo("FalseFalse")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassMoreThanOneNumberAsArguments() |
| { |
| string function = "return arguments[0]+arguments[1];"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| long result = (long)ExecuteScript(function, 30, 12); |
| Assert.That(result, Is.EqualTo(42)); |
| |
| result = (long)ExecuteScript(function, -30, -12); |
| Assert.That(result, Is.EqualTo(-42)); |
| |
| result = (long)ExecuteScript(function, 2147483646, 1); |
| Assert.That(result, Is.EqualTo(2147483647)); |
| |
| result = (long)ExecuteScript(function, -2147483646, -1); |
| Assert.That(result, Is.EqualTo(-2147483647)); |
| |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassADoubleAsAnArgument() |
| { |
| string function = "return arguments[0];"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| double result = (double)ExecuteScript(function, (double)4.2); |
| Assert.That(result, Is.EqualTo(4.2)); |
| |
| result = (double)ExecuteScript(function, (double)-4.2); |
| Assert.That(result, Is.EqualTo(-4.2)); |
| |
| result = (double)ExecuteScript(function, (float)4.2); |
| Assert.That(result, Is.EqualTo(4.2)); |
| |
| result = (double)ExecuteScript(function, (float)-4.2); |
| Assert.That(result, Is.EqualTo(-4.2)); |
| |
| result = (long)ExecuteScript(function, (double)4.0); |
| Assert.That(result, Is.EqualTo(4)); |
| |
| result = (long)ExecuteScript(function, (double)-4.0); |
| Assert.That(result, Is.EqualTo(-4)); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassMoreThanOneDoubleAsArguments() |
| { |
| String function = "return arguments[0]+arguments[1];"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| double result = (double)ExecuteScript(function, 30.1, 12.1); |
| Assert.That(result, Is.EqualTo(42.2)); |
| |
| result = (double)ExecuteScript(function, -30.1, -12.1); |
| Assert.That(result, Is.EqualTo(-42.2)); |
| |
| result = (double)ExecuteScript(function, 2147483646.1, 1.0); |
| Assert.That(result, Is.EqualTo(2147483647.1)); |
| |
| result = (double)ExecuteScript(function, -2147483646.1, -1.0); |
| Assert.That(result, Is.EqualTo(-2147483647.1)); |
| |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassMoreThanOneWebElementAsArguments() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| IWebElement button = driver.FindElement(By.Id("plainButton")); |
| IWebElement dynamo = driver.FindElement(By.Id("dynamo")); |
| string value = (string)ExecuteScript("arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble'] + arguments[1].innerHTML;", button, dynamo); |
| |
| Assert.That(value, Is.EqualTo("plainButtonWhat's for dinner?")); |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassInMixedArguments() |
| { |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| IWebElement dynamo = driver.FindElement(By.Id("dynamo")); |
| string result = (string)ExecuteScript("return arguments[0].innerHTML + arguments[1].toString() + arguments[2].toString() + arguments[3] + arguments[4]", |
| dynamo, |
| 42, |
| 4.2, |
| "Hello, World!", |
| true); |
| |
| Assert.That(result, Is.EqualTo("What's for dinner?424.2Hello, World!true")); |
| |
| } |
| |
| [Test] |
| public void ShouldBeAbleToPassInAndRetrieveDates() |
| { |
| string function = "displayMessage(arguments[0]);"; |
| |
| if (!(driver is IJavaScriptExecutor)) |
| return; |
| |
| driver.Url = javascriptPage; |
| |
| ExecuteScript(function, "2014-05-20T20:00:00+08:00"); |
| IWebElement element = driver.FindElement(By.Id("result")); |
| string text = element.Text; |
| Assert.That(text, Is.EqualTo("2014-05-20T20:00:00+08:00")); |
| } |
| |
| private object ExecuteScript(String script, params Object[] args) |
| { |
| object toReturn = ((IJavaScriptExecutor)driver).ExecuteScript(script, args); |
| return toReturn; |
| } |
| } |