Przechwytywanie błędu JavaScript w Selenium

81

Czy istnieje sposób na wychwycenie błędów występujących w programie DOMin Seleniumi prawdopodobnie oznaczenie tego samego, co błąd na stronie?

Aby dać krótki przykład, powiedzmy, że próbuję powiązać zdarzenie z nieistniejącą kontrolką HTML, moja przeglądarka zgłasza błąd:

element abcd not found in the console.

Teraz, jeśli chcę, aby ten sam błąd nie przeszedł moich testów selenu, a komunikat wyświetlany w przeglądarce jest wyświetlany jako komunikat o błędzie.

Czy można coś takiego zrobić?

Baz1nga
źródło
1
Teraz jest 2018, czy istnieje czystsze rozwiązanie?
Fla

Odpowiedzi:

52

Umieść ten skrypt na swojej stronie, a następnie sprawdź w Selenium pod kątem JSError:

<script type="text/javascript">
    window.onerror=function(msg){
        $("body").attr("JSError",msg);
    }
</script>
jhanifen
źródło
3
Można to łatwo rozszerzyć, aby wychwycić również przypadek, w którym JQuery nie załadował się: dodaj $ ('body'). Attr ("JQLoaded", "Yes") poza wywołaniem onerror. Następnie w Selenium obecność JSError, LUB brak JQLoaded, sygnalizuje błąd Javascript.
Nils
51
Lub możesz po prostu powiedzieć document.body.setAttribute("JSError", msg)zamiast polegać na jQuery
Kos
3
Czy musi być dodawany do strony HTML na zawsze, czy dynamicznie podczas uruchamiania testów? Nie jestem pewien, czy przekonywałbym programistów do dodawania tego fragmentu na każdej stronie. Dziękuję za udostępnienie mi szczegółów.
Michał
3
Połączona strona nie jest już dostępna.
Chris B. Behrens
54

Robię to, aby wychwycić błędy JavaScript:

[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
źródło
3
Naprawdę podoba mi się to rozwiązanie
Rob G
2
Korzystając z najnowszej wersji sterownika Selenium 3.6.0 i przeglądarki Firefox 56.0, metoda „GetLog” generuje „odwołanie do obiektu nie jest ustawione na instancję obiektu”, nie wiem dlaczego ... To zadziałało w starszej wersji WebDriver / Firefox
David Rogers
2
@DavidRogers Myślę, że to już nie działa na geckodriver z tego powodu: github.com/mozilla/geckodriver/issues/284
Christian Hujer
19

Nie jestem pewien, kiedy to się zmieniło, ale teraz działa to dla mnie w Pythonie. Plik jest prostą stroną z błędem JavaScript.

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 w wersji 2.48.0 Linux Firefox 43.0

kleptog
źródło
Działa to również z webdriver.io. driver.log("browser").then(function(results){ console.log(results.value); }
Tyler Hawkins
Obecnie nie będzie działać z przeglądarką Firefox z powodu tego problemu: github.com/mozilla/geckodriver/issues/284
Christian Hujer
7

Oto rozwiązanie webdriver w Pythonie, którego używam:

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

    errors = []
    for entry in browserlogs:
        if entry['level'] == 'SEVERE':
            errors.append(entry)
    return errors
d3ming
źródło
6

JSErrorCollector wykonuje zadanie.

Po skonfigurowaniu jest to kwestia:

List<JavaScriptError> jsErrorList = JavaScriptError.readErrors(driver);
Leor
źródło
2
Do Twojej wiadomości: ten projekt obecnie obsługuje tylko przeglądarkę Firefox
AlignedDev
1
Ostatni zatwierdzony 4 lata temu, mówi o Firefoksie 36 i Firebug ... Od tamtego czasu wiele się zmieniło.
Fla
i czy to jest oryginalny wpis na blogu dotyczący tego? mguillem.wordpress.com/2011/10/11/…
David
3

Chciałbym powtórzyć odpowiedź jhanifen. Oto rozwiązanie javascript, które nie zależy od jQuery. Tworzy niewidoczną listę HTML na dole strony, która zawiera błędy.

(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
źródło
2

Rozwiązanie z "window.onerror" nie działa dla mnie.

Dlatego chciałbym wskazać inne rozwiązanie ze zmianą user-extensions.js, które pomogło mi:
Czy Selenium może wykryć, czy strona zawiera błędy JavaScript?

Główna zaleta: nie musisz zmieniać źródła strony, aby sprawdzić.

A oto jak używać user-extensions.js: Używanie rozszerzeń
użytkownika z Selenium-IDE

Uwaga: to rozwiązanie działa tylko z przeglądarką Firefox

sumid
źródło
2

Oto moje rozwiązanie inspirowane odpowiedzią jhanifena:

// 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'}
Ali powiedział OMAR
źródło
1

Jeśli używasz javy, zapraszam do wypróbowania tej stworzonej przeze mnie biblioteki , która pozwala w prosty sposób zbierać błędy JS otrzymane w sesji Chromedriver, używając adnotacji na metodach testowych. Działa na JUnit5 z rozszerzoną adnotacją i na TestNG z odbiornikiem analizującym adnotację. Adnotacja zawiera wartości logiczne, które pozwalają zdecydować, czy po wykonaniu testu chcesz potwierdzić, czy zapisać znalezione błędy.

Przykład JUnit5:

@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
źródło
1

TestCase.tearDown()W moich testach Python Selenium używam następujących elementów , które powodują niepowodzenie testu w przypadku błędów JavaScript:

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)}')

Jest to inspirowane odpowiedziami @kleptog i @ d3ming.

mrts
źródło
0

Spróbuj uwzględnić zdarzenie windows.onerror na swojej stronie lub włączyć okno dialogowe błędu w opcjach IE. Jeśli wybierzesz później w Se1 zawiesi się. PS: Zostało to omówione tutaj. Wyszukaj.

Rajasankar
źródło