Class BrowseTheWeb
- Namespace
- CSF.Screenplay.Selenium
- Assembly
- CSF.Screenplay.Selenium.dll
Screenplay ability which allows an Actor to browse the web using a Selenium WebDriver.
public class BrowseTheWeb : ICanReport, IDisposable
- Inheritance
-
BrowseTheWeb
- Implements
- Inherited Members
- Extension Methods
Examples
Imagine you have configuration like the following in your appsettings.json, following the
Microsoft Options Pattern, with
a configuration file.
{
"WebDriverFactory": {
"DriverConfigurations": {
"LocalChrome": { "DriverType": "ChromeDriver" },
"LocalFirefox": { "DriverType": "FirefoxDriver" },
},
}
}
You could now use the following technique when you configure your Actor with this ability. The following example shows how to do this using an IPersona.
In addition to the configuration above and the persona shown below, run this code whilst an environment variable
named WebDriverFactory__SelectedConfiguration is defined and set to LocalFirefox.
This environment variable selects which of the two configured WebDrivers is used (in this case, Firefox).
Developers may use the configuration to store a library of available WebDriver configurations, and use a single
environment variable to switch between them at execution time.
using CSF.Extensions.WebDriver;
using CSF.Screenplay.Selenium;
public class Webster(IGetsWebDriver webDriverFactory) : IPersona
{
public string Name => "Webster";
public Actor GetActor(Guid performanceIdentity)
{
var webster = new Actor(Name, performanceIdentity);
var browseTheWeb = new BrowseTheWeb(webDriverFactory);
webster.IsAbleTo(browseTheWeb);
return webster;
}
}
Remarks
The 'Browse the Web' ability wraps a Selenium WebDriver and provides access to it via the WebDriver property. It also provide access to the options which were used to create the web driver, via the DriverOptions property. Following Selenium's architecture, both of these properties are abstract/interfaces and offer only the base/lowest common denominator types. Often, this is sufficient. Developers may check for other Selenium-related interfaces if they are required, using patterns such as the following:
if(browseTheWeb.WebDriver is OpenQA.Selenium.ISupportsPrint printingDriver)
/* ... exercise printingDriver ... */
This ability makes use of the Universal Web Driver Factory from the CSF.Extensions.WebDriver package. This provides a configurable manner, using the .NET Options pattern, to specify the WebDriver without hard-coding the choice.
The Selenium Extension to Screenplay makes the IGetsWebDriver web driver factory available via dependency injection. The recommended way in which to grant an Actor this ability is via an IPersona. The web driver factory may be safely constructor-injected into the persona class.
Constructors
BrowseTheWeb(IGetsWebDriver, string, bool)
Initializes a new instance of the BrowseTheWeb class.
public BrowseTheWeb(IGetsWebDriver webDriverFactory, string webDriverName = null, bool collectLogs = false)
Parameters
webDriverFactoryIGetsWebDriverA universal WebDriver factory instance
webDriverNamestringAn optional name, specifying the WebDriver configuration (within those available in the factory) to use.
collectLogsboolAn optional value indicating whether the Screenplay Selenium extension should go to lengths to ensure that web browser console logs are available. See ShouldCollectLogs for more information.
Remarks
It is quite normal to omit the webDriverName parameter, leaving it with its default null value.
If the WebDriver name is omitted or null then the GetDefaultWebDriver(Action<DriverOptions>) method will
be used to get the WebDriver. This requires that the WebDriver factory is configured with a default driver. This could be done via
the SelectedConfiguration property of the JSON configuration, or via an environment variable (see the example code in the remarks
to this class) or any other way which the Microsoft
Configuration Pattern supports.
Alternatively, to activate a specific named configuration, you may specify the WebDriver name here.
It is normal to retrieve the webDriverFactory parameter via Dependency Injection. The Selenium Extension to
Screenplay makes the factory available in that manner.
Properties
DriverOptions
Gets the WebDriver options which were used to create WebDriver.
public DriverOptions DriverOptions { get; }
Property Value
Remarks
These options are for reference only; there is no effect on the WebDriver instance if you modify them. The purpose of this property is to allow developers to inspect the options which were used to create the WebDriver.
ShouldCollectLogs
Gets a value indicating whether the current WebDriver should go to lengths to collect console log information.
public bool ShouldCollectLogs { get; }
Property Value
Remarks
Different web driver implementations have varying levels of support for providing access to web browser's console logs. As of June 2026, the only implementations which provide native access are local implementations of Chromium-based web drivers, such as ChromeDriver and EdgeDriver. For other web browsers/drivers, as well as all remote web drivers, Selenium is unable to directly access their logs using a native API.
When this property is set to true, it triggers behaviour which causes Screenplay to attempt to access the browser's console logs more aggressively. Screenplay activates a JavaScript-based workaround when native log-collection is not viable. That JavaScript-based approach is coordinated from the Task BeginCollectingLogsWithJavaScriptIfApplicable and ultimately the Action BeginCollectingLogsWithJavaScript. This functionality is consumed by the logic of two Tasks:
In both cases, these tasks will execute the logic of BeginCollectingLogsWithJavaScriptIfApplicable. In determining whether the JavaScript approach is applicable, the task verifies that this setting is true, and whether the current web driver implementation requires the JavaScript workaround to get logs. That is - the WebDriver is not remote, and it does have the quirk CanGetLogsWithJavascriptWorkaround and it does not have the quirk HasNativeLogsSupport. If all these criteria are satisfied, then the action BeginCollectingLogsWithJavaScript is executed, to begin collecting logs in JavaScript.
It's important to understand that the JavaScript workaround for getting console logs is imperfect. Logs are only collected from the point at which the 'begin collection' script is sent to the web browser. Any logs which were written before that script arrives will be missed and will be unavailable for reading. This is why the collection begins immediately after two tasks which cause page reloads. Even so, imagine the loading of a new web page, and immediately as the page loads, there is an important console message written. It's quite possible that - in the brief (perhaps milliseconds) delay between the page load completing and the "Begin collecting logs" script arriving, that the important message was already written to the logs. In this circumstance the important message will not be available to Screenplay. Unfortunately there is no better solution or workaround to this problem when using Selenium.
WebDriver
Gets the Selenium WebDriver associated with the current ability instance.
public IWebDriver WebDriver { get; }
Property Value
Methods
Dispose()
public void Dispose()
Dispose(bool)
Disposes the resources used by the BrowseTheWeb class.
protected virtual void Dispose(bool disposing)
Parameters
disposingboolA boolean value indicating whether the method is called from the Dispose method.
GetReportFragment(Actor, IFormatsReportFragment)
Gets a fragment of a Screenplay report, specific to the execution (performables) or gaining (abilities) of the current instance, for the specified actor.
public ReportFragment GetReportFragment(Actor actor, IFormatsReportFragment formatter)
Parameters
actorActorAn actor for whom to write the report fragment
formatterIFormatsReportFragmentA report-formatting service
Returns
- ReportFragment
A human-readable report fragment.
Examples
For a performable which clicks a button (where the button itself has been constructor-injected into
the performable instance), then a suitable return value might be a formatted string such as
{Actor name} clicks {Button}, where the two placeholders indicated by braces: {} are
substituted with the actor's Name and a string representation of
the button.
For a performable which reads the temperature from a thermometer, a suitable return value might be a
string in the format {Actor name} reads the temperature.
For an ability which allows the actor to wash dishes then a suitable return value might be a string in the
format {Actor name} is able to wash the dishes.
Remarks
Implementers should return a string which indicates that the named actor is performing (present tense)
the performable, for types which also implement a performable interface. For types which represent
abilities, the implementer should return a string which indicates that the named actor is able to do
something. In particular for abilities, to make them easily recognisable in reports, it helps to stick
to the convention {Actor name} is able to {Ability summary}.
For performables which return a value (Questions, or Tasks which behave like Questions), there is no need to include the returned value within the report fragment. The framework will include the return value in the report and will format it via a different mechanism.
Good report fragments are concise. Be aware that report fragments for Tasks (which are composed from other performables) do not need to go into detail about what they do. Users reading Screenplay reports are able to drill-down into Tasks to see what they are composed from, so if the user is curious as to what the task does, it is easy to discover. It is also strongly recommended to avoid periods (full stops) at the end of a report fragment. Whilst report fragments tend to be complete sentences, punctuation like this is distracting and reports are seldom presented as paragraphs of prose.