= BrowserWatcher
Boni García
Version {project-version}

:revnumber: {project-version}

== Motivation
When an automated end-to-end test (e.g., with https://www.selenium.dev/documentation/webdriver/[Selenium WebDriver]) fails, it can be challenging to discover the underlying error cause. A common strategy is to gather the browser console logs to discard problems on the client-side. The problem is the browser log gathering feature is not standard in the https://www.w3.org/TR/webdriver/[W3C WebDriver] specification. The driver for Chrome (i.e., https://chromedriver.chromium.org/[chromedriver]) provides a custom implementation for log gathering using https://selenide.org/2019/12/16/advent-calendar-browser-logs/[LoggingPreferences]. Nevertheless, this feature is not available in other drivers such as https://github.com/mozilla/geckodriver/[geckodriver] (i.e., the driver for Firefox). A standard solution is proposed in the new https://w3c.github.io/webdriver-bidi/[W3C WebDriver BiDi], but this approach is not yet widely adopted in all browsers.


.What is BrowserWatcher?
****
BrowserWatcher is a https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions[browser extension] designed to monitor web browsers such as Chrome, Firefox, or Edge. Its features are cross-browser console log gathering/displaying, tab recording, Content Security Policy (CSP) disabling, and JavaScript/CSS injection.
****

ifndef::backend-pdf[]
++++
include::carbon.html[]
++++
endif::[]

== Setup
BrowserWatcher can be used in two different ways. First, it can be installed as an extension in any browser implementing the https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions[browser extension API] (such as Chrome, Firefox, Edge, etc.). You can use the following files to install BrowserWatcher in your browser:

* https://github.com/bonigarcia/browserwatcher/releases/download/{project-version}/browserwatcher-{project-version}.crx[browserwatcher-{project-version}.crx]: Chrome Extension (CRX), for Chromium-based browsers, such as Chrome or Edge. To install it, you can drag and drop this file into the extensions page  (_chrome://extensions/_).
* https://github.com/bonigarcia/browserwatcher/releases/download/{project-version}/browserwatcher-{project-version}.xpi[browserwatcher-{project-version}.xpi]: XPInstall (XPI), for Firefox. To install it, visit the _about:addons_ page and click on _Install Add-on From File..._.

Second, you can use BrowserWatcher automatically through https://bonigarcia.dev/webdrivermanager/[WebDriverManager]. See the section about <<WebDriverManager>> for a basic introduction to this use.

== Features
Once BrowserWatcher is installed in a browser, you can see its logo in the browser navigation bar, as follows:

[[browserwatcher-install]]
[.thumb]
.BrowserWatcher installed in Chrome
image::browserwatcher-install-v1.png[scaledwidth=100%]

=== Console Log Gathering
BrowserWatcher allows gathering the browser console following a cross-browser approach. Internally, it uses a _monkey patching_ technique to override the JavaScript object `console`. In particular, the following methods are overridden: `log`, `warn`, `error`, `info`, `dir`, `time`, `timeEnd`, `table`, and `count`. In addition, it implements several JavaScript listeners for the following events: `error` (JavaScript error trace), `unhandledrejection` (when a JavaScript _Promise_ with no rejection handler is rejected), `securitypolicyviolation` (when the content security policy is violated), and `xhr-error` (error response from `XMLHttpRequest`). This way, the gathered logs are accessible in the property `_bwLogs` in the `console` object. The following picture shows an example of the gathered logs of a the https://bonigarcia.dev/selenium-webdriver-java/console-logs.html[sample page]:

[[gather-console-logs-example]]
[.thumb]
.Console log gathering example
image::gather-console-logs-example-v3.png[scaledwidth=100%]

BrowserWatcher has a configuration page, displayed when clicked in its icon. This page has three toggle buttons to set up different features. The first one allows enabling (and disabling) the log gathering feature.

[[popup-logs]]
[.thumb]
.BrowserWatcher popup configuration page (console log gathering)
image::popup-logs-v2.png[scaledwidth=100%]

=== Console Log Displaying
In addition to log gathering, BrowserWatcher allows displaying the console logs (and listened events) as dialog notifications on the page. This feature can be enabled using the following button:

[[popup-display]]
[.thumb]
.BrowserWatcher popup configuration page (console log displaying)
image::popup-display-v2.png[scaledwidth=100%]

The following picture shows an example of these notifications:

[[display-console-logs-example]]
[.thumb]
.Display logs example
image::display-console-logs-example-v3.png[scaledwidth=100%]

=== Tab recording
BrowserWatcher allows recording a browser tab. This feature requires a page loaded in the current tab (in other words, it cannot record empty or configuration pages). Then, it can be started using the following button:

[[popup-rec]]
[.thumb]
.BrowserWatcher popup configuration page (recording)
image::popup-rec-v2.png[scaledwidth=100%]

The recording is stopped using the same button. The recording file will be a WEBM file, available in your _Downloads_ folder.

WARNING: This feature is based on the API https://developer.chrome.com/docs/extensions/reference/tabCapture/[tabCapture]. Therefore, this feature is not available in Firefox since this API is not implemented by Firefox yet.

There are some alternative ways to start and stop the recordings. First, by using the keyboard shortcut `Alt+R` (for starting the recording) and `Alt+W` (for stopping the recording). Second, by executing the following JavaScript commands:

* `window.postMessage({ type: "startRecording" });` : For starting the recording. The recording file name will be auto generated, composed by the system timestamp plus the prefix `-browser-recording.webm`. 
* `window.postMessage({ type: "startRecording", name: "myrecording" });`: For starting the recording and specifyng a custom file recording (`myrecording.webm` in this example).
* `window.postMessage({ type: "stopRecording" });` : For stopping the recording.

=== Disabling CSP
https://content-security-policy.com/[Content Security Policy (CSP)] is the name of an HTTP response header that browsers use to improve the security of web pages. CSP helps to protect from attacks such as cross-site scripting (XSS). Nevertheless, developers might want to disable the CSP headers received from the server for testing purposes. For this reason, BrowserWatcher allows bypassing these CSP headers. This feature (i.e., disabling CSP headers) is enabled by clicking the following button:

[[popup-csp]]
[.thumb]
.BrowserWatcher popup configuration page (disable CSP headers)
image::popup-csp-v2.png[scaledwidth=100%]

In addition, this feature can be enabled/disabled by executing the following JavaScript commands:

* `window.postMessage({ type: "disableCsp" });` : For disabling CSP.
* `window.postMessage({ type: "enableCsp" });` : For enabling CSP (as it was by default).

=== JavaScript and CSS injection
BrowserWatcher has an _options_ page, available by clicking on the following menu option:

[[options]]
[.thumb]
.BrowserWatcher menu option
image::options-v1.png[scaledwidth=100%]

This options page allows injecting JavaScript code, libraries, and CSS stylesheets. The following screenshot shows an example that injects an online JavaScript library to highlight the mouse. The resulting mouse pointer is shown subsequently.

[[options-saved]]
[.thumb]
.BrowserWatcher options page (example for highlighting mouse)
image::options-saved-v1.png[scaledwidth=100%]

[[js-css-injection-example]]
[.thumb]
.JavaScript and CSS injection page example (highlighting mouse)
image::js-css-injection-example-v1.png[scaledwidth=100%]

Alternatively, this feature can be enabled by executing the following JavaScript commands:

* `window.postMessage({ type: "injectJavaScriptCode", js: "jsCode" });`
* `window.postMessage({ type: "injectJavaScriptLibs", lib: "jsLib" });`
* `window.postMessage({ type: "injectCssSheets", css: "cssSheet" });`

== WebDriverManager
As of version 5.2.0, WebDriverManager provides seamless integration with BrowserWatcher. In other words, WebDriverManager allows injecting BrowserWatcher in browsers controlled with Selenium WebDriver and created through WebDriverManager with the methods `.watch()` and `.create()`. These browsers allow log gathering, displaying, and tab recording through BrowserWatcher.

For example, the following test shows some basic use of log gathering using WebDriverManager and BrowserWatcher:

[source,java]
----
class GatherLogsChromeTest {

    static final Logger log = getLogger(lookup().lookupClass());

    WebDriverManager wdm = WebDriverManager.chromedriver().watch();
    WebDriver driver;

    @BeforeEach
    void setup() {
        driver = wdm.create();
    }

    @AfterEach
    void teardown() {
        driver.quit();
    }

    @Test
    void test() {
        driver.get(
                "https://bonigarcia.dev/selenium-webdriver-java/console-logs.html");

        List<Map<String, Object>> logMessages = wdm.getLogs();

        for (Map<String, Object> map : logMessages) {
            log.debug("[{}] [{}] {}", map.get("datetime"),
                    String.format("%1$-14s",
                            map.get("source").toString().toUpperCase() + "."
                                    + map.get("type").toString().toUpperCase()),
                    map.get("message"));
        }

        assertThat(logMessages).hasSize(5);
    }

}
----

Please visit its https://bonigarcia.dev/webdrivermanager/[documentation page] for further details.

== Further Documentation
There are other resources related to automated testing you can find helpful. For instance, the following books:

* García, Boni. https://www.oreilly.com/library/view/hands-on-selenium-webdriver/9781098109998/[Hands-On Selenium WebDriver with Java]. _O'Reilly Media, Inc._, 2022.
* García, Boni. https://www.amazon.com/Mastering-Software-Testing-JUnit-Comprehensive-ebook/dp/B076ZQCK5Q/[Mastering Software Testing with JUnit 5]. _Packt Publishing Ltd_, 2017.

Or the following journal papers:

* García, Boni, et al. "https://www.sciencedirect.com/science/article/pii/S0164121223001188[Enhancing Web Applications Observability through Instrumented Automated Browsers]." _Journal of Systems and Software_ (2023): 111723.
* Leotta, M., et al. "https://ieeexplore.ieee.org/document/10132210[Challenges of End-to-End Testing with Selenium WebDriver and How to Face Them: A Survey]". In the 16th _IEEE Conference on Software Testing, Verification and Validation_ (ICST), 2023, Dublin, Ireland. April 2023.
* Leotta, M., et al. "https://link.springer.com/chapter/10.1007/978-3-031-14179-9_3[An Empirical Study to Quantify the SetUp and Maintenance Benefits of Adopting WebDriverManager]." _15th International Conference on the Quality of Information and Communications Technology_ (QUATIC) 2022, Talavera de la Reina, Spain. September 2022.
* García, Boni, et al. "https://www.sciencedirect.com/science/article/abs/pii/S0164121222000516[Selenium-Jupiter: A JUnit 5 extension for Selenium WebDriver]." _Journal of Systems and Software_ (2022): 111298.
* García, Boni, et al. "https://link.springer.com/article/10.1007%2Fs10664-021-09975-3[Automated driver management for Selenium WebDriver]." _Empirical Software Engineering_ 26.5 (2021): 1-51.
* García, Boni, et al. "https://www.mdpi.com/2079-9292/9/7/1067[A survey of the Selenium ecosystem]." _Electronics_ 9.7 (2020): 1067.
* García, Boni, et al. "https://www.mdpi.com/2079-9292/9/3/462[Assessment of QoE for video and audio in WebRTC applications using full-reference models]." _Electronics_ 9.3 (2020): 462.
* García, Boni, et al. "https://www.mdpi.com/2079-9292/8/8/854[Practical evaluation of VMAF perceptual video quality for WebRTC applications]." _Electronics_ 8.8 (2019): 854.
* García, Boni, et al. "https://ieeexplore.ieee.org/document/7992926/[WebRTC testing: challenges and practical solutions]." _IEEE Communications Standards Magazine_ 1.2 (2017): 36-42.
* García, Boni, and Juan Carlos Dueñas. "https://www.rintonpress.com/journals/jweonline.html#v14n56[Web browsing automation for applications quality control]." _Journal of web engineering_ (2015): 474-502.

== About
BrowserWatcher (Copyright © 2021-2023) is an open-source project created and maintained by https://bonigarcia.dev/[Boni García] (https://twitter.com/boni_gg[@boni_gg]), licensed under the terms of https://www.apache.org/licenses/LICENSE-2.0[Apache 2.0 License]. This documentation (also available in link:browserwatcher.pdf[PDF]) is released under the terms of https://creativecommons.org/licenses/by-nc-sa/2.0/[CC BY-NC-SA 2.0].