Skip to content

Commit 421680f

Browse files
[dotnet] Fix JavaScriptEngine.ScriptCallbackBindings not containing new bindings (#15221)
* [dotnet] Fix `JavaScriptEngine.ScriptCallbackBindings` not containing new bindings * Add tests * Implement IEquatable on `InitializationScript` * Remove implementation of IEquatable, override normal `Equals` * Override InitializationScript.GetHashCode
1 parent d458c6e commit 421680f

File tree

3 files changed

+127
-4
lines changed

3 files changed

+127
-4
lines changed

dotnet/src/webdriver/InitializationScript.cs

+22
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,28 @@ public class InitializationScript
4141
/// </summary>
4242
public string ScriptSource { get; internal set; }
4343

44+
/// <summary>
45+
/// Indicates whether the current <see cref="InitializationScript"/> is equal to another <see cref="InitializationScript"/> of the same type.
46+
/// </summary>
47+
/// <param name="other">An <see cref="InitializationScript"/> to compare with this <see cref="InitializationScript"/>.</param>
48+
/// <returns><see langword="true"/> if the current <see cref="InitializationScript"/> is equal to the other parameter; otherwise, <see langword="false"/>.</returns>
49+
public override bool Equals(object obj)
50+
{
51+
return obj is InitializationScript other && this.ScriptId == other.ScriptId && this.ScriptName == other.ScriptName && this.ScriptSource == other.ScriptSource;
52+
}
53+
54+
/// <summary>
55+
/// Serves as a hash function for a particular <see cref="InitializationScript"/>.
56+
/// </summary>
57+
/// <returns>A hash code for the current <see cref="InitializationScript"/>.</returns>
58+
public override int GetHashCode()
59+
{
60+
int result = this.ScriptId.GetHashCode();
61+
result = (31 * result) + this.ScriptName.GetHashCode();
62+
result = (31 * result) + this.ScriptSource.GetHashCode();
63+
return result;
64+
}
65+
4466
/// <summary>
4567
/// Returns a string that represents the current object.
4668
/// </summary>

dotnet/src/webdriver/JavaScriptEngine.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class JavaScriptEngine : IJavaScriptEngine
4040
private Lazy<DevToolsSession> session;
4141
private Dictionary<string, InitializationScript> initializationScripts = new Dictionary<string, InitializationScript>();
4242
private Dictionary<string, PinnedScript> pinnedScripts = new Dictionary<string, PinnedScript>();
43-
private List<string> bindings = new List<string>();
43+
private HashSet<string> bindings = new HashSet<string>();
4444
private bool isEnabled = false;
4545
private bool isDisposed = false;
4646

@@ -271,7 +271,7 @@ public async Task UnpinScript(PinnedScript script)
271271
/// <returns>A task that represents the asynchronous operation.</returns>
272272
public async Task AddScriptCallbackBinding(string bindingName)
273273
{
274-
if (this.bindings.Contains(bindingName))
274+
if (!this.bindings.Add(bindingName))
275275
{
276276
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "A binding named {0} has already been added", bindingName));
277277
}
@@ -288,7 +288,7 @@ public async Task AddScriptCallbackBinding(string bindingName)
288288
public async Task RemoveScriptCallbackBinding(string bindingName)
289289
{
290290
await this.session.Value.Domains.JavaScript.RemoveBinding(bindingName).ConfigureAwait(false);
291-
this.bindings.Remove(bindingName);
291+
_ = this.bindings.Remove(bindingName);
292292
}
293293

294294
/// <summary>

dotnet/test/common/ExecutingJavascriptTest.cs

+102-1
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ public void ShouldBeAbleToExecuteABigChunkOfJavascriptCode()
480480
[IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")]
481481
public async Task ShouldBeAbleToPinJavascriptCodeAndExecuteRepeatedly()
482482
{
483-
IJavaScriptEngine jsEngine = new JavaScriptEngine(driver);
483+
using IJavaScriptEngine jsEngine = new JavaScriptEngine(driver);
484484

485485
driver.Url = xhtmlTestPage;
486486

@@ -500,6 +500,107 @@ public async Task ShouldBeAbleToPinJavascriptCodeAndExecuteRepeatedly()
500500
Throws.TypeOf<JavaScriptException>());
501501
}
502502

503+
[Test]
504+
[NeedsFreshDriver(IsCreatedAfterTest = true)]
505+
[IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")]
506+
[IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Chrome DevTools Protocol")]
507+
[IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")]
508+
public async Task ShouldBeAbleToAddInitializationScriptAndExecuteOnNewDocument()
509+
{
510+
const string ScriptValue = "alert('notice')";
511+
const string ScriptName = "AlertScript";
512+
513+
using IJavaScriptEngine jsEngine = new JavaScriptEngine(driver);
514+
515+
var initScript = await jsEngine.AddInitializationScript(ScriptName, ScriptValue);
516+
517+
Assert.That(initScript, Is.Not.Null);
518+
Assert.That(initScript.ScriptSource, Is.EqualTo(ScriptValue));
519+
Assert.That(initScript.ScriptName, Is.EqualTo(ScriptName));
520+
Assert.That(initScript.ScriptId, Is.Not.Null);
521+
522+
await jsEngine.StartEventMonitoring();
523+
524+
driver.Navigate().Refresh();
525+
driver.SwitchTo().Alert().Accept();
526+
527+
Assert.That(jsEngine.InitializationScripts, Does.Contain(initScript));
528+
await jsEngine.RemoveInitializationScript(ScriptName);
529+
530+
driver.Navigate().Refresh();
531+
Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>());
532+
533+
Assert.That(jsEngine.InitializationScripts, Does.Not.Contain(initScript));
534+
535+
await jsEngine.AddInitializationScript(ScriptName, ScriptValue);
536+
537+
driver.Navigate().Refresh();
538+
driver.SwitchTo().Alert().Accept();
539+
Assert.That(jsEngine.InitializationScripts, Does.Contain(initScript));
540+
541+
await jsEngine.ClearInitializationScripts();
542+
543+
driver.Navigate().Refresh();
544+
Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>());
545+
Assert.That(jsEngine.InitializationScripts, Is.Empty);
546+
547+
await jsEngine.AddInitializationScript(ScriptName, ScriptValue);
548+
driver.Navigate().Refresh();
549+
driver.SwitchTo().Alert().Accept();
550+
551+
await jsEngine.ClearAll();
552+
driver.Navigate().Refresh();
553+
Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>());
554+
Assert.That(jsEngine.InitializationScripts, Is.Empty);
555+
}
556+
557+
[Test]
558+
[NeedsFreshDriver(IsCreatedAfterTest = true)]
559+
[IgnoreBrowser(Selenium.Browser.IE, "IE does not support Chrome DevTools Protocol")]
560+
[IgnoreBrowser(Selenium.Browser.Firefox, "Firefox does not support Chrome DevTools Protocol")]
561+
[IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")]
562+
public async Task ShouldBeAbleToAddAndRemoveScriptCallbackBinding()
563+
{
564+
const string ScriptValue = "alert('Hello world')";
565+
const string ScriptName = "alert";
566+
567+
using IJavaScriptEngine jsEngine = new JavaScriptEngine(driver);
568+
569+
var executedBindings = new List<string>();
570+
jsEngine.JavaScriptCallbackExecuted += AddToList;
571+
await jsEngine.AddInitializationScript(ScriptName, ScriptValue);
572+
await jsEngine.StartEventMonitoring();
573+
574+
driver.Navigate().Refresh();
575+
driver.SwitchTo().Alert().Accept();
576+
577+
await jsEngine.AddScriptCallbackBinding(ScriptName);
578+
579+
driver.Navigate().Refresh();
580+
Assert.That(() => driver.SwitchTo().Alert().Accept(), Throws.TypeOf<NoAlertPresentException>());
581+
582+
Assert.That(executedBindings, Does.Contain(ScriptName));
583+
int oldCount = executedBindings.Count;
584+
driver.Navigate().Refresh();
585+
586+
Assert.That(executedBindings, Has.Count.GreaterThan(oldCount));
587+
Assert.That(jsEngine.ScriptCallbackBindings, Does.Contain(ScriptName));
588+
oldCount = executedBindings.Count;
589+
590+
await jsEngine.RemoveScriptCallbackBinding(ScriptName);
591+
Assert.That(jsEngine.ScriptCallbackBindings, Is.Empty);
592+
await jsEngine.AddScriptCallbackBinding(ScriptName);
593+
Assert.That(jsEngine.ScriptCallbackBindings, Does.Contain(ScriptName));
594+
await jsEngine.ClearScriptCallbackBindings();
595+
Assert.That(jsEngine.ScriptCallbackBindings, Is.Empty);
596+
597+
jsEngine.JavaScriptCallbackExecuted -= AddToList;
598+
driver.Navigate().Refresh();
599+
Assert.That(executedBindings, Has.Count.EqualTo(oldCount));
600+
601+
void AddToList(object sender, JavaScriptCallbackExecutedEventArgs e) => executedBindings.Add(e.BindingName);
602+
}
603+
503604
[Test]
504605
public void ShouldBeAbleToExecuteScriptAndReturnElementsList()
505606
{

0 commit comments

Comments
 (0)