|
| 1 | +# WebDriver quirks |
| 2 | + |
| 3 | +_There are a lot of web browsers and browser versions out there!_ |
| 4 | +Unfortunately they do not all behave in a perfectly uniform manner; some WebDriver implementations have bugs and some just have oddities which are unique to them. |
| 5 | +A real (albeit now-outdated) example is that [WebDriver for Apple Safari v11 could not change the selection of an HTML `<select>` element]. |
| 6 | +When faced with that bug, the only course of action a developer could take was to work around it. |
| 7 | + |
| 8 | +[WebDriver for Apple Safari v11 could not change the selection of an HTML `<select>` element]: https://github.com/SeleniumHQ/selenium/issues/5475#issuecomment-365082942 |
| 9 | + |
| 10 | +## How the 'quirks' architecture can help |
| 11 | + |
| 12 | +Developers do not want to litter their WebDriver-consuming code with browser detection logic. |
| 13 | +Just like in regular web development, [browser detection is bad, feature detection is better]. |
| 14 | +What the quirks architecture provides is an additional interface, added to WebDrivers created by [the universal WebDriver factory]: [`IHasQuirks`]. |
| 15 | + |
| 16 | +WebDrivers which implement `IHasQuirks` can cross-reference their [browser identification] with source data listing which browsers are affected by which quirks. |
| 17 | +The result is the [`AllQuirks`] property and the following extension methods (for convenience): |
| 18 | + |
| 19 | +* [`HasQuirk(string)`] |
| 20 | +* [`GetQuirks()`] |
| 21 | +* [`GetFirstApplicableQuirk(params string[])`] |
| 22 | + |
| 23 | +[browser detection is bad, feature detection is better]: https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection |
| 24 | +[the universal WebDriver factory]: index.md |
| 25 | +[`IHasQuirks`]: xref:CSF.Extensions.WebDriver.Quirks.IHasQuirks |
| 26 | +[browser identification]: DriverIdentification.md |
| 27 | +[`AllQuirks`]: xref:CSF.Extensions.WebDriver.Quirks.IHasQuirks.AllQuirks |
| 28 | + |
| 29 | +[`HasQuirk(string)`]: xref:OpenQA.Selenium.WebDriverExtensions.HasQuirk(OpenQA.Selenium.IWebDriver,System.String) |
| 30 | +[`GetQuirks()`]: xref:OpenQA.Selenium.WebDriverExtensions.GetQuirks(OpenQA.Selenium.IWebDriver) |
| 31 | +[`GetFirstApplicableQuirk(params string[])`]: xref:OpenQA.Selenium.WebDriverExtensions.GetFirstApplicableQuirk(OpenQA.Selenium.IWebDriver,System.String[]) |
| 32 | + |
| 33 | +## The quirks source data |
| 34 | + |
| 35 | +Quirks source data may come from two sources. |
| 36 | +To use quirks _at least one source must be activated_ and it is recommended to enable both. |
| 37 | + |
| 38 | +* Hard-coded into an application/library |
| 39 | +* Supplementary configuration data |
| 40 | + |
| 41 | +The intent is that an application or library may ship with quirks information that is known at the time of writing. |
| 42 | +This information may be supplemented or (in part or wholly) overwritten by quirks information provided by the consumer. |
| 43 | +This allows consuming logic to react to changes in browser quirks (as time moves on) by adding their own quirks configuration and not needing to wait for an upstream app/library to release an updated version with new quirks source data. |
| 44 | + |
| 45 | +This library uses a simple merging algorithm to combine the hard-coded and options data-sources. |
| 46 | +Where the two sources list quirks that the other source does not, the resultant data will contain both quirks. |
| 47 | +Where the two sources list the same quirk, the Options data will _win the disagreement_, so to speak, and will shadow the hard-coded data. |
| 48 | + |
| 49 | +Developers may use this technique to update the affected browsers for a quirk or even to (effectively) remove it, by giving it an empty set of affected browsers. |
| 50 | + |
| 51 | +## Setting up quirks functionality |
| 52 | + |
| 53 | +To configure the source data you must activate it in source control. |
| 54 | +In the following example, `quirksData` represents data which would be hard-coded into your application/library (design-time). |
| 55 | + |
| 56 | +```csharp |
| 57 | +services.AddWebDriverQuirks(quirksData); |
| 58 | +``` |
| 59 | + |
| 60 | +The [`AddWebDriverQuirks`] method is customisable with a number of parameters, most of which are not shown above. |
| 61 | +By default any quirks data specified in [the app Configuration], via [the Options Pattern], will be used to supplement and/or override that hard-coded data. |
| 62 | +The default configuration path for quirks data is `WebDriverQuirks`. |
| 63 | + |
| 64 | +Lastly, to use quirks functionality it must also be activated in the [`WebDriverCreationOptions`], via the [`AddBrowserQuirks`] property. |
| 65 | + |
| 66 | +[`AddWebDriverQuirks`]: xref:CSF.Extensions.WebDriver.ServiceCollectionExtensions.AddWebDriverQuirks(Microsoft.Extensions.DependencyInjection.IServiceCollection,CSF.Extensions.WebDriver.Quirks.QuirksData,System.Boolean,System.String) |
| 67 | +[the app Configuration]: https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration |
| 68 | +[the Options Pattern]: https://learn.microsoft.com/en-us/dotnet/core/extensions/options |
| 69 | +[`WebDriverCreationOptions`]: xref:CSF.Extensions.WebDriver.Factories.WebDriverCreationOptions |
| 70 | +[`AddBrowserQuirks`]: xref:CSF.Extensions.WebDriver.Factories.WebDriverCreationOptions.AddBrowserQuirks |
| 71 | + |
| 72 | +## A note on proxies |
| 73 | + |
| 74 | +Be aware that when the WebDriver quirks functionality is activated, [the WebDriver returned by the universal factory will be _a proxy object_] and not the original concrete WebDriver implementation. |
| 75 | +In best-practice scenarios where the WebDriver is utilised only by its interfaces this should make no difference. |
| 76 | +More information is available at the linked documentation above. |
| 77 | + |
| 78 | +[the WebDriver returned by the universal factory will be _a proxy object_]: Proxies.md |
0 commit comments