diff --git a/src/Shared/E2ETesting/BrowserAssertFailedException.cs b/src/Shared/E2ETesting/BrowserAssertFailedException.cs new file mode 100644 index 0000000000..579be07d47 --- /dev/null +++ b/src/Shared/E2ETesting/BrowserAssertFailedException.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Xunit.Sdk; + +namespace OpenQA.Selenium +{ + // Used to report errors when we find errors in the browser. This is useful + // because the underlying assert probably doesn't provide good information in that + // case. + public class BrowserAssertFailedException : XunitException + { + public BrowserAssertFailedException(IReadOnlyList logs, Exception innerException) + : base(BuildMessage(logs), innerException) + { + } + + private static string BuildMessage(IReadOnlyList logs) + { + return + "Encountered browser errors while running assertion." + Environment.NewLine + + string.Join(Environment.NewLine, logs); + } + } +} diff --git a/src/Shared/E2ETesting/BrowserTestBase.cs b/src/Shared/E2ETesting/BrowserTestBase.cs index 8e94a4bfb2..325509bdb9 100644 --- a/src/Shared/E2ETesting/BrowserTestBase.cs +++ b/src/Shared/E2ETesting/BrowserTestBase.cs @@ -80,15 +80,14 @@ namespace Microsoft.AspNetCore.E2ETesting protected IWebElement WaitUntilExists(By findBy, int timeoutSeconds = 10, bool throwOnError = false) { - List errors = null; + IReadOnlyList errors = null; IWebElement result = null; new WebDriverWait(Browser, TimeSpan.FromSeconds(timeoutSeconds)).Until(driver => { if (throwOnError && Browser.Manage().Logs.AvailableLogTypes.Contains(LogType.Browser)) { // Fail-fast if any errors were logged to the console. - var log = Browser.Manage().Logs.GetLog(LogType.Browser); - errors = log.Where(IsError).ToList(); + errors = Browser.GetBrowserLogs(LogLevel.Severe); if (errors.Count > 0) { return true; diff --git a/src/Shared/E2ETesting/WaitAssert.cs b/src/Shared/E2ETesting/WaitAssert.cs index 42b9934b37..1dc707012b 100644 --- a/src/Shared/E2ETesting/WaitAssert.cs +++ b/src/Shared/E2ETesting/WaitAssert.cs @@ -73,7 +73,12 @@ namespace Microsoft.AspNetCore.E2ETesting } catch (WebDriverTimeoutException) { - if (lastException != null) + var errors = driver.GetBrowserLogs(LogLevel.Severe); + if (errors.Count > 0) + { + throw new BrowserAssertFailedException(errors, lastException); + } + else if (lastException != null) { ExceptionDispatchInfo.Capture(lastException).Throw(); } diff --git a/src/Shared/E2ETesting/WebDriverExtensions.cs b/src/Shared/E2ETesting/WebDriverExtensions.cs new file mode 100644 index 0000000000..04383296bf --- /dev/null +++ b/src/Shared/E2ETesting/WebDriverExtensions.cs @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenQA.Selenium +{ + public static class WebDriverExtensions + { + public static IReadOnlyList GetBrowserLogs(this IWebDriver driver, LogLevel level) + { + if (driver is null) + { + throw new ArgumentNullException(nameof(driver)); + } + + // Fail-fast if any errors were logged to the console. + var log = driver.Manage().Logs.GetLog(LogType.Browser); + if (log == null) + { + return Array.Empty(); + } + + var logs = log.Where(entry => entry.Level >= level && !ShouldIgnore(entry)).ToList(); + if (logs.Count > 0) + { + return logs; + } + + return Array.Empty(); + } + + // Be careful adding anything new to this list. We only want to put things here that are ignorable + // in all cases. + private static bool ShouldIgnore(LogEntry entry) + { + // Don't fail if we're missing the favicon, that's not super important. + if (entry.Message.Contains("favicon.ico")) + { + return true; + } + + // These two messages appear sometimes, but it doesn't actually block the tests. + if (entry.Message.Contains("WASM: wasm streaming compile failed: TypeError: Could not download wasm module")) + { + return true; + } + if (entry.Message.Contains("WASM: falling back to ArrayBuffer instantiation")) + { + return true; + } + + return false; + } + } +}