87

Is there a way to capture errors occurring in the DOM in Selenium and probably flag the same as an error in the page?

To give a brief example, let's say I'm trying to bind an event on a non-existing HTML control, my browser throws an error saying:

element abcd not found in the console.

Now, if I want the same error to fail my selenium tests and the message that is shown on the browser is shown as the error message.

Is it possible to do something like this?

Alex Kulinkovich
  • 4,408
  • 15
  • 46
  • 50
Baz1nga
  • 15,485
  • 3
  • 35
  • 61

12 Answers12

59

I'm doing this to capture JavaScript errors:

[TestCleanup]
public void TestCleanup()
{
    var errorStrings = new List<string> 
    { 
        "SyntaxError", 
        "EvalError", 
        "ReferenceError", 
        "RangeError", 
        "TypeError", 
        "URIError" 
    };

    var jsErrors = Driver.Manage().Logs.GetLog(LogType.Browser).Where(x => errorStrings.Any(e => x.Message.Contains(e)));

    if (jsErrors.Any())
    {
        Assert.Fail("JavaScript error(s):" + Environment.NewLine + jsErrors.Aggregate("", (s, entry) => s + entry.Message + Environment.NewLine));
    }
}
magnusarinell
  • 1,127
  • 14
  • 22
  • 3
    Really like this solution – Rob G Oct 21 '16 at 18:32
  • 2
    Using the latest version of the Selenium Driver 3.6.0 and Firefox 56.0, the "GetLog" method throws a "Object reference not set to an instance of an object", not sure why... This worked in older version of the WebDriver/Firefox – David Rogers Oct 20 '17 at 15:08
  • 2
    @DavidRogers I think this is no longer working on geckodriver because of this: https://github.com/mozilla/geckodriver/issues/284 – Christian Hujer Nov 19 '18 at 15:49
53

Put this script on your page and then check in Selenium for the JSError:

<script type="text/javascript">
    window.onerror=function(msg){
        $("body").attr("JSError",msg);
    }
</script>
jhanifen
  • 4,441
  • 7
  • 43
  • 67
  • 3
    This can easily be extended to also catch the case where JQuery didn't load: add a $('body').attr("JQLoaded","Yes") outside the onerror call. Then in Selenium presence of JSError, OR absence of JQLoaded, signals a Javascript error. – Nils May 23 '12 at 07:17
  • 55
    Or you could just say `document.body.setAttribute("JSError", msg)` instead of depending on jQuery – Kos Apr 28 '14 at 08:49
  • 3
    Does it have to be added to HTML page forever, or dynamically when tests are run?? I am not sure I would convince developers to add that snippet on every page. Thanks for sharing details for me. – Michal Mar 11 '16 at 12:13
  • 3
    The linked page is no longer available. – Chris B. Behrens Oct 09 '17 at 14:21
20

Not sure when this changed, but right now this works for me in Python. The file is a simple page with a javascript error.

In [11]: driver.get("file:///tmp/a.html")

In [12]: driver.get_log("browser")
Out[12]: 
[{u'level': u'SEVERE',
  u'message': u'ReferenceError: foo is not defined',
  u'timestamp': 1450769357488,
  u'type': u''},
 {u'level': u'INFO',
  u'message': u'The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol.',
  u'timestamp': 1450769357498,
  u'type': u''}]

Python-Selenium version 2.48.0 Linux Firefox 43.0

kleptog
  • 631
  • 6
  • 9
8

Here's the python webdriver solution I use:

from selenium.common.exceptions import WebDriverException
import logging


def check_browser_errors(driver):
    """
    Checks browser for errors, returns a list of errors
    :param driver:
    :return:
    """
    try:
        browser_logs = driver.get_log('browser')
    except (ValueError, WebDriverException) as e:
        # Some browsers does not support getting logs
        logging.debug("Could not get browser logs for driver %s due to exception: %s",
                     driver, e)
        return []

    errors = [entry for entry in browser_logs if entry['level'] == 'SEVERE']

    return errors
Preston Badeer
  • 2,658
  • 1
  • 20
  • 21
d3ming
  • 8,496
  • 5
  • 31
  • 33
  • Trying to access `driver.get_log('browser')` gives me `WebDriverException: Message: HTTP method not allowed` – Cerin May 05 '23 at 14:55
6

JSErrorCollector does the job.

Once configured, it's a matter of:

List<JavaScriptError> jsErrorList = JavaScriptError.readErrors(driver);
Leor
  • 1,252
  • 11
  • 12
  • 2
    FYI: this project currently only supports Firefox – AlignedDev Jan 06 '15 at 22:43
  • 1
    Last commit 4 years ago, speaks about Firefox 36 and Firebug... So many things changed since then. – Fla Aug 31 '18 at 13:55
  • and is this the original blog post for this? https://mguillem.wordpress.com/2011/10/11/webdriver-capture-js-errors-while-running-tests/ – David Oct 09 '19 at 01:37
3

Solution with "window.onerror" didn't work for me.

So I'd like to point out another solution with altering user-extensions.js which helped me:
Can Selenium detect if the page has JavaScript errors?

Main advantage: You don't have to change the page source to do the check.

And here is how to use user-extensions.js:
Using User-Extensions With Selenium-IDE

Note: This solution works only with Firefox

sumid
  • 1,871
  • 2
  • 25
  • 37
3

I would like to iterate on the answer of jhanifen. Here is a javascript solution that does not depend on jQuery. It creates an invisible HTML list on the bottom of the page, which contians the errors.

(function () {
    var ul = null;
    function createErrorList() {
        ul = document.createElement('ul');
        ul.setAttribute('id', 'js_error_list');
        ul.style.display = 'none';
        document.body.appendChild(ul);
    }
    window.onerror = function(msg){
        if (ul === null)
            createErrorList();
        var li = document.createElement("li");
        li.appendChild(document.createTextNode(msg));
        ul.appendChild(li);
    };
})();
Gábor Angyal
  • 2,225
  • 17
  • 27
3

Non-window.onerror-based solution (I did not try): http://sejq.blogspot.com/2008/12/can-selenium-detect-if-page-has.html

Tgr
  • 27,442
  • 12
  • 81
  • 118
2

Here my solution inspiring by jhanifen's response:

// common.js - js file common to the entire app
globalError = []
window.onerror = function (msg, url, line, col, error) {
    globalError.push({msg:msg, url:url, line:line})
};

# tests.py
def tearDown(driver):
    # assert on js error 
    ret = driver.selenium.execute_script("return globalError ")
    driver.assertFalse(ret, "errors %r " % ret)
    # ret will be a dict looking like 
    # {'line': 50, 'url': 'http://localhost:8081/static/js/common.js', 'msg': 'Uncaught ReferenceError: s is not defined'}
intotecho
  • 4,925
  • 3
  • 39
  • 54
Ali SAID OMAR
  • 6,404
  • 8
  • 39
  • 56
2

I use the following TestCase.tearDown() in my Python Selenium tests that makes the test fail in case of JavaScript errors:

def tearDown(self):
    browser_logs = driver.get_log("browser")
    errors = [logentry['message'] for logentry in browser_logs if logentry['level'] == 'SEVERE']
    if errors:
        self.fail(f'The following JavaScript errors occurred: {"; ".join(errors)}')

This is inspired by @kleptog and @d3ming answers.

mrts
  • 16,697
  • 8
  • 89
  • 72
1

If you're using java, you're welcome to try this library comitted by me which allows to easily collect JS errors received in Chromedriver session, using annotations on test methods. It works on on JUnit5 with extended annotation, and on TestNG with a listener parsing the annotation. The annotation contains boolean values which let you decide whether you want to assert or log the found errors after test execution.

JUnit5 example:

@Test
@JSErrorsCollectorJUnit
void referenceErrorTest(TestInfo testInfo) throws InterruptedException {

    // Create a new instance of ChromeDriver.
    driver = new ChromeDriver();

    // Set your test name to point its ChromeDriver session in HashMap.
    JSErrorsDriverHolder.setDriverForTest(testInfo.getDisplayName(), driver);

    // Navigate to URL.
    driver.get("http://testjs.site88.net");

    // The click on the button in the test site should cause JS reference error.
    driver.findElement(By.name("testClickButton")).click();
    waitBeforeClosingBrowser();
}
AutomatedOwl
  • 1,039
  • 1
  • 8
  • 14
0

You try including windows.onerror event in your page or enable the show error dialog box in IE options. If you choose the later in Se1 will hang. PS: This has been discussed here. Do a search.

Rajasankar
  • 928
  • 1
  • 19
  • 41