diff --git a/.github/workflows/crossBrowserTesting.yml b/.github/workflows/crossBrowserTesting.yml index 4fe2994a..89ebf10e 100644 --- a/.github/workflows/crossBrowserTesting.yml +++ b/.github/workflows/crossBrowserTesting.yml @@ -1,5 +1,9 @@ name: Cross-browser testing +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + on: push: branches: [ "master" ] diff --git a/CSF.Screenplay.Reqnroll/EnumerableResolutionAdapter.cs b/CSF.Screenplay.Reqnroll/EnumerableResolutionAdapter.cs new file mode 100644 index 00000000..3aff893a --- /dev/null +++ b/CSF.Screenplay.Reqnroll/EnumerableResolutionAdapter.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +#if SPECFLOW +using BoDi; +#else +using Reqnroll.BoDi; +#endif + +namespace CSF.Screenplay +{ + /// + /// Adapter class which - when added to DI - permits the BoDi DI container to resolve arbitrary of + /// service instances. + /// + /// + /// + /// The BoDi DI container which is included in Reqnroll/SpecFlow does not fully support the functionality of Microsoft's DI standard. + /// Notably, it cannot natively resolve an , where type T is a service type which may have multiple implementations + /// added to/registered with the container. + /// BoDi does have conceptually identical functionality, in its function. + /// + /// + /// The purpose of this type is to provide a mechanism by which BoDi may resolve enumerables of service types. + /// This class wraps an instance of and - in its method - redirects to the + /// method. + /// + /// + /// The limitation of this type (as a workaround) is that this type must be added to the container manually for each + /// type which could be resolved from the container. + /// + /// + public class EnumerableResolutionAdapter : IEnumerable where T : class + { + readonly IObjectContainer container; + + /// + public IEnumerator GetEnumerator() + { + var allOptions = container.ResolveAll(); + return allOptions.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + /// + /// Initializes a new instance of . + /// + /// The BoDi object container. + /// is null. + public EnumerableResolutionAdapter(IObjectContainer container) + { + this.container = container ?? throw new ArgumentNullException(nameof(container)); + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Reqnroll/ObjectContainerExtensions.cs b/CSF.Screenplay.Reqnroll/ObjectContainerExtensions.cs new file mode 100644 index 00000000..b1453e7c --- /dev/null +++ b/CSF.Screenplay.Reqnroll/ObjectContainerExtensions.cs @@ -0,0 +1,46 @@ +using System; +#if SPECFLOW +using BoDi; +#else +using Reqnroll.BoDi; +#endif +using Microsoft.Extensions.DependencyInjection; + +namespace CSF.Screenplay +{ + /// + /// Extension methods for the Reqnroll/SpecFlow "BoDi" DI container. + /// + public static class ObjectContainerExtensions + { + /// + /// Gets an adapter object which permits limited use of the BoDi as if it were an + /// . + /// + /// + /// + /// Note that this is an imperfect solution. The BoDi container shipped with Reqnroll/SpecFlow does not support all the functionality + /// which is expected from . Many methods of the returned object will throw + /// if attempts are made to use them (a known LSP violation). Additionally, not all service collection DI behaviour will operate in the same + /// manner when using this adapter. In short "your mileage may vary". + /// + /// + /// However, for the most simple of usages, this enables the use of "Add to DI" logic which has been crafted for service collection, + /// in such a way that services may be added to the BoDi container without additional logic. + /// + /// + /// A Reqnroll/SpecFlow BoDi DI container. + /// An adapter object which implements some of the functionality of + public static IServiceCollection ToServiceCollection(this IObjectContainer bodiContainer) + => new ServiceCollectionAdapter(bodiContainer); + + /// + /// Gets an adapter object which permits the use of the BoDi as if it were an + /// . + /// + /// A Reqnroll/SpecFlow BoDi DI container. + /// An adapter object which implements the functionality of + public static IServiceProvider ToServiceProvider(this IObjectContainer bodiContainer) + => new ServiceProviderAdapter(bodiContainer); + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Reqnroll/PerformanceProviderFactory.cs b/CSF.Screenplay.Reqnroll/PerformanceProviderFactory.cs new file mode 100644 index 00000000..fe46efd8 --- /dev/null +++ b/CSF.Screenplay.Reqnroll/PerformanceProviderFactory.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Concurrent; +using CSF.Screenplay.Performances; +using Microsoft.Extensions.DependencyInjection; +#if SPECFLOW +using TechTalk.SpecFlow; +#else +using Reqnroll; +#endif + +namespace CSF.Screenplay +{ + /// + /// Factory type for instances of . + /// + public class PerformanceProviderFactory + { + readonly ConcurrentDictionary featureContextIds = new ConcurrentDictionary(); + readonly ConcurrentDictionary scenarioContextIds = new ConcurrentDictionary(); + + /// + /// Gets an instance of for the specified service provider. + /// + /// A service provider + /// A . + public PerformanceProvider GetPerformanceContainer(IServiceProvider services) + { + var performance = new Performance(services, new [] { GetFeatureIdAndName(services), GetScenarioIdAndName(services) }); + var performanceContainer = new PerformanceProvider(); + performanceContainer.SetCurrentPerformance(performance); + return performanceContainer; + } + + IdentifierAndName GetFeatureIdAndName(IServiceProvider services) + { + var featureInfo = services.GetRequiredService(); + return new IdentifierAndName(GetFeatureId(featureInfo).ToString(), + featureInfo.Title, + true); + } + + Guid GetFeatureId(FeatureInfo featureContext) => featureContextIds.GetOrAdd(featureContext, _ => Guid.NewGuid()); + + IdentifierAndName GetScenarioIdAndName(IServiceProvider services) + { + var featureInfo = services.GetRequiredService(); + var scenarioInfo = services.GetRequiredService(); + return new IdentifierAndName(GetScenarioId(featureInfo, scenarioInfo).ToString(), + scenarioInfo.Title, + true); + } + + Guid GetScenarioId(FeatureInfo featureInfo, ScenarioInfo scenarioInfo) + => scenarioContextIds.GetOrAdd(new ScenarioAndFeatureInfoKey(scenarioInfo, featureInfo), _ => Guid.NewGuid()); + + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Reqnroll/ScreenplayPlugin.cs b/CSF.Screenplay.Reqnroll/ScreenplayPlugin.cs index 13b5c0d6..1158cd2e 100644 --- a/CSF.Screenplay.Reqnroll/ScreenplayPlugin.cs +++ b/CSF.Screenplay.Reqnroll/ScreenplayPlugin.cs @@ -3,6 +3,8 @@ using System.Reflection; using CSF.Screenplay.Actors; using CSF.Screenplay.Performances; +using Microsoft.Extensions.DependencyInjection; + #if SPECFLOW using BoDi; using TechTalk.SpecFlow; @@ -31,7 +33,7 @@ namespace CSF.Screenplay /// /// /// This may be easily worked-around, though. If you are using a third-party DI plugin then do not use this plugin. - /// Instead use the + /// Instead use the /// method to add Screenplay to that third-party DI system, when customising the dependency registrations. /// Adding Screenplay in that way is equivalent to the work done by this plugin. /// @@ -46,8 +48,6 @@ namespace CSF.Screenplay public class ScreenplayPlugin : IRuntimePlugin { readonly object syncRoot = new object(); - readonly ConcurrentDictionary featureContextIds = new ConcurrentDictionary(); - readonly ConcurrentDictionary scenarioContextIds = new ConcurrentDictionary(); bool initialised; @@ -104,50 +104,28 @@ void OnCustomizeGlobalDependencies(object sender, CustomizeGlobalDependenciesEve { if (initialised) return; - var container = args.ObjectContainer; - var serviceCollection = new ServiceCollectionAdapter(container); - serviceCollection.AddScreenplay(); - container.RegisterFactoryAs(c => new ServiceProviderAdapter(c)); - Screenplay = container.Resolve(); + var boDiContainer = args.ObjectContainer; + var services = new ServiceCollectionAdapter(boDiContainer); + services.AddScreenplayPlugin(); + boDiContainer.RegisterFactoryAs(c => c.ToServiceProvider()); + Screenplay = boDiContainer.Resolve(); initialised = true; } } - void OnCustomizeScenarioDependencies(object sender, CustomizeScenarioDependenciesEventArgs args) - { - var container = args.ObjectContainer; - var services = new ServiceProviderAdapter(container); - container.RegisterInstanceAs(services); - var performance = new Performance(services, new [] { GetFeatureIdAndName(container), GetScenarioIdAndName(container) }); - var performanceContainer = new PerformanceProvider(); - performanceContainer.SetCurrentPerformance(performance); - container.RegisterInstanceAs(performanceContainer); - container.RegisterFactoryAs(c => c.Resolve().GetCurrentPerformance()); - - container.RegisterFactoryAs(c => new Cast(c.Resolve(), c.Resolve().PerformanceIdentity)); - container.RegisterTypeAs(); - } - - IdentifierAndName GetFeatureIdAndName(IObjectContainer container) + static void OnCustomizeScenarioDependencies(object sender, CustomizeScenarioDependenciesEventArgs args) { - var featureInfo = container.Resolve(); - return new IdentifierAndName(GetFeatureId(featureInfo).ToString(), - featureInfo.Title, - true); - } + var boDiContainer = args.ObjectContainer; + var services = boDiContainer.ToServiceProvider(); + boDiContainer.RegisterInstanceAs(services); - Guid GetFeatureId(FeatureInfo featureContext) => featureContextIds.GetOrAdd(featureContext, _ => Guid.NewGuid()); - - IdentifierAndName GetScenarioIdAndName(IObjectContainer container) - { - var featureInfo = container.Resolve(); - var scenarioInfo = container.Resolve(); - return new IdentifierAndName(GetScenarioId(featureInfo, scenarioInfo).ToString(), - scenarioInfo.Title, - true); + var serviceCollection = boDiContainer.ToServiceCollection(); + serviceCollection + .AddSingleton(s => s.GetRequiredService().GetPerformanceContainer(s)) + .AddSingleton(s => s.GetRequiredService().GetCurrentPerformance()) + .AddSingleton(s => new Cast(s, s.GetRequiredService().PerformanceIdentity)) + .AddSingleton(); } - Guid GetScenarioId(FeatureInfo featureInfo, ScenarioInfo scenarioInfo) - => scenarioContextIds.GetOrAdd(new ScenarioAndFeatureInfoKey(scenarioInfo, featureInfo), _ => Guid.NewGuid()); } } diff --git a/CSF.Screenplay.Reqnroll/ServiceCollectionAdapter.cs b/CSF.Screenplay.Reqnroll/ServiceCollectionAdapter.cs index 11b40faf..6e7d8d64 100644 --- a/CSF.Screenplay.Reqnroll/ServiceCollectionAdapter.cs +++ b/CSF.Screenplay.Reqnroll/ServiceCollectionAdapter.cs @@ -30,7 +30,6 @@ public class ServiceCollectionAdapter : IServiceCollection // not actually bypassing accessibility. #pragma warning disable S3011 static readonly MethodInfo - OpenGenericRegisterType = typeof(ServiceCollectionAdapter).GetMethod(nameof(RegisterType), BindingFlags.Instance | BindingFlags.NonPublic), OpenGenericRegisterInstance = typeof(ServiceCollectionAdapter).GetMethod(nameof(RegisterInstance), BindingFlags.Instance | BindingFlags.NonPublic), OpenGenericRegisterFactory = typeof(ServiceCollectionAdapter).GetMethod(nameof(RegisterFactory), BindingFlags.Instance | BindingFlags.NonPublic); #pragma warning restore S3011 @@ -89,12 +88,12 @@ public void Add(ServiceDescriptor item) else if (item.ImplementationInstance != null) OpenGenericRegisterInstance.MakeGenericMethod(item.ServiceType).Invoke(this, new[] { item }); else - OpenGenericRegisterType.MakeGenericMethod(item.ServiceType, item.ImplementationType).Invoke(this, Array.Empty()); + RegisterTypeNonGeneric(item.ServiceType, item.ImplementationType); } - void RegisterType() where TImpl : class,TSvc + void RegisterTypeNonGeneric(Type service, Type implementation) { - wrapped.RegisterTypeAs(); + ((ObjectContainer) wrapped).RegisterTypeAs(implementation, service); } void RegisterInstance(ServiceDescriptor item) where T : class @@ -104,7 +103,7 @@ void RegisterInstance(ServiceDescriptor item) where T : class void RegisterFactory(ServiceDescriptor item) where T : class { - wrapped.RegisterFactoryAs(objectContainer => (T) item.ImplementationFactory(new ServiceProviderAdapter(objectContainer))); + wrapped.RegisterFactoryAs(objectContainer => (T) item.ImplementationFactory(objectContainer.ToServiceProvider())); } /// diff --git a/CSF.Screenplay.Reqnroll/ServiceCollectionExtensions.cs b/CSF.Screenplay.Reqnroll/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..bae7d395 --- /dev/null +++ b/CSF.Screenplay.Reqnroll/ServiceCollectionExtensions.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace CSF.Screenplay +{ + /// + /// Extension methods for . + /// + public static class ServiceCollectionExtensions + { + /// + /// Adds to the DI container for the service type . + /// + /// + /// + /// This is required to work around a limitation of the BoDi DI container which ships with Reqnroll/SpecFlow. + /// See for more information. + /// + /// + /// The service type for which to add the adapter + /// A service collection + /// The same service collection, so calls may be chained + public static IServiceCollection AddEnumerableAdapter(this IServiceCollection services) where TService : class + => services.AddTransient, EnumerableResolutionAdapter>(); + + /// + /// Adds enumerable adapters for service types which are required in order to enable + /// the Microsoft Options Pattern with the specified options type. + /// + /// + /// + /// This is required to work around a limitation of the BoDi DI container which ships with Reqnroll/SpecFlow. + /// See for more information. + /// + /// + /// Use of the options pattern requires the resolution of three enumerable types: , + /// and . This method uses + /// for each of those types. + /// + /// + /// The options type + /// A service collection + /// The same service collection, so calls may be chained + public static IServiceCollection AddOptionsAdapters(this IServiceCollection services) where TOptions : class + { + return services + .AddEnumerableAdapter>() + .AddEnumerableAdapter>() + .AddEnumerableAdapter>(); + } + + /// + /// Adds the services to DI which are required to use the Reqnroll/SpecFlow plugin. + /// + /// A service collection + /// The same service collection, so calls may be chained + public static IServiceCollection AddScreenplayPlugin(this IServiceCollection services) + { + return services + .AddScreenplay() + .AddOptionsAdapters() + .AddSingleton(); + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/Actions/SetTheElementValue.cs b/CSF.Screenplay.Selenium/Actions/SetTheElementValue.cs new file mode 100644 index 00000000..9169abbe --- /dev/null +++ b/CSF.Screenplay.Selenium/Actions/SetTheElementValue.cs @@ -0,0 +1,45 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using CSF.Screenplay.Selenium.Elements; +using OpenQA.Selenium; +using static CSF.Screenplay.Selenium.PerformableBuilder; + +namespace CSF.Screenplay.Selenium.Actions +{ + /// + /// An action that sets the value of a web element using JavaScript. + /// + public class SetTheElementValue : ISingleElementPerformable + { + readonly object value; + readonly bool simulateInteractiveSet; + + /// + public ReportFragment GetReportFragment(Actor actor, Lazy element, IFormatsReportFragment formatter) + { + return simulateInteractiveSet + ? formatter.Format("{Actor} uses JavaScript to simulate setting the value of {Element} to {Value} interactively", actor, element.Value, value) + : formatter.Format("{Actor} uses JavaScript to set the value of {Element} to {Value}", actor, element.Value, value); + } + + /// + public ValueTask PerformAsAsync(ICanPerform actor, IWebDriver webDriver, Lazy element, CancellationToken cancellationToken = default) + { + return simulateInteractiveSet + ? actor.PerformAsync(ExecuteAScript(Scripts.SetElementValueSimulatedInteractively, element.Value.WebElement, value), cancellationToken) + : actor.PerformAsync(ExecuteAScript(Scripts.SetElementValue, element.Value.WebElement, value), cancellationToken); + } + + /// + /// Initializes a new instance of the class. + /// + /// The value to set on the element. + /// If then the JavaScript will fire UI events to simulate having set the element interactively + public SetTheElementValue(object value, bool simulateInteractiveSet) + { + this.value = value; + this.simulateInteractiveSet = simulateInteractiveSet; + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/BrowserQuirks.cs b/CSF.Screenplay.Selenium/BrowserQuirks.cs new file mode 100644 index 00000000..5408b388 --- /dev/null +++ b/CSF.Screenplay.Selenium/BrowserQuirks.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using CSF.Extensions.WebDriver.Quirks; + +namespace CSF.Screenplay.Selenium +{ + /// + /// Static class which holds known browser quirks information. + /// + public static class BrowserQuirks + { + /// + /// Gets the name of a browser quirk which means that a Web Driver cannot set the value of an <input type="date"> using + /// "Send Keys". + /// + /// + /// + /// Date input fields have patchy support amongst browsers and web drivers. The UI which appears in order to set a date often responds + /// poorly to typing a new date manually. Additionally, the calendar UI which most browsers will render is not built from HTML elements + /// and thus cannot be interacted with in the traditional way, by Web Drivers. Thus, if we cannot 'type' a new date and cannot interact + /// by clicking on the calendar, all that remains is to use a JavaScript workaround to set the date. + /// + /// + public static readonly string CannotSetInputTypeDateWithSendKeys = "CannotSetInputTypeDateWithSendKeys"; + + /// + /// Gets the name of a browser quirk which means that - after navigation to a different page - the browser must be instructed to wait + /// until the following page document is ready. + /// + /// + /// + /// Most Web Driver implementations, without this quirk, automatically wait for the 'incoming' page (in traditional web document + /// navigation) to be ready before they attempt to interact with it. That is - if the "document ready" event has not yet occurred, + /// they will continue waiting. Some browsers/web drivers (those with this quirk) need to be instructed to wait for that ready-state, + /// or else they are liable to attempt to interact with a page which is not yet fully loaded. + /// + /// + /// Note that this only applies to traditional web navigation. It does not apply to navigating SPA-type apps. + /// + /// + public static readonly string NeedsToWaitAfterPageLoad = "NeedsToWaitAfterPageLoad"; + + /// + /// Gets hard-coded information about known browser quirks. + /// + /// + /// + /// This information ships with CSF.Screenplay.Selenium. It may be overridden by user-supplied configuration, should + /// things change in the future. See the + /// browser quirks reference material for more information. + /// + /// + /// Quirks data, about the peculiarities of specific browsers. + public static QuirksData GetQuirksData() + { + return new QuirksData + { + Quirks = new Dictionary + { + { + CannotSetInputTypeDateWithSendKeys, + new BrowserInfoCollection + { + AffectedBrowsers = new HashSet + { + new BrowserInfo { Name = "firefox" }, + new BrowserInfo { Name = "safari" }, + } + } + }, + { + NeedsToWaitAfterPageLoad, + new BrowserInfoCollection + { + AffectedBrowsers = new HashSet + { + new BrowserInfo { Name = "safari" }, + } + } + } + } + }; + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/Builders/SetTheValueBuilder.cs b/CSF.Screenplay.Selenium/Builders/SetTheValueBuilder.cs new file mode 100644 index 00000000..e565b99c --- /dev/null +++ b/CSF.Screenplay.Selenium/Builders/SetTheValueBuilder.cs @@ -0,0 +1,72 @@ +using CSF.Screenplay.Performables; +using CSF.Screenplay.Selenium.Actions; +using CSF.Screenplay.Selenium.Elements; + +namespace CSF.Screenplay.Selenium +{ + /// + /// Builds actions for setting values in Selenium web elements. + /// + public class SetTheValueBuilder: IGetsPerformable, SetTheValueBuilder.IChoosesValue + { + readonly ITarget target; + object value; + + /// + public SetTheValueBuilder To(object value) + { + this.value = value; + return this; + } + + /// + /// Gets a performable which, whilst setting the value programatically, attempts to simulate setting it interactively in the browser. + /// + /// + /// + /// Use this method to work around limitations in the web browser/WebDriver, as it is an imperfect solution. + /// When this method is used, it configures the performable to use JavaScript which will not only update the value of the + /// specified element. It will additionally trigger HTML/JavaScript events upon the element such as focus, + /// input, change and blur in an attempt to simulate an interactive change. + /// + /// + /// The reason for this is that client web page functionality may be listening to these events and would be exercised if + /// the element value were updated by a human being interacting with the web page. However when JS is used to update the value, + /// those events are not fired. This method fires the events artificially. + /// + /// + /// A performable + public IPerformable AsIfSetInteractively() => SingleElementPerformableAdapter.From(new SetTheElementValue(value, true), target); + + IPerformable IGetsPerformable.GetPerformable() + => SingleElementPerformableAdapter.From(new SetTheElementValue(value, false), target); + + /// + /// Initializes a new instance of the class with the specified target. + /// + /// The target web element for which to build value-setting actions. + public SetTheValueBuilder(ITarget target) + { + this.target = target ?? throw new System.ArgumentNullException(nameof(target)); + } + + /// + /// An object from which a consumer may choose a value to set into the element. + /// + public interface IChoosesValue + { + /// + /// Gets a builder for a performable which sets the target element to the value specified in this method. + /// + /// + /// + /// If you are using this method to update the value of an element because you are working around a limitation in a web browser/ + /// WebDriver, then strongly consider following it with . + /// + /// + /// The new value for the element + /// A builder for a performable + SetTheValueBuilder To(object value); + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/CSF.Screenplay.Selenium.csproj b/CSF.Screenplay.Selenium/CSF.Screenplay.Selenium.csproj index a7318f27..501569e8 100644 --- a/CSF.Screenplay.Selenium/CSF.Screenplay.Selenium.csproj +++ b/CSF.Screenplay.Selenium/CSF.Screenplay.Selenium.csproj @@ -21,12 +21,13 @@ - + + diff --git a/CSF.Screenplay.Selenium/PerformableBuilder.elementPerformables.cs b/CSF.Screenplay.Selenium/PerformableBuilder.elementPerformables.cs index add96cb2..d3dfbe82 100644 --- a/CSF.Screenplay.Selenium/PerformableBuilder.elementPerformables.cs +++ b/CSF.Screenplay.Selenium/PerformableBuilder.elementPerformables.cs @@ -160,5 +160,19 @@ public static FromTargetActionBuilder SelectTheOptionWithValue(string optionValu /// The target element whose contents will be cleared. /// A performable action public static IPerformable ClearTheContentsOf(ITarget target) => SingleElementPerformableAdapter.From(new ClearTheContents(), target); + + /// + /// Gets a builder for an action which sets the value of an element programatically, using JavaScript. + /// + /// + /// + /// It is advised to use this technique and others like it sparingly, particularly when using Screenplay/Selenium for testing. Whilst + /// it is possible to set values and update the web page's state via JavaScript, this does not properly mimic the manner in which a real + /// human being would interact with the page. + /// + /// + /// The target HTML element, to have its value updated. + /// A builder with which to choose the new value + public static SetTheValueBuilder.IChoosesValue SetTheValueOf(ITarget target) => new SetTheValueBuilder(target); } } \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/Resources/ScriptResources.cs b/CSF.Screenplay.Selenium/Resources/ScriptResources.cs index f111198b..37848a88 100644 --- a/CSF.Screenplay.Selenium/Resources/ScriptResources.cs +++ b/CSF.Screenplay.Selenium/Resources/ScriptResources.cs @@ -12,6 +12,13 @@ static class ScriptResources /// Gets a short JavaScript for . internal static string ClearLocalStorage => resourceManager.GetString("ClearLocalStorage"); + /// Gets a short JavaScript that returns the value of document.readyState. internal static string GetDocReadyState => resourceManager.GetString("GetDocReadyState"); + + /// Gets a short JavaScript which sets the value of an HTML element. + internal static string SetElementValue => resourceManager.GetString("SetElementValue"); + + /// Gets a short JavaScript which sets the value of an HTML element in a way that simulates updating the element interactively. + internal static string SetElementValueSimulatedInteractively => resourceManager.GetString("SetElementValueSimulatedInteractively"); } } \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/Resources/ScriptResources.restext b/CSF.Screenplay.Selenium/Resources/ScriptResources.restext index 782ae2a4..c1dc8bca 100644 --- a/CSF.Screenplay.Selenium/Resources/ScriptResources.restext +++ b/CSF.Screenplay.Selenium/Resources/ScriptResources.restext @@ -1,2 +1,4 @@ ClearLocalStorage = localStorage.clear() -GetDocReadyState = return document.readyState \ No newline at end of file +GetDocReadyState = return document.readyState +SetElementValue = arguments[0].value = arguments[1] +SetElementValueSimulatedInteractively = ((el, v) => {const d = (e, n) => e.dispatchEvent(new Event(n, {bubbles: true}));d(el, 'focus');el.value = v;d(el, 'input');d(el, 'change');d(el, 'blur');})(arguments[0], arguments[1]) \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/Scripts.cs b/CSF.Screenplay.Selenium/Scripts.cs index e9382f0f..0077c854 100644 --- a/CSF.Screenplay.Selenium/Scripts.cs +++ b/CSF.Screenplay.Selenium/Scripts.cs @@ -15,7 +15,6 @@ public static class Scripts /// /// Gets a which clears the Local Storage of the browser, for the current domain. /// - /// A named script. public static NamedScript ClearLocalStorage => new NamedScript(Resources.ScriptResources.ClearLocalStorage, "clear the local storage"); @@ -28,5 +27,17 @@ public static NamedScript ClearLocalStorage /// public static NamedScriptWithResult GetTheDocumentReadyState => new NamedScriptWithResult(Resources.ScriptResources.GetDocReadyState, "get the readiness of the current page"); + + /// + /// Gets a which sets the value of a specified HTML element. + /// + public static NamedScript SetElementValue + => new NamedScript(Resources.ScriptResources.SetElementValue, "set the element's value"); + + /// + /// Gets a which sets the value of a specified HTML element, simulating setting it interactively. + /// + public static NamedScript SetElementValueSimulatedInteractively + => new NamedScript(Resources.ScriptResources.SetElementValueSimulatedInteractively, "simulate setting the element's value interactively"); } } \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/ServiceCollectionExtensions.cs b/CSF.Screenplay.Selenium/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..f46a8ad9 --- /dev/null +++ b/CSF.Screenplay.Selenium/ServiceCollectionExtensions.cs @@ -0,0 +1,33 @@ +using CSF.Extensions.WebDriver; +using Microsoft.Extensions.DependencyInjection; + +namespace CSF.Screenplay.Selenium +{ + /// + /// Extension methods for . + /// + public static class ServiceCollectionExtensions + { + /// + /// Adds the required services to the service collection, so that performances may incorporate Selenium-based performables + /// and abilities. + /// + /// The service collection + /// The same service collection, so calls may be chained. + public static IServiceCollection AddSelenium(this IServiceCollection services) + { + services.AddWebDriverFactory(); + services.AddWebDriverQuirks(BrowserQuirks.GetQuirksData()); + + services.AddTransient(); + services.AddTransient(); + services.Configure(o => + { + o.ValueFormatters.Add(typeof(Reporting.OptionsFormatter)); + o.ValueFormatters.Add(typeof(Reporting.ScreenshotFormatter)); + }); + + return services; + } + } +} \ No newline at end of file diff --git a/CSF.Screenplay.Selenium/Tasks/ClickAndWaitForDocumentReady.cs b/CSF.Screenplay.Selenium/Tasks/ClickAndWaitForDocumentReady.cs index 69aaf007..61467e5c 100644 --- a/CSF.Screenplay.Selenium/Tasks/ClickAndWaitForDocumentReady.cs +++ b/CSF.Screenplay.Selenium/Tasks/ClickAndWaitForDocumentReady.cs @@ -19,6 +19,7 @@ namespace CSF.Screenplay.Selenium.Tasks /// subsequent performables are executed. /// /// + /// public class ClickAndWaitForDocumentReady : ISingleElementPerformable { const string COMPLETE_READY_STATE = "complete"; @@ -35,6 +36,8 @@ public ReportFragment GetReportFragment(Actor actor, Lazy eleme public async ValueTask PerformAsAsync(ICanPerform actor, IWebDriver webDriver, Lazy element, CancellationToken cancellationToken = default) { await actor.PerformAsync(ClickOn(element.Value), cancellationToken); + if(!webDriver.HasQuirk(BrowserQuirks.NeedsToWaitAfterPageLoad)) return; + await actor.PerformAsync(WaitUntil(ElementIsStale(element.Value.WebElement)) .ForAtMost(waitTimeout) .Named($"{element.Value.Name} is no longer on the page"), diff --git a/CSF.Screenplay.Selenium/Tasks/EnterTheDate.cs b/CSF.Screenplay.Selenium/Tasks/EnterTheDate.cs index f16af502..8cbb9bc6 100644 --- a/CSF.Screenplay.Selenium/Tasks/EnterTheDate.cs +++ b/CSF.Screenplay.Selenium/Tasks/EnterTheDate.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using CSF.Screenplay.Selenium.Elements; +using OpenQA.Selenium; using static CSF.Screenplay.Selenium.PerformableBuilder; namespace CSF.Screenplay.Selenium.Actions @@ -45,9 +46,15 @@ public class EnterTheDate : IPerformable, ICanReport string FormatDate() => date.HasValue ? date.Value.ToString(GetShortDatePattern()) : null; + string FormatDateAsIso() => date.HasValue ? date.Value.ToString("yyyy-MM-dd") : null; + /// public ValueTask PerformAsAsync(ICanPerform actor, CancellationToken cancellationToken = default) { + var browseTheWeb = actor.GetAbility(); + if(browseTheWeb.WebDriver.HasQuirk(BrowserQuirks.CannotSetInputTypeDateWithSendKeys)) + return actor.PerformAsync(SetTheValueOf(target).To(FormatDateAsIso()).AsIfSetInteractively(), cancellationToken); + if(!date.HasValue) return actor.PerformAsync(ClearTheContentsOf(target), cancellationToken); diff --git a/CSF.Screenplay/CSF.Screenplay.csproj b/CSF.Screenplay/CSF.Screenplay.csproj index 839babe6..061a62ad 100644 --- a/CSF.Screenplay/CSF.Screenplay.csproj +++ b/CSF.Screenplay/CSF.Screenplay.csproj @@ -11,7 +11,9 @@ - + + + diff --git a/CSF.Screenplay/IGetsScreenplay.cs b/CSF.Screenplay/IGetsScreenplay.cs index a2cb6d2a..c7fe77b2 100644 --- a/CSF.Screenplay/IGetsScreenplay.cs +++ b/CSF.Screenplay/IGetsScreenplay.cs @@ -13,7 +13,7 @@ namespace CSF.Screenplay /// /// Types which implement this interface need only implement the method, which should build /// and return a Screenplay instance. Developers are advised to use - /// + /// /// to create and return the Screenplay. /// /// @@ -45,7 +45,7 @@ public interface IGetsScreenplay /// /// /// Implementors should create and return a new instance from this method; they are strongly urged - /// to consider the use of + /// to consider the use of /// for this purpose. /// As well as the creation of the Screenplay instance itself, they should also add to the service collection any /// services which relate to . diff --git a/CSF.Screenplay/Reporting/ReportPathProvider.cs b/CSF.Screenplay/Reporting/ReportPathProvider.cs index 7d365152..eb378b9d 100644 --- a/CSF.Screenplay/Reporting/ReportPathProvider.cs +++ b/CSF.Screenplay/Reporting/ReportPathProvider.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Microsoft.Extensions.Options; namespace CSF.Screenplay.Reporting { @@ -22,7 +23,7 @@ namespace CSF.Screenplay.Reporting /// public class ReportPathProvider : IGetsReportPath { - readonly ScreenplayOptions screenplayOptions; + readonly IOptions screenplayOptions; readonly ITestsPathForWritePermissions permissionsTester; bool hasCachedReportPath; @@ -47,15 +48,15 @@ public string GetReportPath() /// if reporting should be enabled; if not. bool ShouldEnableReporting(out string reportPath) { - if (string.IsNullOrWhiteSpace(screenplayOptions.ReportPath)) + if (string.IsNullOrWhiteSpace(screenplayOptions.Value.ReportPath)) { reportPath = null; return false; } - reportPath = Path.IsPathRooted(screenplayOptions.ReportPath) - ? screenplayOptions.ReportPath - : Path.Combine(Environment.CurrentDirectory, screenplayOptions.ReportPath); + reportPath = Path.IsPathRooted(screenplayOptions.Value.ReportPath) + ? screenplayOptions.Value.ReportPath + : Path.Combine(Environment.CurrentDirectory, screenplayOptions.Value.ReportPath); return permissionsTester.HasWritePermission(reportPath); } @@ -64,10 +65,10 @@ bool ShouldEnableReporting(out string reportPath) /// /// The screenplay options. /// The permissions tester. - public ReportPathProvider(ScreenplayOptions screenplayOptions, ITestsPathForWritePermissions permissionsTester) + public ReportPathProvider(IOptions screenplayOptions, ITestsPathForWritePermissions permissionsTester) { - this.screenplayOptions = screenplayOptions ?? throw new System.ArgumentNullException(nameof(screenplayOptions)); - this.permissionsTester = permissionsTester ?? throw new System.ArgumentNullException(nameof(permissionsTester)); + this.screenplayOptions = screenplayOptions ?? throw new ArgumentNullException(nameof(screenplayOptions)); + this.permissionsTester = permissionsTester ?? throw new ArgumentNullException(nameof(permissionsTester)); } } } \ No newline at end of file diff --git a/CSF.Screenplay/Screenplay.cs b/CSF.Screenplay/Screenplay.cs index 35881e37..ae4213b4 100644 --- a/CSF.Screenplay/Screenplay.cs +++ b/CSF.Screenplay/Screenplay.cs @@ -5,6 +5,7 @@ using CSF.Screenplay.Performables; using CSF.Screenplay.Performances; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using AsyncPerformanceLogic = System.Func>; namespace CSF.Screenplay @@ -25,10 +26,10 @@ namespace CSF.Screenplay /// /// /// It is recommended to create instances of this type by adding Screenplay to a dependency injection - /// via the extension method + /// via the extension method /// and then resolving an instance of this class from the service provider. /// Alternatively, if you do not wish to configure a service collection manually and just want an instance of this type then - /// use the static method. + /// use the static method. /// /// /// The Screenplay object is used to create instances of via its . @@ -46,8 +47,8 @@ public sealed class Screenplay : IHasServiceProvider /// Screenplay has begun. public void BeginScreenplay() { - var config = ServiceProvider.GetRequiredService(); - foreach (var callback in config.OnBeginScreenplayActions) + var config = ServiceProvider.GetRequiredService>(); + foreach (var callback in config.Value.OnBeginScreenplayActions) callback(ServiceProvider); ServiceProvider.GetRequiredService().InvokeScreenplayStarted(); @@ -59,8 +60,8 @@ public void CompleteScreenplay() { ServiceProvider.GetRequiredService().InvokeScreenplayEnded(); - var config = ServiceProvider.GetRequiredService(); - foreach (var callback in config.OnEndScreenplayActions) + var config = ServiceProvider.GetRequiredService>(); + foreach (var callback in config.Value.OnEndScreenplayActions) callback(ServiceProvider); } @@ -135,8 +136,8 @@ public void CompleteScreenplay() /// /// /// It is unlikely that developers should be executing this constructor directly. Consider using the static factory method - /// . Alternatively, add Screenplay to an using - /// and then resolve an instance of + /// . Alternatively, add Screenplay to an using + /// and then resolve an instance of /// this class from the service provider built from that service collection. /// /// @@ -158,17 +159,15 @@ public Screenplay(IServiceProvider serviceProvider) /// /// /// If you already have an and you wish to integrate Screenplay into it, then use the extension method - /// instead. + /// instead. /// /// /// An optional action which permits further customization of the service collection that is implicitly created by this method. - /// An optional action to configure the which is created by this method. /// A Screenplay instance created from a new service collection. - public static Screenplay Create(Action serviceCollectionCustomisations = null, - Action options = null) + public static Screenplay Create(Action serviceCollectionCustomisations = null) { var services = new ServiceCollection(); - services.AddScreenplay(options); + services.AddScreenplay(); serviceCollectionCustomisations?.Invoke(services); var serviceProvider = services.BuildServiceProvider(); return serviceProvider.GetRequiredService(); diff --git a/CSF.Screenplay/ScreenplayOptions.cs b/CSF.Screenplay/ScreenplayOptions.cs index ed22076e..649d7c77 100644 --- a/CSF.Screenplay/ScreenplayOptions.cs +++ b/CSF.Screenplay/ScreenplayOptions.cs @@ -18,6 +18,11 @@ namespace CSF.Screenplay /// the appropriate methods/logic to register the neccesary services for Options. /// This is why this object uses a somewhat homebrew version of options, without making use of the official libraries. /// + /// + /// Reqnroll is presently investigating replacing the BoDi container, and if it is someday replaced by MSDI, then + /// issue #292 is available to make that switch + /// to the options pattern/ + /// /// public sealed class ScreenplayOptions { diff --git a/CSF.Screenplay/ScreenplayServiceCollectionExtensions.cs b/CSF.Screenplay/ScreenplayServiceCollectionExtensions.cs index 2ba67f0d..7264a480 100644 --- a/CSF.Screenplay/ScreenplayServiceCollectionExtensions.cs +++ b/CSF.Screenplay/ScreenplayServiceCollectionExtensions.cs @@ -7,6 +7,7 @@ using CSF.Screenplay.Reporting; using CSF.Screenplay.ReportModel; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace CSF.Screenplay { @@ -22,65 +23,62 @@ public static class ScreenplayServiceCollectionExtensions /// /// Use this method to add Screenplay to an existing service collection; if you just want an instance of /// and do not care for integrating it with a service collection of your own then consider the convenience method - /// . - /// - /// - /// If you choose to provide any configuration via the parameter, do not 'capture' the - /// object outside the closure. This object is added to dependency injection as a singleton, and so if it is modified outside of - /// this configuration action then the integrity of the Screenplay dependency injection may be compromised. + /// . /// /// /// An - /// An optional configuration action, used to configure Screenplay in DI /// The service collection, so that calls may be chained /// If is . - public static IServiceCollection AddScreenplay(this IServiceCollection services, Action options = null) + public static IServiceCollection AddScreenplay(this IServiceCollection services) { if (services is null) throw new ArgumentNullException(nameof(services)); - var optionsModel = new ScreenplayOptions(); - options?.Invoke(optionsModel); - var eventBus = new PerformanceEventBus(); - optionsModel.PerformanceEventsConfig?.Invoke(eventBus); - - services.AddSingleton(); - services.AddSingleton(eventBus); - services.AddSingleton(s => s.GetRequiredService()); - services.AddSingleton(s => s.GetRequiredService()); - services.AddSingleton(optionsModel); - services.AddSingleton(s => s.GetRequiredService().ValueFormatters); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(s => - { - var reportPath = s.GetRequiredService().GetReportPath(); - if(reportPath is null) return new NoOpReporter(); - - var stream = File.Create(reportPath); - return ActivatorUtilities.CreateInstance(s, stream); - }); + services + .AddOptions() + .Configure((ScreenplayOptions o, PerformanceEventBus eventBus) => o.PerformanceEventsConfig?.Invoke(eventBus)); + + services + .AddSingleton() + .AddSingleton() + .AddSingleton(s => s.GetRequiredService()) + .AddSingleton(s => s.GetRequiredService()) + .AddSingleton(s => s.GetRequiredService>().Value.ValueFormatters) + .AddSingleton() + .AddSingleton() + .AddSingleton(s => + { + var reportPath = s.GetRequiredService().GetReportPath(); + if(reportPath is null) return new NoOpReporter(); + + var stream = File.Create(reportPath); + return ActivatorUtilities.CreateInstance(s, stream); + }); - services.AddScoped(s => new Cast(s, s.GetRequiredService().PerformanceIdentity)); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(s => s.GetRequiredService().GetCurrentPerformance()); - services.AddScoped(); + services + .AddScoped(s => new Cast(s, s.GetRequiredService().PerformanceIdentity)) + .AddScoped() + .AddScoped() + .AddScoped(s => s.GetRequiredService().GetCurrentPerformance()) + .AddScoped(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient, PerformanceReportBuilder>>(s => - { - return idsAndNames => ActivatorUtilities.CreateInstance(s, idsAndNames); - }); - services.AddTransient(); - foreach(var type in optionsModel.ValueFormatters) - services.AddTransient(type); + services + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient, PerformanceReportBuilder>>(s => + { + return idsAndNames => ActivatorUtilities.CreateInstance(s, idsAndNames); + }) + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient(); return services; } diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/AppleSafari.flags.json b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/AppleSafari.flags.json deleted file mode 100644 index 286888f1..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/AppleSafari.flags.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "browserName": "Safari", - "flags": [ - ], - }, - { - "browserName": "Safari", - "minVersion": "11", - "flags": [ - "HtmlElements.Select.RequiresUpdatesViaJavaScriptWorkaround", - ], - }, -] - diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/GoogleChrome.flags.json b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/GoogleChrome.flags.json deleted file mode 100644 index b62dc273..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/GoogleChrome.flags.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "browserName": "Chrome", - "flags": [ - "HtmlElements.InputTypeDate.RequiresEntryUsingLocaleFormat", - ], - }, -] \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/InternetExplorer.flags.json b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/InternetExplorer.flags.json deleted file mode 100644 index f92a921c..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/InternetExplorer.flags.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "browserName": [ "InternetExplorer", "Internet Explorer" ], - "flags": [ - ], - }, -] \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/MicrosoftEdge.flags.json b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/MicrosoftEdge.flags.json deleted file mode 100644 index d9fd8749..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/MicrosoftEdge.flags.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "browserName": "MicrosoftEdge", - "flags": [ - "Browser.CannotClearDomainCookies", - "HtmlElements.SelectMultiple.RequiresCtrlClickToToggleOptionSelection", - "HtmlElements.InputTypeDate.RequiresInputViaJavaScriptWorkaround", - ], - }, -] \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/MozillaFirefox.flags.json b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/MozillaFirefox.flags.json deleted file mode 100644 index c8e38046..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Definitions/MozillaFirefox.flags.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "browserName": "Firefox", - "flags": [ - "HtmlElements.InputTypeDate.RequiresInputViaJavaScriptWorkaround" - ], - }, -] diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.Browser.cs b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.Browser.cs deleted file mode 100644 index b1cef97f..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.Browser.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace CSF.Screenplay.Selenium -{ - public static partial class Flags - { - /// - /// Flags relating to the web browser itself, such as management of cookies. - /// - public static class Browser - { - /// - /// Indicates that the web driver is incapable of clearing the cookies for the current domain. - /// - /// - /// - /// The current domain is the domain for the page upon which the web driver is currently viewing. - /// - /// - public static readonly string CannotClearDomainCookies = "Browser.CannotClearDomainCookies"; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.HtmlElements.cs b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.HtmlElements.cs deleted file mode 100644 index 3be266d8..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.HtmlElements.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -namespace CSF.Screenplay.Selenium -{ - public static partial class Flags - { - /// - /// Flags relating to specific HTML elements. - /// - public static class HtmlElements - { - /// - /// Flags relating to HTML <input type="date"> elements. - /// - public static class InputTypeDate - { - /// - /// Indicates that the web driver may be used to enter a date using a format that conforms to the web browser's - /// current locale setting. - /// - public static readonly string RequiresEntryUsingLocaleFormat = "HtmlElements.InputTypeDate.RequiresEntryUsingLocaleFormat"; - - /// - /// Indicates that the web driver must use a JavaScript workaround to set the date, because it is impossible to do so - /// by typing keys. - /// - public static readonly string RequiresInputViaJavaScriptWorkaround = "HtmlElements.InputTypeDate.RequiresInputViaJavaScriptWorkaround"; - } - - /// - /// Flags relating to HTML <select multiple> elements. - /// - public static class SelectMultiple - { - /// - /// Indicates that the web driver must send Ctrl+Click in order to toggle the selection of a single - /// option within the select element. Without Ctrl, the click is interpreted as "change entire selection to just - /// the one option clicked". - /// - public static readonly string RequiresCtrlClickToToggleOptionSelection = "HtmlElements.SelectMultiple.RequiresCtrlClickToToggleOptionSelection"; - } - - /// - /// Flags relating to HTML <select> elements. - /// - public static class Select - { - /// - /// Indicates that the browser requires a JavaScript workaround in order to change the selection state - /// of an HTML <select> element. - /// - public static readonly string RequiresUpdatesViaJavaScriptWorkaround = "HtmlElements.Select.RequiresUpdatesViaJavaScriptWorkaround"; - } - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.cs b/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.cs deleted file mode 100644 index 2a0f2e1c..00000000 --- a/Old/CSF.Screenplay.Selenium.BrowserFlags_old/Flags.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -namespace CSF.Screenplay.Selenium -{ - /// - /// A catalogue of the the various browser flags of which this library is aware. - /// - public static partial class Flags - { - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/ArgumentsArrayValidator.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/ArgumentsArrayValidator.cs deleted file mode 100644 index 06e95245..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/ArgumentsArrayValidator.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// ArgumentsArrayValidator.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.ScriptResources -{ - /// - /// A stored JavaScript which validates a collection of arguments passed as an array. - /// - public class ArgumentsArrayValidator : ScriptResource - { - const string EntryPointNameConst = "validateArgumentsArray"; - - /// - /// Gets the name of the entry point for this script (which differs from the default). - /// - /// The name of the entry point. - public static string EntryPointName => EntryPointNameConst; - - /// - /// Gets the name of this script. - /// - /// The name. - public override string Name => "a JavaScript which validates function arguments arrays"; - - /// - /// Gets the name of the entry point to the script - this is the function exposed by - /// . - /// - /// The name of the entry point function. - public override string GetEntryPointName() => EntryPointName; - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/ArgumentsArrayValidator.js b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/ArgumentsArrayValidator.js deleted file mode 100644 index 6b653445..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/ArgumentsArrayValidator.js +++ /dev/null @@ -1,87 +0,0 @@ -var argumentsArrayValidator = function() -{ - 'use strict'; - - function getLengthParams(min, max) - { - if(typeof min === 'number' && max === undefined) - { - return { - count: min, - validateCount: true, - }; - } - - var minCount, validateMinCount = false, maxCount, validateMaxCount = false; - - if(typeof min === 'number') - { - minCount = min; - validateMinCount = true; - } - - if(typeof max === 'number') - { - maxCount = max; - validateMaxCount = true; - } - - return { - min: minCount, - validateMin: validateMinCount, - max: maxCount, - validateMax: validateMaxCount, - validateCount: false, - }; - } - - function validateType(argsArray) - { - if(!argsArray) throw new Error('Arguments must be a non-null array.'); - if(!(argsArray instanceof Array)) throw new Error('Arguments must be an array.'); - } - - function validateLength(argsArray, lengthParams) - { - if(lengthParams.validateCount && argsArray.length !== lengthParams.count) - throw new Error('Arguments array must contain precisely ' + lengthParams.count + ' item(s).'); - - if(lengthParams.validateMin && argsArray.length < lengthParams.min) - throw new Error('Arguments array must contain at least ' + lengthParams.min + ' item(s).'); - - if(lengthParams.validateMax && argsArray.length > lengthParams.max) - throw new Error('Arguments array must contain no more than ' + lengthParams.max + ' item(s).'); - } - - function validate(argsArray, min, max) - { - validateType(argsArray); - var lengthParams = getLengthParams(min, max); - validateLength(argsArray, lengthParams); - - return true; - } - - function selfValidate(argsArray, min, max) - { - try - { - return validate(argsArray, min, max); - } - catch(e) { throw new Error('The call to \'validateArgumentsArray\' raised an error: ' + e.message); } - } - - return { - validate: validate, - selfValidate: selfValidate, - }; -}(); - -function validateArgumentsArray(argsArray) -{ - 'use strict'; - - validator.selfValidate(argsArray, 1, 3); - var arrayToValidate = argsArray[0], min = argsArray[1], max = argsArray[2]; - return validator.validate(arrayToValidate, min, max); -} \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetALocalisedDate.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetALocalisedDate.cs deleted file mode 100644 index 8cb0206f..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetALocalisedDate.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// GetALocalisedDate.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.ScriptResources -{ - /// - /// Script resource for getting a localised date string - /// - public class GetALocalisedDate : ScriptResource - { - readonly ScriptResource argsValidator; - - /// - /// Gets the name of this script. - /// - /// The name. - public override string Name => "a JavaScript which converts a date to a locale-formatted string"; - - /// - /// Gets a collection of scripts which the current script instance depends upon. - /// - /// The dependencies. - protected override ScriptResource[] GetDependencies() => new [] { argsValidator }; - - /// - /// Initializes a new instance of the class. - /// - public GetALocalisedDate() : this(null) {} - - /// - /// Initializes a new instance of the class. - /// - /// Arguments validator. - public GetALocalisedDate(ScriptResource argsValidator) - { - this.argsValidator = argsValidator ?? new ArgumentsArrayValidator(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetALocalisedDate.js b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetALocalisedDate.js deleted file mode 100644 index 9456b68c..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetALocalisedDate.js +++ /dev/null @@ -1,17 +0,0 @@ -function executeScript(argsArray) { - 'use strict'; - - argumentsArrayValidator.validate(argsArray, 3); - - var - year = argsArray[0], - month = argsArray[1], - day = argsArray[2], - theDate; - - if(typeof year !== 'number' || typeof month !== 'number' || typeof day !== 'number') - throw new Error('The supplied year, month and day must all be numbers.'); - - theDate = new Date(year, month, day); - return theDate.toLocaleDateString(); -} \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetDocumentReadyState.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetDocumentReadyState.cs deleted file mode 100644 index bff50835..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetDocumentReadyState.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// GetDocumentReadyState.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.ScriptResources -{ - /// - /// Script resource for getting the document ready state. - /// - public class GetDocumentReadyState : ScriptResource - { - /// - /// Gets the name of this script. - /// - /// The name. - public override string Name => "a JavaScript which gets the current web page's ready-state"; - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetDocumentReadyState.js b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetDocumentReadyState.js deleted file mode 100644 index b8953856..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/GetDocumentReadyState.js +++ /dev/null @@ -1,4 +0,0 @@ -function executeScript(argsArray) { - 'use strict'; - return document.readyState; -} \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementAttribute.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementAttribute.cs deleted file mode 100644 index 93126cf8..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// SetAnElementAttribute.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.ScriptResources -{ - /// - /// Script resource for setting an attribute upon an element. - /// - public class SetAnElementAttribute : ScriptResource - { - /// - /// Gets the name of this script. - /// - /// The name. - public override string Name => "a JavaScript which sets an attribute upon an element"; - - /// - /// Gets a collection of scripts which the current script instance depends upon. - /// - /// The dependencies. - protected override ScriptResource[] GetDependencies() => new [] { new ArgumentsArrayValidator() }; - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementAttribute.js b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementAttribute.js deleted file mode 100644 index 79c5f7e9..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementAttribute.js +++ /dev/null @@ -1,24 +0,0 @@ -function executeScript(argsArray) -{ - 'use strict'; - - argumentsArrayValidator.validate(argsArray, 3); - - var htmlElement = argsArray[0], attributeName = argsArray[1], newValue = argsArray[2]; - - function validateElement(element) - { - if(element === null || element === undefined) - throw new Error('You must provide an HTML element object.'); - if(!(element instanceof HTMLElement)) - throw new Error('The element must be an HTML element.'); - } - - validateElement(htmlElement); - if(newValue === null) - htmlElement.removeAttribute(attributeName); - else - htmlElement.setAttribute(attributeName, newValue); - - return true; -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementValue.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementValue.cs deleted file mode 100644 index 3b9279da..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementValue.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// SetAnElementValue.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.ScriptResources -{ - /// - /// A stored JavaScript which sets the value of an HTML element and then triggers the 'change' event for that element. - /// - public class SetAnElementValue : ScriptResource - { - readonly ScriptResource argsValidator; - - /// - /// Gets the name of this script. - /// - /// The name. - public override string Name => "a JavaScript to set the value of an HTML element"; - - /// - /// Gets a collection of scripts which the current script instance depends upon. - /// - /// The dependencies. - protected override ScriptResource[] GetDependencies() => new [] { argsValidator }; - - /// - /// Initializes a new instance of the class. - /// - public SetAnElementValue() : this(null) {} - - /// - /// Initializes a new instance of the class. - /// - /// Arguments validator. - public SetAnElementValue(ScriptResource argsValidator) - { - this.argsValidator = argsValidator ?? new ArgumentsArrayValidator(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementValue.js b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementValue.js deleted file mode 100644 index d93f5b4f..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/SetAnElementValue.js +++ /dev/null @@ -1,36 +0,0 @@ -function executeScript(argsArray) -{ - 'use strict'; - - argumentsArrayValidator.validate(argsArray, 2); - - var htmlElement = argsArray[0], newValue = argsArray[1]; - - function validateElement(element) - { - if(element === null || element === undefined) - throw new Error('You must provide an HTML element object.'); - if(!(element instanceof HTMLElement)) - throw new Error('The element must be an HTML element.'); - if(element.value === undefined) - throw new Error('The element must have a \'value\' property.'); - } - - function setValue(element, val) - { - element.value = val; - } - - function triggerChangeEvent(element) - { - var ev = document.createEvent('Event'); - ev.initEvent('change', true, true); - element.dispatchEvent(ev); - } - - validateElement(htmlElement); - setValue(htmlElement, newValue); - triggerChangeEvent(htmlElement); - - return true; -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/UpdateSelectElementSelection.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/UpdateSelectElementSelection.cs deleted file mode 100644 index ef9a59a6..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/ScriptResources/UpdateSelectElementSelection.cs +++ /dev/null @@ -1,83 +0,0 @@ -// -// UpdateSelectElementSelection.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.ScriptResources -{ - /// - /// A stored JavaScript which sets the selected option(s) for an HTML <select> element. - /// - public class UpdateSelectElementSelection : ScriptResource - { - /// - /// Gets the action name for deselecting every option. - /// - public static readonly string DeselectAllActionName = "deselectAll"; - - /// - /// Gets the action name for selecting an option by its zero-based index. - /// - public static readonly string SelectByIndexActionName = "selectByIndex"; - - /// - /// Gets the action name for selecting an option by its value. - /// - public static readonly string SelectByValueActionName = "selectByValue"; - - /// - /// Gets the action name for selecting an option by its displyed text. - /// - public static readonly string SelectByTextActionName = "selectByText"; - - /// - /// Gets the action name for deselecting an option by its zero-based index. - /// - public static readonly string DeselectByIndexActionName = "deselectByIndex"; - - /// - /// Gets the action name for deselecting an option by its value. - /// - public static readonly string DeselectByValueActionName = "deselectByValue"; - - /// - /// Gets the action name for deselecting an option by its displayed text. - /// - public static readonly string DeselectByTextActionName = "deselectByText"; - - /// - /// Gets the name of this script. - /// - /// The name. - public override string Name => "a JavaScript to set the select options of an HTML element.'); - } - - var optionUpdater = function() - { - function triggerChangeEvent(element) - { - var ev = document.createEvent('Event'); - ev.initEvent('change', true, true); - element.dispatchEvent(ev); - } - - function getOptionByIndex(selectElement, index) - { - return selectElement.item(index); - } - - function getOptionByValue(selectElement, value) - { - var options = selectElement.options; - for(var i = 0, len = options.length; i < len; i++) - if(options[i].value === value) return options[i]; - return null; - } - - function getOptionByText(selectElement, text) - { - var options = selectElement.options; - for(var i = 0, len = options.length; i < len; i++) - if(options[i].text === text) return options[i]; - return null; - } - - function setSelectedByIndex(selectElement, index, selected) - { - var option = getOptionByIndex(selectElement, index); - return setSelected(selectElement, option, selected); - } - - function setSelectedByValue(selectElement, value, selected) - { - var option = getOptionByValue(selectElement, value); - return setSelected(selectElement, option, selected); - } - - function setSelectedByText(selectElement, text, selected) - { - var option = getOptionByText(selectElement, text); - return setSelected(selectElement, option, selected); - } - - function setSelected(selectElement, option, selected) - { - if(!option) return false; - option.selected = selected; - triggerChangeEvent(selectElement); - return true; - } - - function deselectAll(selectElement) - { - var options = selectElement.options; - for(var i = 0, len = options.length; i < len; i++) - options.item(i).selected = false; - triggerChangeEvent(selectElement); - return options.length > 0; - } - - return { - selectByIndex: function(ele, idx) { return setSelectedByIndex(ele, idx, true); }, - selectByValue: function(ele, val) { return setSelectedByValue(ele, val, true); }, - selectByText: function(ele, txt) { return setSelectedByText(ele, txt, true); }, - deselectByIndex: function(ele, idx) { return setSelectedByIndex(ele, idx, false); }, - deselectByValue: function(ele, val) { return setSelectedByValue(ele, val, false); }, - deselectByText: function(ele, txt) { return setSelectedByText(ele, txt, false); }, - deselectAll: deselectAll, - }; - - }(); - - var - element = argsArray[0], - action = argsArray[1], - value = argsArray[2]; - - validateElement(element); - - if(!optionUpdater.hasOwnProperty(action)) - throw new Error("The action '" + action + "' was not recognised."); - - return optionUpdater[action](element, value); -} \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ICreatesInvocationScript.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ICreatesInvocationScript.cs deleted file mode 100644 index 339a9f34..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ICreatesInvocationScript.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// IInvokesScripts.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// A service which creates a JavaScript which is used for the purpose of invoking other JavaScripts. - /// - public interface ICreatesInvocationScript - { - /// - /// Gets an invocation script for the given entry point name. - /// - /// The invocation script. - /// The name of the entry point which should be invoked. - string GetScript(string entryPoint); - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/IProvidesScript.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/IProvidesScript.cs deleted file mode 100644 index 9b0461aa..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/IProvidesScript.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// IStoredScript.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// A service which provides a JavaScript fragment with a named entry point. - /// - public interface IProvidesScript - { - /// - /// Gets the name of this script. - /// - /// The name. - string Name { get; } - - /// - /// Gets a JavaScript which includes a named function. The name of that function is exposed via - /// . - /// - /// The script. - string GetScript(); - - /// - /// Gets the name of the entry point to the script - this is the function exposed by . - /// - /// The name of the entry point function. - string GetEntryPointName(); - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/IRunsScripts.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/IRunsScripts.cs deleted file mode 100644 index 244a2c2c..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/IRunsScripts.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// IRunsStoredScripts.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using OpenQA.Selenium; - -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// A service which executes JavaScripts using given parameters. - /// - public interface IRunsScripts - { - /// - /// Executes the script exposed by the given script provider and returns the result. - /// - /// The script result. - /// A JavaScript provider. - /// A web driver. - /// The script arguments. - object ExecuteScript(IProvidesScript script, IWebDriver webDriver, params object[] arguments); - - /// - /// Executes the script and returns the result. - /// - /// The script result. - /// A JavaScript. - /// A web driver. - /// The script arguments. - object ExecuteScript(string script, IWebDriver webDriver, params object[] arguments); - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptInvokerFactory.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptInvokerFactory.cs deleted file mode 100644 index c3776f33..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptInvokerFactory.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// ArgumentsArrayConverter.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// A special stored JavaScript which is used to invoke other JavaScripts. - /// - public class ScriptInvokerFactory : ICreatesInvocationScript - { - readonly ScriptResourceLoader loader; - - /// - /// Gets an invocation script for the given entry point name. - /// - /// The invocation script. - /// The name of the entry point which should be invoked. - public string GetScript(string entryPoint) - { - var invokerService = loader.GetScriptFor(); - var invocationLine = GetInvocationLine(entryPoint); - - return String.Concat(invokerService, Environment.NewLine, invocationLine); - } - - string GetInvocationLine(string entryPoint) - => $"return invoker.invoke({entryPoint}, arguments);"; - - /// - /// Initializes a new instance of the class. - /// - public ScriptInvokerFactory() - { - loader = new ScriptResourceLoader(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptInvokerFactory.js b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptInvokerFactory.js deleted file mode 100644 index 689a2f9b..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptInvokerFactory.js +++ /dev/null @@ -1,24 +0,0 @@ -var invoker = function() -{ - 'use strict'; - - function validateEntryPoint(entryPoint) - { - if(!entryPoint || typeof entryPoint !== 'function') - throw new Error('The script entry-point must be a function'); - } - - function getArgumentsObjectAsArray(argumentsObject) - { - return Array.prototype.slice.call(argumentsObject); - } - - function invoke(entryPoint, argumentsObject) - { - validateEntryPoint(entryPoint); - var args = getArgumentsObjectAsArray(argumentsObject); - return entryPoint(args); - } - - return { invoke: invoke }; -}(); diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptResource.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptResource.cs deleted file mode 100644 index 2f511b50..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptResource.cs +++ /dev/null @@ -1,103 +0,0 @@ -// -// ScriptResource.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Linq; - -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// Abstract implementation of for a JavaScript which is stored as an embedded resource. - /// - public abstract class ScriptResource : IProvidesScript - { - internal const string - DefaultEntryPointName = "executeScript"; - readonly ScriptResourceLoader scriptLoader; - - /// - /// Gets the name of this script. - /// - /// The name. - public virtual string Name => GetType().Name; - - /// - /// Gets the name of the entry point to the script - this is the function exposed by - /// . - /// - /// The name of the entry point function. - public virtual string GetEntryPointName() => DefaultEntryPointName; - - /// - /// Gets a JavaScript which includes a named function. The name of that function is exposed via - /// . - /// - /// The script. - public virtual string GetScript() => CombineScripts(this, GetDependencies()); - - /// - /// Gets the script fragment as a named function (without any dependency scripts, if any). - /// The name of that function is exposed via - /// . - /// - /// The current script. - protected virtual string GetScriptWithoutDependencies() => scriptLoader.GetScriptFor(GetType()); - - /// - /// Gets a collection of scripts which the current script instance depends upon. - /// - /// The dependencies. - protected virtual ScriptResource[] GetDependencies() => new ScriptResource[0]; - - /// - /// Combines the given script (which provides an entry point) with other scripts, creating one long script. - /// - /// The scripts. - /// Entry point provider. - /// Scripts. - protected string CombineScripts(ScriptResource entryPointProvider, params ScriptResource[] scripts) - { - if(entryPointProvider == null) - throw new ArgumentNullException(nameof(entryPointProvider)); - if(scripts == null) - throw new ArgumentNullException(nameof(scripts)); - - var scriptsToCombine = scripts - .Select(x => x.GetScript()) - .Union(new [] { entryPointProvider.GetScriptWithoutDependencies() }) - .ToArray(); - - return String.Join(Environment.NewLine, scriptsToCombine); - } - - /// - /// Initializes a new instance of the class. - /// - public ScriptResource() - { - scriptLoader = new ScriptResourceLoader(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptResourceLoader.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptResourceLoader.cs deleted file mode 100644 index 55b0f44d..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptResourceLoader.cs +++ /dev/null @@ -1,59 +0,0 @@ -// -// ScriptResourceLoader.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Reflection; - -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// Loads a string manifest resource representing a JavaScript which matches the name of a System.Type. - /// - public class ScriptResourceLoader - { - /// - /// Gets the JavaScript for the given type. - /// - /// The JavaScript resource. - /// The type for which to load script. - public string GetScriptFor() - => GetScriptFor(typeof(T)); - - /// - /// Gets the JavaScript for the given type. - /// - /// The JavaScript resource. - /// The type for which to load script. - public string GetScriptFor(Type type) - { - if(type == null) - throw new ArgumentNullException(nameof(type)); - - var scriptAssembly = type.Assembly; - - return scriptAssembly.GetManifestResourceText(type, $"{type.Name}.js"); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptRunner.cs b/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptRunner.cs deleted file mode 100644 index 769d54ff..00000000 --- a/Old/CSF.Screenplay.Selenium.JavaScriptWorkarounds_old/StoredScripts/ScriptRunner.cs +++ /dev/null @@ -1,106 +0,0 @@ -// -// ScriptRunner.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using OpenQA.Selenium; - -namespace CSF.Screenplay.Selenium.StoredScripts -{ - /// - /// Default implementation of - /// - public class ScriptRunner : IRunsScripts - { - readonly ICreatesInvocationScript invoker; - - /// - /// Executes the script and returns the result. - /// - /// The script result. - /// A JavaScript. - /// A web driver. - /// The script arguments. - public object ExecuteScript(string script, IWebDriver webDriver, params object[] arguments) - { - if(script == null) - throw new ArgumentNullException(nameof(script)); - if(webDriver == null) - throw new ArgumentNullException(nameof(webDriver)); - - var javaScriptRunner = GetJavaScriptExecutor(webDriver); - return javaScriptRunner.ExecuteScript(script, arguments); - } - - /// - /// Executes the script exposed by the given script provider and returns the result. - /// - /// The script result. - /// A JavaScript provider. - /// A web driver. - /// The script arguments. - public object ExecuteScript(IProvidesScript script, IWebDriver webDriver, params object[] arguments) - { - if(script == null) - throw new ArgumentNullException(nameof(script)); - if(webDriver == null) - throw new ArgumentNullException(nameof(webDriver)); - - var scriptBody = GetScriptBodyWithInvoker(script); - return ExecuteScript(scriptBody, webDriver, arguments); - } - - string GetScriptBodyWithInvoker(IProvidesScript script) - { - var scriptBody = script.GetScript(); - var invokerBody = invoker.GetScript(script.GetEntryPointName()); - - return String.Concat(scriptBody, Environment.NewLine, invokerBody); - } - - IJavaScriptExecutor GetJavaScriptExecutor(IWebDriver driver) - { - var jsDriver = driver as IJavaScriptExecutor; - - if(jsDriver == null) - throw new ArgumentException($"The {nameof(IWebDriver)} must support the execution of JavaScript.", nameof(driver)); - - return jsDriver; - } - - /// - /// Initializes a new instance of the class. - /// - public ScriptRunner() : this(null) {} - - /// - /// Initializes a new instance of the class. - /// - /// A JavaScript which invokes other scripts via their named entry points. - public ScriptRunner(ICreatesInvocationScript invoker) - { - this.invoker = invoker ?? new ScriptInvokerFactory(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Actions/TargetNotFoundTests.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Actions/TargetNotFoundTests.cs deleted file mode 100644 index c2b62286..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Actions/TargetNotFoundTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.NUnit; -using CSF.Screenplay.Selenium.Abilities; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Models; -using CSF.Screenplay.Selenium.Tests.Pages; -using NUnit.Framework; -using static CSF.Screenplay.StepComposer; - -namespace CSF.Screenplay.Selenium.Tests.Actions -{ - [TestFixture] - [Description("Behaviours when a target is not found for a desired action")] - public class TargetNotFoundTests - { - [Test,Screenplay] - [Description("Attempting to click on a link which does not exist raises an appropriate 'target not found' exception.")] - public void Click_on_non_existent_element_raises_TargetNotFoundException(ICast cast, BrowseTheWeb browseTheWeb) - { - var joe = cast.Get("Joe");joe.IsAbleTo(browseTheWeb); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - - Assert.That(() => When(joe).AttemptsTo(Click.On(ListsPage.ListOfItems)), - Throws.TypeOf()); - } - - [Test,Screenplay] - [Description("When a 'target not found' exception is raised, it should have a name which matches the missing target.")] - public void TargetNotFoundException_raised_has_correct_target_name(ICast cast, BrowseTheWeb browseTheWeb) - { - var joe = cast.Get("Joe");joe.IsAbleTo(browseTheWeb); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - - IHasTargetName target = null; - try - { - When(joe).AttemptsTo(Click.On(ListsPage.ListOfItems)); - Assert.Fail("The action should raise an exception."); - } - catch(TargetNotFoundException ex) - { - target = ex.Target; - } - catch(Exception ex) - { - Assert.Fail($"Wrong exception type caught. Expected {nameof(TargetNotFoundException)}, got:\n{ex.ToString()}"); - } - - Assert.That(target, Is.Not.Null, "Target should not be null."); - Assert.That(target.GetName(), Is.EqualTo(ListsPage.ListOfItems.GetName()), "Target has the correct name"); - } - - [Test,Screenplay] - [Description("A 'target not found' exception should include the target name in its report when the target is provided.")] - public void TargetNotFoundException_includes_target_name_in_report(ICast cast, BrowseTheWeb browseTheWeb) - { - var joe = cast.Get("Joe");joe.IsAbleTo(browseTheWeb); - var ex = new TargetNotFoundException() { Target = ListsPage.ListOfItems }; - - var result = ex.GetReport(joe); - - Assert.That(result, Is.EqualTo("Joe cannot see the list of items on the screen.")); - } - - [Test,Screenplay] - [Description("A 'target not found' exception should include the target name in its report when the target is provided.")] - public void TargetNotFoundException_can_create_a_report_without_target(ICast cast, BrowseTheWeb browseTheWeb) - { - var joe = cast.Get("Joe");joe.IsAbleTo(browseTheWeb); - var ex = new TargetNotFoundException(); - - var result = ex.GetReport(joe); - - Assert.That(result, Is.EqualTo("Joe cannot see the required element on the screen.")); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/DateInputPage.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/DateInputPage.cs deleted file mode 100644 index cfd399f6..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/DateInputPage.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// DateInputPage.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class DateInputPage : Page - { - public override string GetName() => "the date-input page"; - - public override IUriProvider GetUriProvider() => new AppUri("DateInput"); - - public static ILocatorBasedTarget DateInput = new ElementId("DateInput", "the date input field"); - - public static ILocatorBasedTarget DateOutput = new ElementId("DateOutput", "the date display"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ElementsWithAttributesPage.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ElementsWithAttributesPage.cs deleted file mode 100644 index db45f496..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ElementsWithAttributesPage.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// ElementsWithAttributesPage.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class ElementsWithAttributesPage : Page - { - public override string GetName() => "the elements-with-attributes page"; - - public override IUriProvider GetUriProvider() => new AppUri("ElementsWithAttributes"); - - public static ILocatorBasedTarget DivWithClass = new ElementId("DivWithClass", "a div with a class attribute"); - - public static ILocatorBasedTarget ClassOutput = new ElementId("DisplayDivClass", "the displayed class"); - - public static ILocatorBasedTarget DateInput = new ElementId("DateInput", "the date input field"); - - public static ILocatorBasedTarget DateOutput = new ElementId("DisplayDateReadonly", "the displayed date-readonly attribute"); - - public static ILocatorBasedTarget TextInput = new ElementId("TextInput", "the text input field"); - - public static ILocatorBasedTarget TextOutput = new ElementId("DisplayTextReadonly", "the displayed text-readonly attribute"); - - public static ILocatorBasedTarget TextPlaceholder = new ElementId("DisplayTextPlaceholder", "the displayed text-placeholder attribute"); - - public static ILocatorBasedTarget GetOutputButton = new ElementId("GetOutput", "the button which refreshes the outputs"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/HomePage.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/HomePage.cs deleted file mode 100644 index 659b338b..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/HomePage.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class HomePage : Page - { - public override string GetName() => "the app home page"; - - public override IUriProvider GetUriProvider() => new AppUri("Home"); - - public static ITarget SecondPageLink => new ClassName("second_page_link", "the hyperlink to page two"); - - public static ITarget SlowLoadingLink => new ElementId("load_in_2_seconds", "the link to reload with a 2-second delay"); - - public static ITarget LoadDelay => new ElementId("load_delay", "the readout of the page-load delay"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ListsPage.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ListsPage.cs deleted file mode 100644 index f1ba4403..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ListsPage.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// ListsPage.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class ListsPage : Page - { - public override string GetName() => "the lists testing page"; - - public override IUriProvider GetUriProvider() => new AppUri("Lists"); - - public static ITarget SingleSelectionList => new CssSelector("#single_selection", "the single selection list"); - - public static ITarget SingleSelectionValue => new CssSelector("#single_selected_value", "the single-selection value"); - - public static ITarget MultiSelectionList => new CssSelector("#multiple_selection", "the multi selection list"); - - public static ITarget MultiSelectionValue => new CssSelector("#multiple_selected_value", "the multi-selection value"); - - public static ITarget ListOfItems => new CssSelector("#list_of_items", "the list of items"); - - public static ILocatorBasedTarget ItemsInTheList => new CssSelector("#list_of_items li", "items in the list"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/PageThree.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/PageThree.cs deleted file mode 100644 index 9d71c802..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/PageThree.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class PageThree : Page - { - public override string GetName() => "page three"; - - public override IUriProvider GetUriProvider() => new AppUri("PageThree"); - - public static ITarget DelayedButtonOne => new CssSelector("#delay_click_one", "the first delay button"); - - public static ITarget DelayedLinkOne => new CssSelector("#delay_appear_target_one .appeared", "the first delay-appearance link"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/PageTwo.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/PageTwo.cs deleted file mode 100644 index ee3ed9b2..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/PageTwo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class PageTwo : Page - { - public override string GetName() => "the second page"; - - public override IUriProvider GetUriProvider() => new AppUri("PageTwo"); - - public static ILocatorBasedTarget SpecialInputField => new CssSelector(".special_text input", "the special input field"); - - public static ITarget SecondTextbox => new CssSelector(".second_textbox input", "the second text box"); - - public static ITarget TheDynamicTextArea => new ElementId("dynamic_value", "the dynamic value"); - - public static ITarget JavaScriptResult => new ElementId("ScriptOutput", "the Javascript output"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ReadElementsPage.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ReadElementsPage.cs deleted file mode 100644 index 269d69c3..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ReadElementsPage.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// InputPage.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class ReadElementsPage : Page - { - public override string GetName() => "the page for testing reading HTML elements"; - - public override IUriProvider GetUriProvider() => new AppUri("ReadElements"); - - public static ITarget ImportantString => new ElementId("important_string", "the string element"); - - public static ITarget ImportantNumber => new ElementId("important_number", "the numeric element"); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ScriptTestingHarness.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ScriptTestingHarness.cs deleted file mode 100644 index 7881c6af..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Pages/ScriptTestingHarness.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// ScriptTestingHarness.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Models; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.Tests.Pages -{ - public class ScriptTestingHarness : Page - { - readonly IProvidesScript scriptProvider; - - public override string GetName() => $"the Jasmine test harness for {scriptProvider.Name}"; - - public override IUriProvider GetUriProvider() - => new AppUri($"StoredScriptTest/Index/{scriptProvider.GetType().Name}"); - - public static ILocatorBasedTarget TheResultsBar - => new CssSelector(".jasmine_html-reporter .jasmine-bar", "the Jasmine results bar"); - - public ScriptTestingHarness(IProvidesScript scriptProvider) - { - if(scriptProvider == null) - throw new ArgumentNullException(nameof(scriptProvider)); - - this.scriptProvider = scriptProvider; - } - - public static ScriptTestingHarness For() where TScript : IProvidesScript, new() - => new ScriptTestingHarness(new TScript()); - - public static ScriptTestingHarness For(Type scriptType) - => new ScriptTestingHarness((IProvidesScript) Activator.CreateInstance(scriptType)); - - public static ScriptTestingHarness For(IProvidesScript script) - => new ScriptTestingHarness(script); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/ScriptResources/SetAnAttributeValueTests.cs b/Old/CSF.Screenplay.Selenium.Tests_old/ScriptResources/SetAnAttributeValueTests.cs deleted file mode 100644 index 912c9324..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/ScriptResources/SetAnAttributeValueTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// SetAnAttributeValueTests.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.NUnit; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Tests.Pages; -using CSF.Screenplay.Selenium.Tests.Personas; -using FluentAssertions; -using NUnit.Framework; -using static CSF.Screenplay.StepComposer; - -namespace CSF.Screenplay.Selenium.Tests.ScriptResources -{ - [TestFixture,Description("Setting the value of an attribute using JavaScript")] - public class SetAnAttributeValueTests - { - [Test,Screenplay,Description("Removing an attribute should result in successful removal")] - public void Removing_an_attribute_should_remove_it(ICast cast) - { - var joe = cast.Get(); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - var element = Given(joe).WasAbleTo(Get.TheElement(ElementsWithAttributesPage.TextInput)); - - When(joe).AttemptsTo(Execute.JavaScript.WhichRemovesTheAttribute("readonly").From(element)); - When(joe).AttemptsTo(Click.On(ElementsWithAttributesPage.GetOutputButton)); - - Then(joe).ShouldSee(TheText.Of(ElementsWithAttributesPage.TextOutput)).Should().Be(String.Empty); - } - - [Test,Screenplay,Description("Removing an unrelated attribute should not affect the original")] - public void Removing_a_disabled_attribute_should_not_the_readonly_attribute(ICast cast) - { - var joe = cast.Get(); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - var element = Given(joe).WasAbleTo(Get.TheElement(ElementsWithAttributesPage.TextInput)); - - When(joe).AttemptsTo(Execute.JavaScript.WhichRemovesTheAttribute("disabled").From(element)); - When(joe).AttemptsTo(Click.On(ElementsWithAttributesPage.GetOutputButton)); - - Then(joe).ShouldSee(TheText.Of(ElementsWithAttributesPage.TextOutput)).Should().Be("readonly"); - } - - [Test,Screenplay,Description("Setting a previously-unset attribute should update its value")] - public void Editing_an_attribute_should_set_it_to_the_new_value(ICast cast) - { - var joe = cast.Get(); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - var element = Given(joe).WasAbleTo(Get.TheElement(ElementsWithAttributesPage.TextInput)); - - When(joe).AttemptsTo(Execute.JavaScript.WhichSetsTheAttribute("placeholder").For(element).To("New placeholder")); - When(joe).AttemptsTo(Click.On(ElementsWithAttributesPage.GetOutputButton)); - - Then(joe).ShouldSee(TheText.Of(ElementsWithAttributesPage.TextPlaceholder)).Should().Be("New placeholder"); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/ScriptResources/SetAnElementValueTests.cs b/Old/CSF.Screenplay.Selenium.Tests_old/ScriptResources/SetAnElementValueTests.cs deleted file mode 100644 index 2e744bf2..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/ScriptResources/SetAnElementValueTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// SetAnElementValueTests.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.NUnit; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Tests.Pages; -using CSF.Screenplay.Selenium.Tests.Personas; -using FluentAssertions; -using NUnit.Framework; -using static CSF.Screenplay.StepComposer; - -namespace CSF.Screenplay.Selenium.Tests.ScriptResources -{ - [TestFixture] - [Description("The SetAnElementValue stored JavaScript")] - public class SetAnElementValueTests - { - [Test,Screenplay,Description("Executing the script successfully sets the value of the element")] - public void Executing_the_script_successfully_sets_the_value(ICast cast) - { - var joe = cast.Get(); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - var theElement = Given(joe).WasAbleTo(Get.TheElement(PageTwo.SpecialInputField)); - - When(joe).AttemptsTo(Execute.JavaScript.WhichSetsTheValueOf(theElement).To("The right value")); - - Then(joe).ShouldSee(TheText.Of(PageTwo.TheDynamicTextArea)).Should().Be("different value"); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/SampleScript.cs b/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/SampleScript.cs deleted file mode 100644 index 96426a1e..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/SampleScript.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// SampleScript.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.Tests.StoredScripts -{ - public class SampleScript : ScriptResource - { - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/SampleScript.js b/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/SampleScript.js deleted file mode 100644 index 02f5bb61..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/SampleScript.js +++ /dev/null @@ -1,4 +0,0 @@ -function executeScript(argsArray) -{ - window.console.log('Test'); -} \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/ScriptResourceTests.cs b/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/ScriptResourceTests.cs deleted file mode 100644 index 86d9d9a7..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/ScriptResourceTests.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// ScriptResourceTests.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using NUnit.Framework; - -namespace CSF.Screenplay.Selenium.Tests.StoredScripts -{ - [TestFixture] - public class ScriptResourceTests - { - [Test] - public void Sample_Script_has_correct_script_body() - { - // Arrange - var expectedScript = @"function executeScript(argsArray) -{ - window.console.log('Test'); -}"; - var sut = new SampleScript(); - - // Act - var actualScript = sut.GetScript(); - - // Assert - Assert.That(actualScript, Is.EqualTo(expectedScript)); - } - - [Test] - public void Sample_Script_has_correct_entry_point_name() - { - // Arrange - var expectedName = @"executeScript"; - var sut = new SampleScript(); - - // Act - var actualName = sut.GetEntryPointName(); - - // Assert - Assert.That(actualName, Is.EqualTo(expectedName)); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/ScriptRunnerTests.cs b/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/ScriptRunnerTests.cs deleted file mode 100644 index 6c39d2cc..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/ScriptRunnerTests.cs +++ /dev/null @@ -1,84 +0,0 @@ -// -// ScriptRunnerTests.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; -using Moq; -using NUnit.Framework; -using OpenQA.Selenium; - -namespace CSF.Screenplay.Selenium.Tests.StoredScripts -{ - [TestFixture] - public class ScriptRunnerTests - { - [Test] - public void ExecuteScript_passes_correct_script_to_webdriver() - { - // Arrange - var script = Mock.Of(); - var driver = new Mock(); - driver.As(); - var invoker = Mock.Of(x => x.GetScript(It.IsAny()) == "return fooBar(argsArray);"); - var sut = new ScriptRunner(invoker); - - Mock.Get(script).Setup(x => x.GetScript()).Returns("function fooBar(argsArray) {}"); - Mock.Get(script).Setup(x => x.GetEntryPointName()).Returns("fooBar"); - - var expectedExecutedScript = @"function fooBar(argsArray) {} -return fooBar(argsArray);"; - - // Act - sut.ExecuteScript(script, driver.Object); - - // Assert - driver - .As() - .Verify(x => x.ExecuteScript(expectedExecutedScript), Times.Once); - } - - [Test] - public void ExecuteScript_passes_correct_script_arguments_to_webdriver() - { - // Arrange - var script = Mock.Of(); - var driver = new Mock(); - driver.As(); - var invoker = Mock.Of(x => x.GetScript(It.IsAny()) == String.Empty); - var sut = new ScriptRunner(invoker); - - Mock.Get(script).Setup(x => x.GetScript()).Returns(String.Empty); - Mock.Get(script).Setup(x => x.GetEntryPointName()).Returns(String.Empty); - - // Act - sut.ExecuteScript(script, driver.Object, 1, 2, "three"); - - // Assert - driver - .As() - .Verify(x => x.ExecuteScript(It.IsAny(), 1, 2, "three"), Times.Once); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/TestAllScriptsViaTestingHarness.cs b/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/TestAllScriptsViaTestingHarness.cs deleted file mode 100644 index 4455e0c4..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/StoredScripts/TestAllScriptsViaTestingHarness.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// TestAllScriptsViaTestingHarness.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using CSF.Screenplay.NUnit; -using CSF.Screenplay.Selenium.Tests.Personas; -using CSF.Screenplay.Selenium.Tests.Tasks; -using NUnit.Framework; -using static CSF.Screenplay.StepComposer; - -namespace CSF.Screenplay.Selenium.Tests.StoredScripts -{ - [TestFixture] - [Description("The JavaScripts in the CSF.Screenplay.Selenium.JavaScriptWorkarounds project")] - public class TestAllScriptsViaTestingHarness - { - [Test,Screenplay] - [Description("Every script should pass a Jasmine test suite")] - public void Every_script_in_the_main_assembly_must_pass_its_Jasmine_test_suite(ICast cast) - { - /* Please note that this single test scenario will test every available script using all of the - * available Jasmine test suites. Those Jasmine tests themselves are not held within this project. - * - * They are all written using JavaScript and are found within the CSF.Screenplay.WebTestWebsite project, - * at the path: - * Scripts/script-tests/ - * Each class in the CSF.Screenplay.Selenium.JavaScriptWorkarounds project has its own test suite in that - * directory, named after the name of its class, with the suffix 'tests.js'. - * - * If further JavaScript workarounds are added then each should have its own test suite in that path. - */ - var joe = cast.Get(); - - var scriptTypes = Given(joe).Got(AllOfTheExecutableScriptTypes.FromTheMainAssembly()); - var results = When(joe).Gets(AllOfTheScriptTestResults.ForTheScriptTypes(scriptTypes)); - Then(joe).Should(VerifyThatAllOfTheScriptTestsPassed.ForTheResults(results)); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/AllOfTheExecutableScriptTypes.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/AllOfTheExecutableScriptTypes.cs deleted file mode 100644 index bd41e3ed..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/AllOfTheExecutableScriptTypes.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// GetAllOfTheScriptTypes.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Collections.Generic; -using System.Linq; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.ScriptResources; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - public class AllOfTheExecutableScriptTypes : Question> - { - protected override string GetReport(INamed actor) - => $"{actor.Name} gets all of the executable script provider types from the main assembly."; - - protected override IReadOnlyCollection PerformAs(IPerformer actor) - { - var assembly = typeof(IProvidesScript).Assembly; - return assembly.GetExportedTypes().Where(IsExecutableScriptType).ToArray(); - } - - bool IsExecutableScriptType(Type type) - { - if(!typeof(IProvidesScript).IsAssignableFrom(type)) return false; - if(!type.IsClass || type.IsAbstract) return false; - if(typeof(ICreatesInvocationScript).IsAssignableFrom(type)) return false; - return true; - } - - public static IQuestion> FromTheMainAssembly() - => new AllOfTheExecutableScriptTypes(); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/AllOfTheScriptTestResults.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/AllOfTheScriptTestResults.cs deleted file mode 100644 index 2f74dfaf..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/AllOfTheScriptTestResults.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// GetAllOfTheScriptTestResults.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Collections.Generic; -using System.Linq; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - public class AllOfTheScriptTestResults : Question> - { - readonly IReadOnlyCollection types; - - protected override string GetReport(INamed actor) => $"{actor.Name} runs all of the Jasmine script tests and gets their results"; - - protected override IReadOnlyCollection PerformAs(IPerformer actor) - => GetResults(actor).ToArray(); - - IEnumerable GetResults(IPerformer actor) - { - foreach(var type in types) - yield return actor.Perform(TestTheStoredScript.OfType(type)); - } - - public AllOfTheScriptTestResults(IReadOnlyCollection types) - { - if(types == null) - throw new ArgumentNullException(nameof(types)); - - this.types = types; - } - - public static IQuestion> ForTheScriptTypes(IReadOnlyCollection types) - => new AllOfTheScriptTestResults(types); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/EnterTextIntoThePageTwoInputField.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/EnterTextIntoThePageTwoInputField.cs deleted file mode 100644 index 461246b3..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/EnterTextIntoThePageTwoInputField.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Tests.Pages; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - public class EnterTextIntoThePageTwoInputField : Performable - { - readonly string text; - - protected override string GetReport(INamed actor) - => $"{actor.Name} enters '{text}' into the input field on page two"; - - protected override void PerformAs(IPerformer actor) - { - actor.Perform(OpenTheirBrowserOn.ThePage()); - actor.Perform(Enter.TheText(text).Into(PageTwo.SpecialInputField)); - } - - public EnterTextIntoThePageTwoInputField(string text) - { - if(text == null) - throw new ArgumentNullException(nameof(text)); - - this.text = text; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/EnterTheDateTests.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/EnterTheDateTests.cs deleted file mode 100644 index 0a9145f6..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/EnterTheDateTests.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.NUnit; -using CSF.Screenplay.Selenium.Abilities; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Tests.Pages; -using CSF.Screenplay.Selenium.Tests.Personas; -using FluentAssertions; -using NUnit.Framework; -using static CSF.Screenplay.StepComposer; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - [TestFixture] - [Description("Entering dates")] - public class EnterTheDateTests - { - [Test,Screenplay] - [Description("Entering a date into an HTML 5 input field should work cross-browser")] - public void Enter_TheDate_puts_the_correct_value_into_the_control(ICast cast, BrowseTheWeb browseTheWeb) - { - var joe = cast.Get(); - - var date = new DateTime(2012, 5, 6); - var expectedString = date.ToString("yyyy-MM-dd"); - - Given(joe).WasAbleTo(OpenTheirBrowserOn.ThePage()); - - When(joe).AttemptsTo(Enter.TheDate(date).Into(DateInputPage.DateInput)); - - Then(joe).ShouldSee(TheText.Of(DateInputPage.DateOutput)) - .Should() - .Be(expectedString, because: "the displayed date should match"); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/ScriptTestResult.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/ScriptTestResult.cs deleted file mode 100644 index 46a4371f..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/ScriptTestResult.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// ScriptTestResult.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.StoredScripts; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - public class ScriptTestResult - { - public IProvidesScript Script { get; } - - public bool Success { get; } - - public ScriptTestResult(IProvidesScript script, bool result) - { - if(script == null) - throw new ArgumentNullException(nameof(script)); - - Script = script; - Success = result; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/TestTheStoredScript.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/TestTheStoredScript.cs deleted file mode 100644 index 7f4ef0a8..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/TestTheStoredScript.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// TestTheStoredScript.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Text.RegularExpressions; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.StoredScripts; -using CSF.Screenplay.Selenium.Tests.Pages; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - public class TestTheStoredScript : Question - { - const string JasminePassedClassPattern = @"\bjasmine-passed\b"; - static readonly Regex PassMatcher = new Regex(JasminePassedClassPattern, RegexOptions.Compiled); - - readonly IProvidesScript script; - - protected override string GetReport(INamed actor) - => $"{actor.Name} gets the result for {script.Name}"; - - protected override ScriptTestResult PerformAs(IPerformer actor) - { - var theTestPage = ScriptTestingHarness.For(script); - actor.Perform(OpenTheirBrowserOn.ThePage(theTestPage)); - - actor.Perform(Wait.ForAtMost(5).Seconds().OrUntil(ScriptTestingHarness.TheResultsBar).IsVisible()); - - var classAttribute = actor.Perform(TheAttribute.Named("class").From(ScriptTestingHarness.TheResultsBar)); - var testsPassed = PassMatcher.IsMatch(classAttribute); - - return new ScriptTestResult(script, testsPassed); - } - - public TestTheStoredScript(IProvidesScript script) - { - if(script == null) - throw new ArgumentNullException(nameof(script)); - - this.script = script; - } - - public static IQuestion OfType(Type scriptType) - => new TestTheStoredScript(GetTheScript(scriptType)); - - static IProvidesScript GetTheScript(Type theScriptType) - => (IProvidesScript) Activator.CreateInstance(theScriptType); - } -} diff --git a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/VerifyThatAllOfTheScriptTestsPassed.cs b/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/VerifyThatAllOfTheScriptTestsPassed.cs deleted file mode 100644 index 147ba33f..00000000 --- a/Old/CSF.Screenplay.Selenium.Tests_old/Tasks/VerifyThatAllOfTheScriptTestsPassed.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// VerifyThatAllOfTheScriptTestsPassed.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using System.Collections.Generic; -using System.Linq; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using NUnit.Framework; - -namespace CSF.Screenplay.Selenium.Tests.Tasks -{ - public class VerifyThatAllOfTheScriptTestsPassed : Performable - { - readonly IReadOnlyCollection results; - - protected override string GetReport(INamed actor) - => $"{actor.Name} verifies that all of the script tests were successful"; - - protected override void PerformAs(IPerformer actor) - { - var failures = results.Where(x => !x.Success).ToArray(); - - Assert.That(failures, - Has.Length.Zero, - "The following scripts failed testing:{0} {1}", - Environment.NewLine, - String.Join($"{Environment.NewLine} ", failures.Select(x => x.Script.Name).ToArray())); - } - - public VerifyThatAllOfTheScriptTestsPassed(IReadOnlyCollection results) - { - if(results == null) - throw new ArgumentNullException(nameof(results)); - - this.results = results; - } - - public static IPerformable ForTheResults(IReadOnlyCollection results) - => new VerifyThatAllOfTheScriptTestsPassed(results); - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/Clear.cs b/Old/CSF.Screenplay.Selenium_old/Builders/Clear.cs deleted file mode 100644 index e4c21eec..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/Clear.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Actions; -using CSF.Screenplay.Selenium.Models; -using CSF.Screenplay.Selenium.Tasks; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Builds an action which clears contents from editable areas of the page. - /// - public class Clear - { - /// - /// Clears the contents of a user-editable HTML element, such as an input element. - /// - /// A performable action. - /// The target from which to clear the value. - public static IPerformable TheContentsOf(ITarget target) - => new TargettedAction(target, new ClearTheContents()); - - /// - /// Clears the contents of an HTML <input type="date"> element. - /// - /// A performable action. - /// The target from which to clear the date. - public static IPerformable TheDateFrom(ITarget target) - => new ClearTheDate(target); - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/Enter.cs b/Old/CSF.Screenplay.Selenium_old/Builders/Enter.cs deleted file mode 100644 index 3b1f5d4c..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/Enter.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Builds an action representing an actor entering text into a page element. - /// - public class Enter - { - readonly string val; - readonly DateTime? date; - - /// - /// The actor enters the text into a given . - /// - /// A performable action instance. - /// Target. - public IPerformable Into(ITarget target) - { - if(date.HasValue) - return new Tasks.EnterTheDate(date.Value, target); - - return new Actions.TargettedAction(target, new Actions.Enter(val)); - } - - /// - /// Indicates the text that the actor is to enter. - /// - /// A builder instance accepting further configuration. - /// The text to be entered. - public static Enter TheText(string val) - { - return new Enter(val); - } - - /// - /// Indicates a date that the actor is to enter. - /// - /// A builder instance accepting further configuration. - /// The date to be entered. - public static Enter TheDate(DateTime date) - { - return new Enter(date); - } - - Enter(string val) - { - if(val == null) - throw new ArgumentNullException(nameof(val)); - - this.val = val; - } - - Enter(DateTime date) - { - this.date = date; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/GetALocalisedDateScriptExtensions.cs b/Old/CSF.Screenplay.Selenium_old/Builders/GetALocalisedDateScriptExtensions.cs deleted file mode 100644 index 33236362..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/GetALocalisedDateScriptExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// StoredScriptBuilderExtensions.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Actions; -using CSF.Screenplay.Selenium.ScriptResources; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Extension methods for a , related to building performables which use the - /// JavaScript. - /// - public static class GetALocalisedDateScriptExtensions - { - /// - /// Gets a performable which represents an invocation of the JavaScript, using the - /// given parameters. - /// - /// The JavaScript question performable. - /// Builder. - /// The date. - public static IPerformableJavaScriptWithResult WhichGetsALocaleFormattedVersionOf(this ExecuteJavaScriptBuilder builder, - DateTime date) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - - int - year = date.Year, - // Months in JavaScript start with zero, because reasons - month = date.Month - 1, - day = date.Day; - - return builder.AsPerformableBuilder.BuildQuestion(year, month, day); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/GetDocumentReadyStateExtensions.cs b/Old/CSF.Screenplay.Selenium_old/Builders/GetDocumentReadyStateExtensions.cs deleted file mode 100644 index 40c925f1..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/GetDocumentReadyStateExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// GetDocumentReadyStateExtensions.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Actions; -using CSF.Screenplay.Selenium.ScriptResources; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Extension methods for a , related to building performables which use the - /// JavaScript. - /// - public static class GetDocumentReadyStateExtensions - { - /// - /// Gets a performable which represents an invocation of the JavaScript. - /// - /// The JavaScript question performable. - /// Builder. - public static IPerformableJavaScriptWithResult WhichGetsTheDocumentReadyState(this ExecuteJavaScriptBuilder builder) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - - return builder.AsPerformableBuilder.BuildQuestion(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/SetAnElementAttributeExtensions.cs b/Old/CSF.Screenplay.Selenium_old/Builders/SetAnElementAttributeExtensions.cs deleted file mode 100644 index a0fc5011..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/SetAnElementAttributeExtensions.cs +++ /dev/null @@ -1,160 +0,0 @@ -// -// SetAnElementAttributeExtensions.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Actions; -using CSF.Screenplay.Selenium.Models; -using CSF.Screenplay.Selenium.ScriptResources; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Extension methods for a , related to building performables which use the - /// JavaScript. - /// - public static class SetAnElementAttributeExtensions - { - /// - /// Gets a performable which represents an invocation of the JavaScript to - /// remove a given attribute from an element. - /// - /// The JavaScript question performable. - /// Builder. - /// The attribute name. - public static RemoveAttributeBuilder WhichRemovesTheAttribute(this ExecuteJavaScriptBuilder builder, - string name) - { - return new RemoveAttributeBuilder(builder, name); - } - - /// - /// Gets a performable which represents an invocation of the JavaScript to - /// set a given attribute upon an element to a new value. - /// - /// The JavaScript question performable. - /// Builder. - /// The attribute name. - public static ChooseElementBuilder WhichSetsTheAttribute(this ExecuteJavaScriptBuilder builder, - string name) - { - return new ChooseElementBuilder(builder, name); - } - - /// - /// Builder for an action which removes an attribute. - /// - public class RemoveAttributeBuilder - { - readonly string attributeName; - readonly ExecuteJavaScriptBuilder builder; - - /// - /// Choose the element from which to remove the attribute. - /// - /// Element. - public IPerformableJavaScript From(IWebElementAdapter element) - { - return builder.AsPerformableBuilder.BuildAction(element.GetUnderlyingElement(), - attributeName, - null); - } - - internal RemoveAttributeBuilder(ExecuteJavaScriptBuilder builder, string attributeName) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - if(attributeName == null) - throw new ArgumentNullException(nameof(attributeName)); - - this.builder = builder; - this.attributeName = attributeName; - } - } - - /// - /// Builder for an action which alters an attribute value. - /// - public class ChooseElementBuilder - { - readonly string attributeName; - readonly ExecuteJavaScriptBuilder builder; - - /// - /// Choose the element for which to set the attribute. - /// - /// Element. - public ChooseNewValueBuilder For(IWebElementAdapter element) - { - return new ChooseNewValueBuilder(builder, attributeName, element); - } - - internal ChooseElementBuilder(ExecuteJavaScriptBuilder builder, string attributeName) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - if(attributeName == null) - throw new ArgumentNullException(nameof(attributeName)); - - this.builder = builder; - this.attributeName = attributeName; - } - } - - /// - /// Builder for an action which alters an attribute value. - /// - public class ChooseNewValueBuilder - { - readonly string attributeName; - readonly ExecuteJavaScriptBuilder builder; - readonly IWebElementAdapter element; - - /// - /// Choose the new value for the attribute. - /// - /// New value. - public IPerformableJavaScript To(string newValue) - { - return builder.AsPerformableBuilder.BuildAction(element.GetUnderlyingElement(), - attributeName, - newValue); - } - - internal ChooseNewValueBuilder(ExecuteJavaScriptBuilder builder, string attributeName, IWebElementAdapter element) - { - if(element == null) - throw new ArgumentNullException(nameof(element)); - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - if(attributeName == null) - throw new ArgumentNullException(nameof(attributeName)); - - this.builder = builder; - this.attributeName = attributeName; - this.element = element; - } - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/SetAnElementValueExtensions.cs b/Old/CSF.Screenplay.Selenium_old/Builders/SetAnElementValueExtensions.cs deleted file mode 100644 index 92b3912c..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/SetAnElementValueExtensions.cs +++ /dev/null @@ -1,87 +0,0 @@ -// -// SetAnElementValueExtensions.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Actions; -using CSF.Screenplay.Selenium.Models; -using CSF.Screenplay.Selenium.ScriptResources; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Extension methods for a , related to building performables which use the - /// JavaScript. - /// - public static class SetAnElementValueExtensions - { - /// - /// Gets a builder which assists in the creation of the performable. In this method call, the target of the - /// value-setting operation is decided. - /// - /// The set-element-value builder. - /// Builder. - /// The target element, which is to have its value set. - public static SetAnElementValueBuilder WhichSetsTheValueOf(this ExecuteJavaScriptBuilder builder, - IWebElementAdapter element) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - if(element == null) - throw new ArgumentNullException(nameof(element)); - - return new SetAnElementValueBuilder(builder, element); - } - - /// - /// A builder type which creates a performable which uses the JavaScript. - /// - public class SetAnElementValueBuilder - { - readonly IWebElementAdapter element; - readonly ExecuteJavaScriptBuilder builder; - - /// - /// Gets the performable action from the new value to set into the element's 'value' property. - /// - /// The new value. - public IPerformableJavaScript To(object value) - { - var webElement = element.GetUnderlyingElement(); - return builder.AsPerformableBuilder.BuildAction(webElement, value); - } - - internal SetAnElementValueBuilder(ExecuteJavaScriptBuilder builder, IWebElementAdapter element) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - if(element == null) - throw new ArgumentNullException(nameof(element)); - - this.builder = builder; - this.element = element; - } - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Builders/UpdateSelectElementSelectionExtensions.cs b/Old/CSF.Screenplay.Selenium_old/Builders/UpdateSelectElementSelectionExtensions.cs deleted file mode 100644 index 1628ba13..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Builders/UpdateSelectElementSelectionExtensions.cs +++ /dev/null @@ -1,138 +0,0 @@ -// -// UpdateSelectElementSelectionExtensions.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Selenium.Actions; -using CSF.Screenplay.Selenium.Models; -using CSF.Screenplay.Selenium.ScriptResources; -using static CSF.Screenplay.Selenium.ScriptResources.UpdateSelectElementSelection; - -namespace CSF.Screenplay.Selenium.Builders -{ - /// - /// Extension methods for a , related to building performables which use the - /// JavaScript. - /// - public static class UpdateSelectElementSelectionExtensions - { - /// - /// Creates a builder for selecting a single option within an HTML <select> element. - /// - /// The builder. - /// A JavaScript execution builder. - /// Element. - public static OptionChoiceBuilder WhichSelectsTheOptionFrom(this ExecuteJavaScriptBuilder builder, - IWebElementAdapter element) - { - return new OptionChoiceBuilder(builder, element, true); - } - - /// - /// Creates a builder for deselecting a single option within an HTML <select> element. - /// - /// The builder. - /// A JavaScript execution builder. - /// Element. - public static OptionChoiceBuilder WhichDeselectsTheOptionFrom(this ExecuteJavaScriptBuilder builder, - IWebElementAdapter element) - { - return new OptionChoiceBuilder(builder, element, false); - } - - /// - /// Creates a performable action for deselecting every option from an HTML <select> element. - /// - /// The builder. - /// A JavaScript execution builder. - /// Element. - public static IPerformableJavaScript WhichDeselectsEverythingFrom(this ExecuteJavaScriptBuilder builder, - IWebElementAdapter element) - { - var jsBuilder = builder.AsPerformableBuilder; - return jsBuilder.BuildAction(element.GetUnderlyingElement(), DeselectAllActionName); - } - - /// - /// A builder type for choosing a single option element. - /// - public class OptionChoiceBuilder - { - readonly IWebElementAdapter element; - readonly bool select; - readonly ExecuteJavaScriptBuilder builder; - - /// - /// Chooses an option by its zero-based index and returns a performable JavaScript object - /// - /// A performable JavaScript. - /// Index. - public IPerformableJavaScript ByIndex(int index) - { - var actionName = select? SelectByIndexActionName : DeselectByIndexActionName; - return BuildAction(actionName, index); - } - - /// - /// Chooses an option by its underlying value and returns a performable JavaScript object - /// - /// A performable JavaScript. - /// Value. - public IPerformableJavaScript ByValue(string value) - { - var actionName = select? SelectByValueActionName : DeselectByValueActionName; - return BuildAction(actionName, value); - } - - /// - /// Chooses an option by its displayed text and returns a performable JavaScript object - /// - /// A performable JavaScript. - /// Text. - public IPerformableJavaScript ByText(string text) - { - var actionName = select? SelectByTextActionName : DeselectByTextActionName; - return BuildAction(actionName, text); - } - - IPerformableJavaScript BuildAction(string actionName, object actionValue) - { - var jsBuilder = builder.AsPerformableBuilder; - return jsBuilder.BuildAction(element.GetUnderlyingElement(), actionName, actionValue); - } - - internal OptionChoiceBuilder(ExecuteJavaScriptBuilder builder, IWebElementAdapter element, bool select) - { - if(builder == null) - throw new ArgumentNullException(nameof(builder)); - if(element == null) - throw new ArgumentNullException(nameof(element)); - - this.builder = builder; - this.element = element; - this.select = select; - } - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/CHANGELOG b/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/CHANGELOG deleted file mode 100644 index 3f5d60b0..00000000 --- a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/CHANGELOG +++ /dev/null @@ -1,8 +0,0 @@ -The file SelectElement.cs is copied directly from the Selenium support -repository as of tag v3.4.0. Minor changes have been made in order to make -it easier to subclass. - -The original file may be found (as it appeared at the time of -copying) in its repository at: - - https://github.com/SeleniumHQ/selenium/blob/selenium-3.4.0/dotnet/src/support/UI/SelectElement.cs \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/NOTICE b/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/NOTICE deleted file mode 100644 index ea6a613d..00000000 --- a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -This notice file applies ONLY to files within the namespace CSF.Selenium.Support.UI - -Some portions copyright 2018 CSF Software Limited -Copyright 2011-2016 Software Freedom Conservancy -Copyright 2004-2011 Selenium committers \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/SelectElement.cs b/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/SelectElement.cs deleted file mode 100644 index 43d1de17..00000000 --- a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/SelectElement.cs +++ /dev/null @@ -1,501 +0,0 @@ -// -// SelectElement.cs -// -// Author: -// Various Selenium authors -// Screenplay modifications: Craig Fowler -// -// This file began its life as a copy of the following: -// https://github.com/SeleniumHQ/selenium/blob/selenium-3.4.0/dotnet/src/support/UI/SelectElement.cs -// -// The original file is copyright 2011-2016 [various authors]. -// Further modifications are copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using OpenQA.Selenium; -using OpenQA.Selenium.Internal; -using OpenQA.Selenium.Support.UI; - -namespace CSF.Selenium.Support.UI -{ - /// - /// Provides a convenience method for manipulating selections of options in an HTML select element. - /// - public class SelectElement : IWrapsElement - { - #region fields - - readonly IWebElement element; - - #endregion - - #region properties - - /// - /// Gets the wrapped by this object. - /// - public IWebElement WrappedElement - { - get { return this.element; } - } - - /// - /// Gets a value indicating whether the parent element supports multiple selections. - /// - public bool IsMultiple { get; private set; } - - /// - /// Gets the list of options for the select element. - /// - public IList Options - { - get - { - return this.element.FindElements(By.TagName("option")); - } - } - - /// - /// Gets the selected item within the select element. - /// - /// If more than one item is selected this will return the first item. - /// Thrown if no option is selected. - public IWebElement SelectedOption - { - get - { - foreach (IWebElement option in this.Options) - { - if (option.Selected) - { - return option; - } - } - - throw new NoSuchElementException("No option is selected"); - } - } - - /// - /// Gets all of the selected options within the select element. - /// - public IList AllSelectedOptions - { - get - { - List returnValue = new List(); - foreach (IWebElement option in this.Options) - { - if (option.Selected) - { - returnValue.Add(option); - } - } - - return returnValue; - } - } - - #endregion - - #region methods - - /// - /// Select all options by the text displayed. - /// - /// The text of the option to be selected. If an exact match is not found, - /// this method will perform a substring match. - /// When given "Bar" this method would select an option like: - /// - /// <option value="foo">Bar</option> - /// - /// - /// Thrown if there is no element with the given text present. - public void SelectByText(string text) - { - if (text == null) - { - throw new ArgumentNullException("text", "text must not be null"); - } - - // try to find the option via XPATH ... - IList options = this.element.FindElements(By.XPath(".//option[normalize-space(.) = " + EscapeQuotes(text) + "]")); - - bool matched = false; - foreach (IWebElement option in options) - { - SetSelected(option, true); - if (!this.IsMultiple) - { - return; - } - - matched = true; - } - - if (options.Count == 0 && text.Contains(" ")) - { - string substringWithoutSpace = GetLongestSubstringWithoutSpace(text); - IList candidates; - if (string.IsNullOrEmpty(substringWithoutSpace)) - { - // hmm, text is either empty or contains only spaces - get all options ... - candidates = this.element.FindElements(By.TagName("option")); - } - else - { - // get candidates via XPATH ... - candidates = this.element.FindElements(By.XPath(".//option[contains(., " + EscapeQuotes(substringWithoutSpace) + ")]")); - } - - foreach (IWebElement option in candidates) - { - if (text == option.Text) - { - SetSelected(option, true); - if (!this.IsMultiple) - { - return; - } - - matched = true; - } - } - } - - if (!matched) - { - throw new NoSuchElementException("Cannot locate element with text: " + text); - } - } - - /// - /// Select an option by the value. - /// - /// The value of the option to be selected. - /// When given "foo" this method will select an option like: - /// - /// <option value="foo">Bar</option> - /// - /// - /// Thrown when no element with the specified value is found. - public void SelectByValue(string value) - { - StringBuilder builder = new StringBuilder(".//option[@value = "); - builder.Append(EscapeQuotes(value)); - builder.Append("]"); - IList options = this.element.FindElements(By.XPath(builder.ToString())); - - bool matched = false; - foreach (IWebElement option in options) - { - SetSelected(option, true); - if (!this.IsMultiple) - { - return; - } - - matched = true; - } - - if (!matched) - { - throw new NoSuchElementException("Cannot locate option with value: " + value); - } - } - - /// - /// Select the option by the index, as determined by the "index" attribute of the element. - /// - /// The value of the index attribute of the option to be selected. - /// Thrown when no element exists with the specified index attribute. - public void SelectByIndex(int index) - { - string match = index.ToString(CultureInfo.InvariantCulture); - - foreach (IWebElement option in this.Options) - { - if (option.GetAttribute("index") == match) - { - SetSelected(option, true); - return; - } - } - - throw new NoSuchElementException("Cannot locate option with index: " + index); - } - - /// - /// Clear all selected entries. This is only valid when the SELECT supports multiple selections. - /// - /// Thrown when attempting to deselect all options from a SELECT - /// that does not support multiple selections. - public void DeselectAll() - { - if (!this.IsMultiple) - { - throw new InvalidOperationException("You may only deselect all options if multi-select is supported"); - } - - foreach (IWebElement option in this.Options) - { - SetSelected(option, false); - } - } - - /// - /// Deselect the option by the text displayed. - /// - /// Thrown when attempting to deselect option from a SELECT - /// that does not support multiple selections. - /// Thrown when no element exists with the specified test attribute. - /// The text of the option to be deselected. - /// When given "Bar" this method would deselect an option like: - /// - /// <option value="foo">Bar</option> - /// - /// - public void DeselectByText(string text) - { - if (!this.IsMultiple) - { - throw new InvalidOperationException("You may only deselect option if multi-select is supported"); - } - - bool matched = false; - StringBuilder builder = new StringBuilder(".//option[normalize-space(.) = "); - builder.Append(EscapeQuotes(text)); - builder.Append("]"); - IList options = this.element.FindElements(By.XPath(builder.ToString())); - foreach (IWebElement option in options) - { - SetSelected(option, false); - matched = true; - } - - if (!matched) - { - throw new NoSuchElementException("Cannot locate option with text: " + text); - } - } - - /// - /// Deselect the option having value matching the specified text. - /// - /// Thrown when attempting to deselect option from a SELECT - /// that does not support multiple selections. - /// Thrown when no element exists with the specified value attribute. - /// The value of the option to deselect. - /// When given "foo" this method will deselect an option like: - /// - /// <option value="foo">Bar</option> - /// - /// - public void DeselectByValue(string value) - { - if (!this.IsMultiple) - { - throw new InvalidOperationException("You may only deselect option if multi-select is supported"); - } - - bool matched = false; - StringBuilder builder = new StringBuilder(".//option[@value = "); - builder.Append(EscapeQuotes(value)); - builder.Append("]"); - IList options = this.element.FindElements(By.XPath(builder.ToString())); - foreach (IWebElement option in options) - { - SetSelected(option, false); - matched = true; - } - - if (!matched) - { - throw new NoSuchElementException("Cannot locate option with value: " + value); - } - } - - /// - /// Deselect the option by the index, as determined by the "index" attribute of the element. - /// - /// Thrown when attempting to deselect option from a SELECT - /// that does not support multiple selections. - /// Thrown when no element exists with the specified index attribute. - /// The value of the index attribute of the option to deselect. - public void DeselectByIndex(int index) - { - if (!this.IsMultiple) - { - throw new InvalidOperationException("You may only deselect option if multi-select is supported"); - } - - string match = index.ToString(CultureInfo.InvariantCulture); - foreach (IWebElement option in this.Options) - { - if (match == option.GetAttribute("index")) - { - SetSelected(option, false); - return; - } - } - - throw new NoSuchElementException("Cannot locate option with index: " + index); - } - - /// - /// Sets the selected state of the given option. - /// - /// The option element for which to set selection state. - /// If set to true then the state will be set to 'selected'; if false then deselected. - protected virtual void SetSelected(IWebElement option, bool select) - { - if(option == null) - throw new ArgumentNullException(nameof(option)); - - bool isSelected = option.Selected; - if ((!isSelected && select) || (isSelected && !select)) - { - ToggleSelectedState(option); - } - } - - /// - /// Toggles the selected/deselected state of the given option element. - /// - /// The option element for which to toggle the selection state. - protected virtual void ToggleSelectedState(IWebElement option) - { - if(option == null) - throw new ArgumentNullException(nameof(option)); - - option.Click(); - } - - #endregion - - #region constructor - - /// - /// Initializes a new instance of the class. - /// - /// The element to be wrapped - /// Thrown when the object is - /// Thrown when the element wrapped is not a <select> element. - public SelectElement(IWebElement element) - { - if (element == null) - { - throw new ArgumentNullException("element", "element cannot be null"); - } - - if (string.IsNullOrEmpty(element.TagName) || string.Compare(element.TagName, "select", StringComparison.OrdinalIgnoreCase) != 0) - { - throw new UnexpectedTagNameException("select", element.TagName); - } - - this.element = element; - - // let check if it's a multiple - string attribute = element.GetAttribute("multiple"); - this.IsMultiple = attribute != null && attribute.ToLowerInvariant() != "false"; - } - - #endregion - - #region static methods - - static string EscapeQuotes(string toEscape) - { - // Convert strings with both quotes and ticks into: foo'"bar -> concat("foo'", '"', "bar") - if (toEscape.IndexOf("\"", StringComparison.OrdinalIgnoreCase) > -1 && toEscape.IndexOf("'", StringComparison.OrdinalIgnoreCase) > -1) - { - bool quoteIsLast = false; - if (toEscape.LastIndexOf("\"", StringComparison.OrdinalIgnoreCase) == toEscape.Length - 1) - { - quoteIsLast = true; - } - - List substrings = new List(toEscape.Split('\"')); - if (quoteIsLast && string.IsNullOrEmpty(substrings[substrings.Count - 1])) - { - // If the last character is a quote ('"'), we end up with an empty entry - // at the end of the list, which is unnecessary. We don't want to split - // ignoring *all* empty entries, since that might mask legitimate empty - // strings. Instead, just remove the empty ending entry. - substrings.RemoveAt(substrings.Count - 1); - } - - StringBuilder quoted = new StringBuilder("concat("); - for (int i = 0; i < substrings.Count; i++) - { - quoted.Append("\"").Append(substrings[i]).Append("\""); - if (i == substrings.Count - 1) - { - if (quoteIsLast) - { - quoted.Append(", '\"')"); - } - else - { - quoted.Append(")"); - } - } - else - { - quoted.Append(", '\"', "); - } - } - - return quoted.ToString(); - } - - // Escape string with just a quote into being single quoted: f"oo -> 'f"oo' - if (toEscape.IndexOf("\"", StringComparison.OrdinalIgnoreCase) > -1) - { - return string.Format(CultureInfo.InvariantCulture, "'{0}'", toEscape); - } - - // Otherwise return the quoted string - return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", toEscape); - } - - static string GetLongestSubstringWithoutSpace(string s) - { - string result = string.Empty; - string[] substrings = s.Split(' '); - foreach (string substring in substrings) - { - if (substring.Length > result.Length) - { - result = substring; - } - } - - return result; - } - - #endregion - - } -} \ No newline at end of file diff --git a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/SelectElementUsingModifierKey.cs b/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/SelectElementUsingModifierKey.cs deleted file mode 100644 index 244304e4..00000000 --- a/Old/CSF.Screenplay.Selenium_old/CSF.Selenium.Support.UI/SelectElementUsingModifierKey.cs +++ /dev/null @@ -1,87 +0,0 @@ -// -// SelectElementUsingModifierKey.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using OpenQA.Selenium; -using OpenQA.Selenium.Interactions; - -namespace CSF.Selenium.Support.UI -{ - /// - /// Specialisation of which makes use of a modifier key in order to - /// toggle the selection state of an option inside the select element when that select element - /// allows multiple options to be selected. - /// - /// - /// - /// Recent browsers are now requiring ctrl-click or command-click in order to toggle the selection - /// of a single option. This enables that behaviour. - /// - /// - /// It works around the issue described at: https://github.com/SeleniumHQ/selenium/issues/4490 - /// - /// - public class SelectElementUsingModifierKey : SelectElement - { - readonly string modifierKey; - readonly IWebDriver driver; - - /// - /// Toggles the selected/deselected state of the given option element. - /// - /// The option element for which to toggle the selection state. - protected override void ToggleSelectedState(IWebElement option) - { - if(!IsMultiple) - { - base.ToggleSelectedState(option); - return; - } - - new Actions(driver) - .KeyDown(modifierKey) - .Click(option) - .KeyUp(modifierKey) - .Perform(); - } - - /// - /// Initializes a new instance of the class. - /// - /// Element. - /// Modifier key. - /// Driver. - public SelectElementUsingModifierKey(IWebElement element, string modifierKey, IWebDriver driver) : base(element) - { - if(driver == null) - throw new ArgumentNullException(nameof(driver)); - if(modifierKey == null) - throw new ArgumentNullException(nameof(modifierKey)); - - this.driver = driver; - this.modifierKey = modifierKey; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/FlagsDefinitionProvider.cs b/Old/CSF.Screenplay.Selenium_old/FlagsDefinitionProvider.cs deleted file mode 100644 index 9514757b..00000000 --- a/Old/CSF.Screenplay.Selenium_old/FlagsDefinitionProvider.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using CSF.WebDriverExtras.Flags; - -namespace CSF.Screenplay.Selenium -{ - /// - /// Implementation of which provides flags definitions from two sources: - /// The definitions compiled into the CSF.Screenplay.Selenium.BrowserFlags assembly and also any - /// optionally definitions found in a collection of definitions file paths passed in the constructor. - /// - public class FlagsDefinitionProvider : IProvidesFlagsDefinitions - { - readonly IReadsFlagsDefinitions definitionReader; - readonly IReadOnlyCollection extraDefinitionFilePaths; - readonly Encoding fileEncoding; - - /// - /// Gets the flags definitions. - /// - /// The flags definitions. - public IReadOnlyCollection GetFlagsDefinitions() - { - var baseDefinitions = GetBrowserFlagsDefinitions.FromDefinitionsAssembly(); - var fileDefinitions = extraDefinitionFilePaths.SelectMany(x => ReadDefinitionsFromFile(x)); - - return baseDefinitions.Union(fileDefinitions).ToArray(); - } - - IReadOnlyCollection ReadDefinitionsFromFile(string filePath) - { - Stream stream = null; - - try - { - stream = File.OpenRead(filePath); - return ReadDefinitionsFromFileStream(stream, filePath); - } - // In any of these exception cases, where we can't open the file, drop the error to the console and skip the file - catch(PathTooLongException ex) { return GetBadDefinitionsFileResult(ex, filePath); } - catch(DirectoryNotFoundException ex) { return GetBadDefinitionsFileResult(ex, filePath); } - catch(UnauthorizedAccessException ex) { return GetBadDefinitionsFileResult(ex, filePath); } - catch(FileNotFoundException ex) { return GetBadDefinitionsFileResult(ex, filePath); } - catch(IOException ex) { return GetBadDefinitionsFileResult(ex, filePath); } - // And finally clean up the stream - finally - { - if(stream != null) - stream.Dispose(); - stream = null; - } - } - - IReadOnlyCollection ReadDefinitionsFromFileStream(Stream stream, string filePath) - { - try - { - return definitionReader.GetFlagsDefinitions(stream); - } - catch(Exception ex) - { - Console.Error.WriteLine("WARNING: Skipped browser flags definition file '{0}' because reading the file raised an exception:{1}{2}", - filePath, - Environment.NewLine, - ex); - - return new FlagsDefinition[0]; - } - } - - IReadOnlyCollection GetBadDefinitionsFileResult(Exception ex, string filePath) - { - Console.Error.WriteLine("WARNING: Skipped browser flags definition file '{0}' because opening the file raised an exception:{1}{2}", - filePath, - Environment.NewLine, - ex); - - return new FlagsDefinition[0]; - } - - /// - /// Initializes a new instance of the class. - /// - /// An optional collection of file paths, each of which contains one or more JSON flags definitions. - public FlagsDefinitionProvider(params string[] extraDefinitionFilePaths) - : this(Encoding.UTF8, extraDefinitionFilePaths) { } - - /// - /// Initializes a new instance of the class. - /// - /// The file encoding for externally-provided definitions files. - /// An optional collection of file paths, each of which contains one or more JSON flags definitions. - public FlagsDefinitionProvider(Encoding fileEncoding, params string[] extraDefinitionFilePaths) - { - if(fileEncoding == null) - throw new ArgumentNullException(nameof(fileEncoding)); - - this.fileEncoding = fileEncoding; - this.extraDefinitionFilePaths = extraDefinitionFilePaths ?? new string[0]; - this.definitionReader = new DefinitionReader(); - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Tasks/ClearTheDate.cs b/Old/CSF.Screenplay.Selenium_old/Tasks/ClearTheDate.cs deleted file mode 100644 index 93ce153d..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Tasks/ClearTheDate.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// ClearTheDateField.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Abilities; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tasks -{ - /// - /// A task which clears the value from an HTML <input type="date"> element. - /// - /// - /// - /// This is required because web browsers which have the flag - /// cannot use the 'normal' - /// mechanism to clear the value of a date field. This task abstracts around browsers that can or can't do - /// that and uses a JavaScript workaround to clear dates when the browser couldn't otherwise do it. - /// - /// - public class ClearTheDate : Performable - { - readonly ITarget target; - - /// - /// Gets the report of the current instance, for the given actor. - /// - /// The human-readable report text. - /// An actor for whom to write the report. - protected override string GetReport(INamed actor) => $"{actor.Name} clears the date from {target.GetName()}"; - - /// - /// Performs this operation, as the given actor. - /// - /// The actor performing this task. - protected override void PerformAs(IPerformer actor) - { - var browseTheWeb = actor.GetAbility(); - - if(browseTheWeb.FlagsDriver.HasFlag(Flags.HtmlElements.InputTypeDate.RequiresInputViaJavaScriptWorkaround)) - actor.Perform(ClearTheTargetUsingAJavaScriptWorkaround(browseTheWeb)); - else - actor.Perform(Clear.TheContentsOf(target)); - } - - IPerformable ClearTheTargetUsingAJavaScriptWorkaround(BrowseTheWeb browseTheWeb) - { - var webElement = target.GetWebElementAdapter(browseTheWeb); - return Execute.JavaScript.WhichSetsTheValueOf(webElement).To(String.Empty); - } - - /// - /// Initializes a new instance of the class. - /// - /// Target. - public ClearTheDate(ITarget target) - { - if(target == null) - throw new ArgumentNullException(nameof(target)); - - this.target = target; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDate.cs b/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDate.cs deleted file mode 100644 index 498d8cf9..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDate.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Abilities; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tasks -{ - /// - /// A task which enters a date value into an input element (of type "date") in a cross-browser manner. - /// - public class EnterTheDate : Performable - { - readonly DateTime date; - readonly ITarget target; - - /// - /// Gets the report of the current instance, for the given actor. - /// - /// The human-readable report text. - /// An actor for whom to write the report. - protected override string GetReport(INamed actor) - => $"{actor.Name} enters the date {date.ToString("yyyy-MM-dd")} into {target.GetName()}"; - - /// - /// Performs this operation, as the given actor. - /// - /// The actor performing this task. - protected override void PerformAs(IPerformer actor) - { - var browseTheWeb = actor.GetAbility(); - - if(browseTheWeb.FlagsDriver.HasFlag(Flags.HtmlElements.InputTypeDate.RequiresEntryUsingLocaleFormat)) - actor.Perform(EnterTheDateInLocaleFormat()); - else if(browseTheWeb.FlagsDriver.HasFlag(Flags.HtmlElements.InputTypeDate.RequiresInputViaJavaScriptWorkaround)) - actor.Perform(EnterTheDateViaAJavaScriptWorkaround()); - else - actor.Perform(EnterTheDateInIsoFormat()); - } - - IPerformable EnterTheDateInLocaleFormat() - => new EnterTheDateIntoAnHtml5InputTypeDate(date, target); - - IPerformable EnterTheDateInIsoFormat() - => new EnterTheDateAsAnIsoFormattedString(date, target); - - IPerformable EnterTheDateViaAJavaScriptWorkaround() - => new SetTheDateUsingAJavaScriptWorkaround(date, target); - - /// - /// Initializes a new instance of the class. - /// - /// Date. - /// Target. - public EnterTheDate(DateTime date, ITarget target) - { - if(target == null) - throw new ArgumentNullException(nameof(target)); - - this.date = date; - this.target = target; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDateAsAnIsoFormattedString.cs b/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDateAsAnIsoFormattedString.cs deleted file mode 100644 index b9efb63b..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDateAsAnIsoFormattedString.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tasks -{ - /// - /// A task which enters a date as a plain ISO-formatted yyyy-MM-dd string into a plain - /// text control. This may be used as a fallback for web browsers which do not fully support HTML 5 input - /// type="date" elements. - /// - public class EnterTheDateAsAnIsoFormattedString : Performable - { - readonly DateTime date; - readonly ITarget target; - - /// - /// Gets the report of the current instance, for the given actor. - /// - /// The human-readable report text. - /// An actor for whom to write the report. - protected override string GetReport(INamed actor) - => $"{actor.Name} enters the date {date.ToString("yyyy-MM-dd")} into {target.GetName()} as an ISO-formatted string"; - - /// - /// Performs this operation, as the given actor. - /// - /// The actor performing this task. - protected override void PerformAs(IPerformer actor) - { - actor.Perform(Clear.TheContentsOf(target)); - actor.Perform(Enter.TheText(date.ToString("yyyy-MM-dd")).Into(target)); - } - - /// - /// Initializes a new instance of the class. - /// - /// Date. - /// Target. - public EnterTheDateAsAnIsoFormattedString(DateTime date, ITarget target) - { - if(target == null) - throw new ArgumentNullException(nameof(target)); - - this.date = date; - this.target = target; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDateIntoAnHtml5InputTypeDate.cs b/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDateIntoAnHtml5InputTypeDate.cs deleted file mode 100644 index 743a4004..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Tasks/EnterTheDateIntoAnHtml5InputTypeDate.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tasks -{ - /// - /// A task which manages the inputting of a date value into an HTML 5 <input type="date" /> element - /// as a locale-formatted string. - /// - public class EnterTheDateIntoAnHtml5InputTypeDate : Performable - { - const string - Numbers = @"\d+", - NonNumericCharacters = @"\D"; - static readonly Regex - NumberMatcher = new Regex(Numbers, RegexOptions.Compiled), - NonNumericStripper = new Regex(NonNumericCharacters, RegexOptions.Compiled); - - readonly DateTime date; - readonly ITarget target; - - /// - /// Gets the report of the current instance, for the given actor. - /// - /// The human-readable report text. - /// An actor for whom to write the report. - protected override string GetReport(INamed actor) - => $"{actor.Name} enters the date {date.ToString("yyyy-MM-dd")} into {target.GetName()} using the current locale's format"; - - /// - /// Performs this operation, as the given actor. - /// - /// The actor performing this task. - protected override void PerformAs(IPerformer actor) - { - var localeFormattedDate = actor.Perform(GetTheLocaleFormattedDate()); - var keysToPress = GetTheKeysToPress(localeFormattedDate); - actor.Perform(Enter.TheText(keysToPress).Into(target)); - } - - IQuestion GetTheLocaleFormattedDate() - => new GetTheLocaleFormattedDate(date); - - string GetTheKeysToPress(string formattedDate) - { - var zeroPaddedFormattedDate = GetZeroPaddedFormattedDate(formattedDate); - return NonNumericStripper.Replace(zeroPaddedFormattedDate, String.Empty); - } - - string GetZeroPaddedFormattedDate(string formattedDate) - { - return NumberMatcher.Replace(formattedDate, match => { - if(match.Length > 1) - return match.Value; - - return String.Concat("0", match.Value); - }); - } - - /// - /// Initializes a new instance of the class. - /// - /// Date. - /// Target. - public EnterTheDateIntoAnHtml5InputTypeDate(DateTime date, ITarget target) - { - if(target == null) - throw new ArgumentNullException(nameof(target)); - - this.date = date; - this.target = target; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Tasks/GetTheLocaleFormattedDate.cs b/Old/CSF.Screenplay.Selenium_old/Tasks/GetTheLocaleFormattedDate.cs deleted file mode 100644 index c4922da6..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Tasks/GetTheLocaleFormattedDate.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using CSF.Screenplay.Actors; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.ScriptResources; - -namespace CSF.Screenplay.Selenium.Tasks -{ - /// - /// A task which gets the representation of a System.DateTime in a format compatible with the web browser's - /// current localisation. - /// - public class GetTheLocaleFormattedDate : Question - { - readonly DateTime date; - - /// - /// Gets the report of the current instance, for the given actor. - /// - /// The human-readable report text. - /// An actor for whom to write the report. - protected override string GetReport(INamed actor) - => $"{actor.Name} gets the locale-formatted representation of the date {date.ToString("yyyy-MM-dd")}"; - - /// - /// Performs this operation, as the given actor. - /// - /// The response or result. - /// The actor performing this task. - protected override string PerformAs(IPerformer actor) - { - return (string) actor.Perform(Execute.JavaScript.WhichGetsALocaleFormattedVersionOf(date)); - } - - /// - /// Initializes a new instance of the class. - /// - /// Date. - public GetTheLocaleFormattedDate(DateTime date) - { - this.date = date; - } - } -} diff --git a/Old/CSF.Screenplay.Selenium_old/Tasks/SetTheDateUsingAJavaScriptWorkaround.cs b/Old/CSF.Screenplay.Selenium_old/Tasks/SetTheDateUsingAJavaScriptWorkaround.cs deleted file mode 100644 index 6ad92c20..00000000 --- a/Old/CSF.Screenplay.Selenium_old/Tasks/SetTheDateUsingAJavaScriptWorkaround.cs +++ /dev/null @@ -1,76 +0,0 @@ -// -// SetTheDateUsingAJavaScriptWorkaround.cs -// -// Author: -// Craig Fowler -// -// Copyright (c) 2018 Craig Fowler -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using CSF.Screenplay.Performables; -using CSF.Screenplay.Selenium.Abilities; -using CSF.Screenplay.Selenium.Builders; -using CSF.Screenplay.Selenium.Models; - -namespace CSF.Screenplay.Selenium.Tasks -{ - /// - /// Sets the value of an HTML <input type="date"> element, using a JavaScript workaround. - /// - public class SetTheDateUsingAJavaScriptWorkaround : Performable - { - readonly DateTime date; - readonly ITarget target; - - /// - /// Gets the report of the current instance, for the given actor. - /// - /// The human-readable report text. - /// An actor for whom to write the report. - protected override string GetReport(Actors.INamed actor) - => $"{actor.Name} enters the date {date.ToString("yyyy-MM-dd")} into {target.GetName()} using a JavaScript workaround"; - - /// - /// Performs this operation, as the given actor. - /// - /// The actor performing this task. - protected override void PerformAs(Actors.IPerformer actor) - { - var browseTheWeb = actor.GetAbility(); - var webElement = target.GetWebElementAdapter(browseTheWeb); - - actor.Perform(Execute.JavaScript.WhichSetsTheValueOf(webElement).To(date.ToString("yyyy-MM-dd"))); - } - - /// - /// Initializes a new instance of the class. - /// - /// Date. - /// Target. - public SetTheDateUsingAJavaScriptWorkaround(DateTime date, ITarget target) - { - if(target == null) - throw new ArgumentNullException(nameof(target)); - - this.date = date; - this.target = target; - } - } -} diff --git a/Old/README.md b/Old/README.md deleted file mode 100644 index f21b3673..00000000 --- a/Old/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Old content - -This old content is kept just as reference, for a few features which are not yet migrated to v2.0.0. -Before v2.0.0 is released, this whole directory should be deleted. diff --git a/Tests/CSF.Screenplay.Selenium.Tests/Actions/ClickTests.cs b/Tests/CSF.Screenplay.Selenium.Tests/Actions/ClickTests.cs index 973e32a1..c00fd9d8 100644 --- a/Tests/CSF.Screenplay.Selenium.Tests/Actions/ClickTests.cs +++ b/Tests/CSF.Screenplay.Selenium.Tests/Actions/ClickTests.cs @@ -1,4 +1,5 @@ +using CSF.Screenplay.Performables; using CSF.Screenplay.Selenium.Elements; using static CSF.Screenplay.PerformanceStarter; using static CSF.Screenplay.Selenium.PerformableBuilder; @@ -10,6 +11,7 @@ public class ClickTests { static readonly ITarget clickableButton = new ElementId("clickable", "the clickable button"), + nonExistent = new ElementId("nope", "the non-existent element"), displayText = new ElementId("display", "the displayable text"); static readonly NamedUri testPage = new NamedUri("ClickTests.html", "the test page"); @@ -25,4 +27,31 @@ public async Task ClickingAButtonShouldTriggerAnEvent(IStage stage) Assert.That(contents, Is.EqualTo("Clicked!")); } + + [Test, Screenplay] + public async Task ClickingAnElementWhichDoesNotExistShouldThrow(IStage stage) + { + var webster = stage.Spotlight(); + + await Given(webster).WasAbleTo(OpenTheUrl(testPage)); + Assert.That(async () => await When(webster).AttemptsTo(ClickOn(nonExistent)), + Throws.InstanceOf().And.InnerException.InstanceOf()); + } + + [Test, Screenplay] + public async Task ClickingAnElementWhichDoesNotExistShouldIncludeTheCorrectTargetInTheException(IStage stage) + { + var webster = stage.Spotlight(); + + await Given(webster).WasAbleTo(OpenTheUrl(testPage)); + try + { + await When(webster).AttemptsTo(ClickOn(nonExistent)); + Assert.Fail("Should have thrown an exception!"); + } + catch(PerformableException e) when (e is { InnerException: TargetNotFoundException tnfEx }) + { + Assert.That(tnfEx.Target, Has.Property(nameof(ITarget.Name)).EqualTo("the non-existent element")); + } + } } \ No newline at end of file diff --git a/Tests/CSF.Screenplay.Selenium.Tests/Actions/OpenUrlTests.cs b/Tests/CSF.Screenplay.Selenium.Tests/Actions/OpenUrlTests.cs index b7e514b6..e3d65372 100644 --- a/Tests/CSF.Screenplay.Selenium.Tests/Actions/OpenUrlTests.cs +++ b/Tests/CSF.Screenplay.Selenium.Tests/Actions/OpenUrlTests.cs @@ -38,20 +38,20 @@ public async Task OpenTheUrlWithDifferentBasePathShouldYieldDifferentContent(ISt } [Test, AutoMoqData] - public async Task PerformAsAsyncShouldThrowIfTheUrlIsNotAbsolute(Actor actor, + public void PerformAsAsyncShouldThrowIfTheUrlIsNotAbsolute(Actor actor, [MockDriver] BrowseTheWeb ability) { actor.IsAbleTo(ability); var sut = new OpenUrl(new NamedUri("foo/bar/baz.html")); - Assert.That(() => sut.PerformAsAsync(actor), Throws.InstanceOf()); + Assert.That(async () => await sut.PerformAsAsync(actor), Throws.InstanceOf()); } [Test, AutoMoqData] - public async Task PerformAsAsyncShouldNotThrowIfTheUrlIsAbsolute(Actor actor, - [MockDriver] BrowseTheWeb ability) + public void PerformAsAsyncShouldNotThrowIfTheUrlIsAbsolute(Actor actor, + [MockDriver] BrowseTheWeb ability) { actor.IsAbleTo(ability); var sut = new OpenUrl(new NamedUri("https://example.com/foo/bar/baz.html")); - Assert.That(() => sut.PerformAsAsync(actor), Throws.Nothing); + Assert.That(async () => await sut.PerformAsAsync(actor), Throws.Nothing); } } \ No newline at end of file diff --git a/Tests/CSF.Screenplay.Selenium.Tests/Actions/SetTheElementValueTests.cs b/Tests/CSF.Screenplay.Selenium.Tests/Actions/SetTheElementValueTests.cs new file mode 100644 index 00000000..e8b076f3 --- /dev/null +++ b/Tests/CSF.Screenplay.Selenium.Tests/Actions/SetTheElementValueTests.cs @@ -0,0 +1,47 @@ +using CSF.Screenplay.Performables; +using CSF.Screenplay.Selenium.Elements; +using Moq; +using OpenQA.Selenium; +using static CSF.Screenplay.Selenium.PerformableBuilder; + +namespace CSF.Screenplay.Selenium.Actions; + +[TestFixture, Parallelizable] +public class SetTheElementValueTests +{ + [Test, AutoMoqData] + public async Task PerformAsAsyncShouldUseTheSimulatedInteractiveScriptIfApplicable([MockDriver] BrowseTheWeb browseTheWeb, + object value, + Actor actor, + ITarget target, + SeleniumElement element) + { + actor.IsAbleTo(browseTheWeb); + Mock.Get(target).Setup(x => x.GetElement(browseTheWeb.WebDriver)).Returns(element); + + var sut = SetTheValueOf(target).To(value).AsIfSetInteractively(); + await sut.PerformAsAsync(actor); + + Mock.Get(browseTheWeb.WebDriver) + .As() + .Verify(x => x.ExecuteScript(Scripts.SetElementValueSimulatedInteractively.ScriptBody, element.WebElement, value)); + } + + [Test, AutoMoqData] + public async Task PerformAsAsyncShouldUseTheNonInteractiveScriptInteractiveNotRequested([MockDriver] BrowseTheWeb browseTheWeb, + object value, + Actor actor, + ITarget target, + SeleniumElement element) + { + actor.IsAbleTo(browseTheWeb); + Mock.Get(target).Setup(x => x.GetElement(browseTheWeb.WebDriver)).Returns(element); + + var sut = ((IGetsPerformable) SetTheValueOf(target).To(value)).GetPerformable(); + await sut.PerformAsAsync(actor); + + Mock.Get(browseTheWeb.WebDriver) + .As() + .Verify(x => x.ExecuteScript(Scripts.SetElementValue.ScriptBody, element.WebElement, value)); + } +} \ No newline at end of file diff --git a/Tests/CSF.Screenplay.Selenium.Tests/MockDriverAttribute.cs b/Tests/CSF.Screenplay.Selenium.Tests/MockDriverAttribute.cs index dae743ba..20bcb1b9 100644 --- a/Tests/CSF.Screenplay.Selenium.Tests/MockDriverAttribute.cs +++ b/Tests/CSF.Screenplay.Selenium.Tests/MockDriverAttribute.cs @@ -3,6 +3,7 @@ using CSF.Extensions.WebDriver; using CSF.Extensions.WebDriver.Factories; using Moq; +using OpenQA.Selenium; namespace CSF.Screenplay.Selenium; @@ -16,6 +17,11 @@ public class MockDriverCustomization : ICustomization { public void Customize(IFixture fixture) { + fixture.Customize(c => + { + return c + .FromFactory(() => (IWebDriver) new Mock().As().Object); + }); fixture.Customize(c => c.FromFactory((WebDriverAndOptions d) => Mock.Of(m => m.GetDefaultWebDriver(null) == d && m.GetWebDriver(It.IsAny(), null) == d))); fixture.Customize(c => c.FromFactory((IGetsWebDriver d) => new BrowseTheWeb(d))); diff --git a/Tests/CSF.Screenplay.Selenium.Tests/ScreenplayFactory.cs b/Tests/CSF.Screenplay.Selenium.Tests/ScreenplayFactory.cs index 5fde4d84..24912094 100644 --- a/Tests/CSF.Screenplay.Selenium.Tests/ScreenplayFactory.cs +++ b/Tests/CSF.Screenplay.Selenium.Tests/ScreenplayFactory.cs @@ -12,15 +12,10 @@ public Screenplay GetScreenplay() var screenplay = Screenplay.Create(services => { services.AddSingleton(GetConfiguration()); - services.AddWebDriverFactory(); services.AddLogging(l => l.AddConsole(c => c.LogToStandardErrorThreshold = LogLevel.Warning)); - + services.AddSelenium(); services.AddTransient(); services.AddTransient(); - }, options => - { - options.ValueFormatters.Add(typeof(Reporting.OptionsFormatter)); - options.ValueFormatters.Add(typeof(Reporting.ScreenshotFormatter)); }); return screenplay; diff --git a/Tests/CSF.Screenplay.Selenium.Tests/Tasks/ClickAndWaitForDocumentReadyTests.cs b/Tests/CSF.Screenplay.Selenium.Tests/Tasks/ClickAndWaitForDocumentReadyTests.cs index f11f401f..7420f833 100644 --- a/Tests/CSF.Screenplay.Selenium.Tests/Tasks/ClickAndWaitForDocumentReadyTests.cs +++ b/Tests/CSF.Screenplay.Selenium.Tests/Tasks/ClickAndWaitForDocumentReadyTests.cs @@ -16,8 +16,6 @@ static readonly ITarget link = new ElementId("clickable"), displayText = new ElementId("textContent"); - static readonly string[] ignoredBrowsers = ["chrome", "MicrosoftEdge"]; - [Test, Screenplay] public async Task PerformAsAsyncShouldWaitSoItCanGetTheAppropriateContent(IStage stage) { @@ -36,7 +34,7 @@ public async Task PerformAsAsyncShouldThrowIfWeDontWaitLongEnough(IStage stage) var webster = stage.Spotlight(); var ability = webster.GetAbility(); - if(ignoredBrowsers.Contains(ability.DriverOptions.BrowserName)) + if(!ability.WebDriver.HasQuirk(BrowserQuirks.NeedsToWaitAfterPageLoad)) Assert.Pass("This test cannot meaningfully be run on a Chrome or Edge browser, because they always wait for the page load. Treating this test as an implicit pass."); await Given(webster).WasAbleTo(OpenTheUrl(startPage)); diff --git a/Tests/CSF.Screenplay.Selenium.Tests/Tasks/EnterTheDateTests.cs b/Tests/CSF.Screenplay.Selenium.Tests/Tasks/EnterTheDateTests.cs index 08cbb1fb..1be82a05 100644 --- a/Tests/CSF.Screenplay.Selenium.Tests/Tasks/EnterTheDateTests.cs +++ b/Tests/CSF.Screenplay.Selenium.Tests/Tasks/EnterTheDateTests.cs @@ -1,6 +1,8 @@ using System; using System.Globalization; +using System.Linq; using CSF.Screenplay.Selenium.Elements; +using OpenQA.Selenium; using static CSF.Screenplay.PerformanceStarter; using static CSF.Screenplay.Selenium.PerformableBuilder; @@ -47,6 +49,11 @@ public async Task EnteringADateInAnUnusualCultureShouldYieldIncorrectResults(ISt if(CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern.StartsWith("y", StringComparison.InvariantCultureIgnoreCase)) Assert.Inconclusive("This test can't be meaningfully run when the current culture uses Y/M/D date formatting"); + var ability = webster.GetAbility(); + + if(ability.WebDriver.HasQuirk(BrowserQuirks.CannotSetInputTypeDateWithSendKeys)) + Assert.Pass("This test cannot meaningfully be run on a browser which requires a JS workaround to set dates. Treating this test as an implicit pass."); + await Given(webster).WasAbleTo(OpenTheUrl(testPage)); await When(webster).AttemptsTo(EnterTheDate(new DateTime(2025, 11, 12)).Into(inputArea).ForTheCultureNamed("ja-JP")); var result = await Then(webster).Should(ReadFromTheElement(displayText).TheText()); diff --git a/Tests/CSF.Screenplay.Tests/CSF.Screenplay.Tests.csproj b/Tests/CSF.Screenplay.Tests/CSF.Screenplay.Tests.csproj index 09f16731..89c5a653 100644 --- a/Tests/CSF.Screenplay.Tests/CSF.Screenplay.Tests.csproj +++ b/Tests/CSF.Screenplay.Tests/CSF.Screenplay.Tests.csproj @@ -18,7 +18,7 @@ - + diff --git a/Tests/CSF.Screenplay.Tests/DefaultScreenplayCustomization.cs b/Tests/CSF.Screenplay.Tests/DefaultScreenplayCustomization.cs index 2e375640..e2e4cff4 100644 --- a/Tests/CSF.Screenplay.Tests/DefaultScreenplayCustomization.cs +++ b/Tests/CSF.Screenplay.Tests/DefaultScreenplayCustomization.cs @@ -1,4 +1,5 @@ using AutoFixture; +using Microsoft.Extensions.DependencyInjection; namespace CSF.Screenplay; @@ -6,6 +7,6 @@ public class DefaultScreenplayCustomization : ICustomization { public void Customize(IFixture fixture) { - fixture.Customize(c => c.FromFactory(() => Screenplay.Create(options: o => o.ReportPath = null))); + fixture.Customize(c => c.FromFactory(() => Screenplay.Create(s => s.Configure(o => o.ReportPath = null)))); } } \ No newline at end of file diff --git a/Tests/CSF.Screenplay.Tests/ScreenplayExtensionsTests.cs b/Tests/CSF.Screenplay.Tests/ScreenplayExtensionsTests.cs index c661674b..80c5a30c 100644 --- a/Tests/CSF.Screenplay.Tests/ScreenplayExtensionsTests.cs +++ b/Tests/CSF.Screenplay.Tests/ScreenplayExtensionsTests.cs @@ -65,7 +65,7 @@ public void ExecuteAsPerformanceShouldThrowIfTheTaskTakesTooLong([DefaultScreenp [Test,AutoMoqData] public void ExecuteAsPerformanceGenericShouldExecuteThePerformanceHostLogic() { - var sut = Screenplay.Create(s => s.AddSingleton(), o => o.ReportPath = null); + var sut = Screenplay.Create(s => s.AddSingleton().Configure(o => o.ReportPath = null)); sut.ExecuteAsPerformanceAsync();