Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions dotnet/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,12 @@ pkg_zip(
"release-artifact",
],
)

filegroup(
name = "source_files_support_needs_from_core",
srcs = [
"//dotnet/src/webdriver:Internal/StringSyntaxAttribute.cs",
"//dotnet/src/webdriver:Internal/StringSyntaxConstants.cs",
],
visibility = ["__subpackages__"],
)
10 changes: 8 additions & 2 deletions dotnet/src/support/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ csharp_library(
"Events/*.cs",
"Extensions/*.cs",
"UI/*.cs",
]) + [":assembly-info"],
]) + [
":assembly-info",
"//dotnet:source_files_support_needs_from_core",
],
out = "WebDriver.Support",
langversion = "12.0",
nullable = "enable",
Expand Down Expand Up @@ -71,7 +74,10 @@ csharp_library(
"Events/*.cs",
"Extensions/*.cs",
"UI/*.cs",
]) + [":assembly-info"],
]) + [
":assembly-info",
"//dotnet:source_files_support_needs_from_core",
],
out = "WebDriver.Support.StrongNamed",
keyfile = "//dotnet:Selenium.snk",
langversion = "12.0",
Expand Down
6 changes: 4 additions & 2 deletions dotnet/src/support/Events/EventFiringWebDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium.Support.Events;

Expand Down Expand Up @@ -442,7 +444,7 @@ public void Dispose()
/// variable, as if the function were called via "Function.apply"
/// </para>
/// </remarks>
public object? ExecuteScript(string script, params object?[] args)
public object? ExecuteScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
if (this.WrappedDriver is not IJavaScriptExecutor javascriptDriver)
{
Expand Down Expand Up @@ -542,7 +544,7 @@ public void Dispose()
/// <param name="script">The JavaScript code to execute.</param>
/// <param name="args">The arguments to the script.</param>
/// <returns>The value returned by the script.</returns>
public object? ExecuteAsyncScript(string script, params object?[] args)
public object? ExecuteAsyncScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
if (this.WrappedDriver is not IJavaScriptExecutor javascriptDriver)
{
Expand Down
4 changes: 3 additions & 1 deletion dotnet/src/support/Events/WebDriverScriptEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
// </copyright>

using System;
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium.Support.Events;

Expand All @@ -32,7 +34,7 @@ public class WebDriverScriptEventArgs : EventArgs
/// <param name="driver">The WebDriver instance used to execute the script.</param>
/// <param name="script">The script executed by the driver.</param>
/// <exception cref="ArgumentNullException">If <paramref name="driver"/> or <paramref name="script"/> are <see langword="null"/>.</exception>
public WebDriverScriptEventArgs(IWebDriver driver, string script)
public WebDriverScriptEventArgs(IWebDriver driver, [StringSyntax(StringSyntaxConstants.JavaScript)] string script)
{
this.Driver = driver ?? throw new ArgumentNullException(nameof(driver));
this.Script = script ?? throw new ArgumentNullException(nameof(script));
Expand Down
6 changes: 4 additions & 2 deletions dotnet/src/support/Extensions/WebDriverExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
// </copyright>

using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium.Support.Extensions;

Expand Down Expand Up @@ -71,7 +73,7 @@ public static Screenshot TakeScreenshot(this IWebDriver driver)
/// <param name="args">The arguments to the script.</param>
/// <exception cref="WebDriverException">Thrown if this <see cref="IWebDriver"/> instance
/// does not implement <see cref="IJavaScriptExecutor"/></exception>
public static void ExecuteJavaScript(this IWebDriver driver, string script, params object?[] args)
public static void ExecuteJavaScript(this IWebDriver driver, [StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
ExecuteJavaScriptInternal(driver, script, args);
}
Expand All @@ -87,7 +89,7 @@ public static void ExecuteJavaScript(this IWebDriver driver, string script, para
/// <exception cref="WebDriverException">Thrown if this <see cref="IWebDriver"/> instance
/// does not implement <see cref="IJavaScriptExecutor"/>, or if the actual return type
/// of the JavaScript execution does not match the expected type.</exception>
public static T? ExecuteJavaScript<T>(this IWebDriver driver, string script, params object?[] args)
public static T? ExecuteJavaScript<T>(this IWebDriver driver, [StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args)
{
var value = ExecuteJavaScriptInternal(driver, script, args);
if (value == null)
Expand Down
6 changes: 6 additions & 0 deletions dotnet/src/support/Selenium.WebDriver.Support.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,10 @@
<ProjectReference Include="$(CsprojIncludePath)\Selenium.WebDriver.csproj" />
</ItemGroup>

<ItemGroup>
<!--Workaround for being unable to have two different types of the same name in WebDriver and in Support, despite both being internal-->
<Compile Include="$(CsprojIncludePath)\Internal\StringSyntaxAttribute.cs" />
<Compile Include="$(CsprojIncludePath)\Internal\StringSyntaxConstants.cs" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions dotnet/src/webdriver/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ load(

exports_files([
"WebDriver.csproj",
"Internal/StringSyntaxAttribute.cs",
"Internal/StringSyntaxConstants.cs",
])

generated_assembly_info(
Expand Down
6 changes: 4 additions & 2 deletions dotnet/src/webdriver/DevTools/JavaScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
// </copyright>

using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium.DevTools;

Expand Down Expand Up @@ -85,7 +87,7 @@ public abstract class JavaScript
/// </summary>
/// <param name="script">The script to add to be evaluated when a new document is opened.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the internal ID of the script.</returns>
public abstract Task<string> AddScriptToEvaluateOnNewDocument(string script);
public abstract Task<string> AddScriptToEvaluateOnNewDocument([StringSyntax(StringSyntaxConstants.JavaScript)] string script);

/// <summary>
/// Removes a JavaScript snippet from evaluate when a new document is opened.
Expand All @@ -103,7 +105,7 @@ public abstract class JavaScript
/// This method is internal to the operation of pinned scripts in Selenium, and
/// is therefore internal by design.
/// </remarks>
internal abstract Task Evaluate(string script);
internal abstract Task Evaluate([StringSyntax(StringSyntaxConstants.JavaScript)] string script);

/// <summary>
/// Raises the BindingCalled event.
Expand Down
6 changes: 4 additions & 2 deletions dotnet/src/webdriver/IJavaScriptEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium;

Expand Down Expand Up @@ -88,7 +90,7 @@ public interface IJavaScriptEngine : IDisposable
/// <param name="script">The JavaScript to be loaded on every page.</param>
/// <returns>A task containing an <see cref="InitializationScript"/> object representing the script to be loaded on each page.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="scriptName"/> or <paramref name="script"/> are <see langword="null"/>.</exception>
Task<InitializationScript> AddInitializationScript(string scriptName, string script);
Task<InitializationScript> AddInitializationScript(string scriptName, [StringSyntax(StringSyntaxConstants.JavaScript)] string script);

/// <summary>
/// Asynchronously removes JavaScript from being loaded on every document load.
Expand All @@ -112,7 +114,7 @@ public interface IJavaScriptEngine : IDisposable
/// <param name="script">The JavaScript to pin</param>
/// <returns>A task containing a <see cref="PinnedScript"/> object to use to execute the script.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="script"/> is <see langword="null"/>.</exception>
Task<PinnedScript> PinScript(string script);
Task<PinnedScript> PinScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script);

/// <summary>
/// Unpins a previously pinned script from the browser.
Expand Down
6 changes: 4 additions & 2 deletions dotnet/src/webdriver/IJavascriptExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium;

Expand Down Expand Up @@ -62,7 +64,7 @@ public interface IJavaScriptExecutor
/// variable, as if the function were called via "Function.apply"
/// </para>
/// </remarks>
object? ExecuteScript(string script, params object?[] args);
object? ExecuteScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args);

/// <summary>
/// Executes JavaScript in the context of the currently selected frame or window.
Expand Down Expand Up @@ -108,5 +110,5 @@ public interface IJavaScriptExecutor
/// <param name="script">The JavaScript code to execute.</param>
/// <param name="args">The arguments to the script.</param>
/// <returns>The value returned by the script.</returns>
object? ExecuteAsyncScript(string script, params object?[] args);
object? ExecuteAsyncScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script, params object?[] args);
}
3 changes: 3 additions & 0 deletions dotnet/src/webdriver/InitializationScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
// </copyright>

using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using OpenQA.Selenium.Internal;

namespace OpenQA.Selenium;

Expand Down Expand Up @@ -47,6 +49,7 @@ internal InitializationScript(string scriptId, string scriptName, string scriptS
/// <summary>
/// Gets the JavaScript source of the initialization script.
/// </summary>
[StringSyntax(StringSyntaxConstants.JavaScript)]
public string ScriptSource { get; }

/// <summary>
Expand Down
7 changes: 2 additions & 5 deletions dotnet/src/webdriver/Internal/FileUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

using OpenQA.Selenium.Internal.Logging;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
Expand Down Expand Up @@ -209,11 +210,7 @@ public static string GetCurrentDirectory()
/// <param name="directoryPattern">The pattern to use in creating the directory name, following standard
/// .NET string replacement tokens.</param>
/// <returns>The full path to the random directory name in the temporary directory.</returns>
public static string GenerateRandomTempDirectoryName(
#if NET8_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.CompositeFormat)]
#endif
string directoryPattern)
public static string GenerateRandomTempDirectoryName([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string directoryPattern)
{
string directoryName = string.Format(CultureInfo.InvariantCulture, directoryPattern, Guid.NewGuid().ToString("N"));
return Path.Combine(Path.GetTempPath(), directoryName);
Expand Down
89 changes: 89 additions & 0 deletions dotnet/src/webdriver/Internal/StringSyntaxAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// <copyright file="StringSyntaxAttribute.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>

#if !NET8_0_OR_GREATER

namespace System.Diagnostics.CodeAnalysis;

/// <summary>Specifies the syntax used in a string.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class StringSyntaxAttribute : Attribute
{
/// <summary>Initializes the <see cref="StringSyntaxAttribute"/> with the identifier of the syntax used.</summary>
/// <param name="syntax">The syntax identifier.</param>
public StringSyntaxAttribute(string syntax)
{
Syntax = syntax;
Arguments = [];
}

/// <summary>Initializes the <see cref="StringSyntaxAttribute"/> with the identifier of the syntax used.</summary>
/// <param name="syntax">The syntax identifier.</param>
/// <param name="arguments">Optional arguments associated with the specific syntax employed.</param>
public StringSyntaxAttribute(string syntax, params object?[] arguments)
{
Syntax = syntax;
Arguments = arguments;
}

/// <summary>Gets the identifier of the syntax used.</summary>
public string Syntax { get; }

/// <summary>Optional arguments associated with the specific syntax employed.</summary>
public object?[] Arguments { get; }

/// <summary>The syntax identifier for strings containing composite formats for string formatting.</summary>
public const string CompositeFormat = nameof(CompositeFormat);

/// <summary>The syntax identifier for strings containing date format specifiers.</summary>
public const string DateOnlyFormat = nameof(DateOnlyFormat);

/// <summary>The syntax identifier for strings containing date and time format specifiers.</summary>
public const string DateTimeFormat = nameof(DateTimeFormat);

/// <summary>The syntax identifier for strings containing <see cref="Enum"/> format specifiers.</summary>
public const string EnumFormat = nameof(EnumFormat);

/// <summary>The syntax identifier for strings containing <see cref="Guid"/> format specifiers.</summary>
public const string GuidFormat = nameof(GuidFormat);

/// <summary>The syntax identifier for strings containing JavaScript Object Notation (JSON).</summary>
public const string Json = nameof(Json);

/// <summary>The syntax identifier for strings containing numeric format specifiers.</summary>
public const string NumericFormat = nameof(NumericFormat);

/// <summary>The syntax identifier for strings containing regular expressions.</summary>
public const string Regex = nameof(Regex);

/// <summary>The syntax identifier for strings containing time format specifiers.</summary>
public const string TimeOnlyFormat = nameof(TimeOnlyFormat);

/// <summary>The syntax identifier for strings containing <see cref="TimeSpan"/> format specifiers.</summary>
public const string TimeSpanFormat = nameof(TimeSpanFormat);

/// <summary>The syntax identifier for strings containing URIs.</summary>
public const string Uri = nameof(Uri);

/// <summary>The syntax identifier for strings containing XML.</summary>
public const string Xml = nameof(Xml);
}

#endif

25 changes: 25 additions & 0 deletions dotnet/src/webdriver/Internal/StringSyntaxConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// <copyright file="StringSyntaxConstants.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>

namespace OpenQA.Selenium.Internal;

internal static class StringSyntaxConstants
{
public const string JavaScript = "javascript";
}
4 changes: 2 additions & 2 deletions dotnet/src/webdriver/JavaScriptEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public async Task DisableDomMutationMonitoring()
/// <param name="script">The JavaScript to be loaded on every page.</param>
/// <returns>A task containing an <see cref="InitializationScript"/> object representing the script to be loaded on each page.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="scriptName"/> or <paramref name="script"/> are <see langword="null"/>.</exception>
public async Task<InitializationScript> AddInitializationScript(string scriptName, string script)
public async Task<InitializationScript> AddInitializationScript(string scriptName, [StringSyntax(StringSyntaxConstants.JavaScript)] string script)
{
if (scriptName is null)
{
Expand Down Expand Up @@ -233,7 +233,7 @@ public async Task ClearInitializationScripts()
/// <param name="script">The JavaScript to pin</param>
/// <returns>A task containing a <see cref="PinnedScript"/> object to use to execute the script.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="script"/> is <see langword="null"/>.</exception>
public async Task<PinnedScript> PinScript(string script)
public async Task<PinnedScript> PinScript([StringSyntax(StringSyntaxConstants.JavaScript)] string script)
{
if (script == null)
{
Expand Down
Loading