Attempt to read the logs from the browser (#26289)

* Attempt to read the logs from the browser

Seleniunm currently does not return log messages (See https://github.com/SeleniumHQ/selenium/issues/8229).
This making figuring out blazor WASM test failures a lot harder.

This change adds some JS to the test apps to read the console output.

* WIP
This commit is contained in:
Pranav K 2020-09-28 17:07:22 -07:00 committed by GitHub
parent 90f4cdad9e
commit 0e5d7ef1d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 118 additions and 42 deletions

View File

@ -6,6 +6,7 @@
</head>
<body>
<app>Loading...</app>
<script src="seleniumworkaround.js"></script>
<script src="customJsFileForTests.js"></script>
<script src="_framework/blazor.webassembly.js" autostart="false"></script>

View File

@ -0,0 +1,26 @@
(function () {
// Note: there are multiple copies of this file throughout the repo. If you're editing it, please look for
// other seleniumworkaround.js files and keep them all in sync.
const logs = [];
const defaultLog = console.log;
console.log = function () {
defaultLog.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
const defaultError = console.error;
console.error = function () {
defaultError.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
const defaultWarn = console.warn;
console.warn = function () {
defaultWarn.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
window.getBrowserLogs = () => logs;
})();

View File

@ -17,6 +17,8 @@
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="seleniumworkaround.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
</body>

View File

@ -0,0 +1,26 @@
(function () {
// Note: there are multiple copies of this file throughout the repo. If you're editing it, please look for
// other seleniumworkaround.js files and keep them all in sync.
const logs = [];
const defaultLog = console.log;
console.log = function () {
defaultLog.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
const defaultError = console.error;
console.error = function () {
defaultError.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
const defaultWarn = console.warn;
console.warn = function () {
defaultWarn.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
window.getBrowserLogs = () => logs;
})();

View File

@ -62,8 +62,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
((IJavaScriptExecutor)Browser).ExecuteScript("Blazor._internal.forceCloseConnection()");
// Wait until the reconnection dialog has been shown but is now hidden
new WebDriverWait(Browser, TimeSpan.FromSeconds(10))
.Until(driver => driver.FindElement(By.Id("components-reconnect-modal"))?.GetCssValue("display") == "none");
var reconnectModel = Browser.Exists(By.Id("components-reconnect-modal"));
Browser.Equal("none", () => reconnectModel.GetCssValue("display"));
}
}
}

View File

@ -48,8 +48,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
var interopButton = Browser.FindElement(By.Id("btn-interop"));
interopButton.Click();
var wait = new WebDriverWait(Browser, TimeSpan.FromSeconds(10))
.Until(d => d.FindElement(By.Id("done-with-interop")));
Browser.Exists(By.Id("done-with-interop"));
foreach (var expectedValue in expectedValues)
{

View File

@ -2,13 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using BasicTestApp;
using BasicTestApp.HttpClientTest;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using Microsoft.AspNetCore.Testing;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using TestServer;
using Xunit;
using Xunit.Abstractions;
@ -61,9 +59,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
_appElement.FindElement(By.Id("send-request")).Click();
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.Id("response-status")) != null);
_responseStatus = _appElement.FindElement(By.Id("response-status"));
_responseStatus = Browser.Exists(By.Id("response-status"));
_responseStatusText = _appElement.FindElement(By.Id("response-status-text"));
_testOutcome = _appElement.FindElement(By.Id("test-outcome"));
}

View File

@ -148,8 +148,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
private void WaitUntilLoaded()
{
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.TagName("h1")).Text == "Hello, world!");
var element = Browser.Exists(By.TagName("h1"));
Browser.Equal("Hello, world!", () => element.Text);
}
}
}

View File

@ -61,11 +61,10 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
Assert.NotNull(Browser.FindElement(By.Id("test-selector")));
}
private void WaitUntilLoaded()
{
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.TagName("app")).Text != "Loading...");
var app = Browser.Exists(By.TagName("app"));
Browser.NotEqual("Loading...", () => app.Text);
}
}
}

View File

@ -48,8 +48,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
private void WaitUntilLoaded()
{
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.TagName("app")).Text != "Loading...");
var app = Browser.Exists(By.TagName("app"));
Browser.NotEqual("Loading...", () => app.Text);
}
}
}

View File

@ -134,9 +134,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
string WaitAndGetResponseText()
{
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.Id("response-text")) != null);
return app.FindElement(By.Id("response-text")).Text;
return Browser.Exists(By.Id("response-text")).Text;
}
}
@ -150,9 +148,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
_appElement.FindElement(By.Id("send-request")).Click();
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.Id("response-status")) != null);
_responseStatus = _appElement.FindElement(By.Id("response-status"));
_responseStatus = Browser.Exists(By.Id("response-status"));
_responseBody = _appElement.FindElement(By.Id("response-body"));
_responseHeaders = _appElement.FindElement(By.Id("response-headers"));
}

View File

@ -135,8 +135,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
var interopButton = Browser.FindElement(By.Id("btn-interop"));
interopButton.Click();
var wait = new WebDriverWait(Browser, TimeSpan.FromSeconds(10))
.Until(d => d.FindElement(By.Id("done-with-interop")));
Browser.Exists(By.Id("done-with-interop"));
foreach (var expectedValue in expectedValues)
{

View File

@ -546,10 +546,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
SetUrlViaPushState("/LongPage1");
new WebDriverWait(Browser, TimeSpan.FromSeconds(2)).Until(
driver => driver.FindElement(By.Id("loading-banner")) != null);
Assert.True(app.FindElement(By.Id("loading-banner")) != null);
Browser.Exists(By.Id("loading-banner"));
}
[Fact]

View File

@ -96,8 +96,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
// Wait until loaded
var tableSelector = By.CssSelector("table.table");
new WebDriverWait(Browser, TimeSpan.FromSeconds(10)).Until(
driver => driver.FindElement(tableSelector) != null);
Browser.Exists(tableSelector);
// Check the table is displayed correctly
var rows = Browser.FindElements(By.CssSelector("table.table tbody tr"));
@ -111,8 +110,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
private void WaitUntilLoaded()
{
new WebDriverWait(Browser, TimeSpan.FromSeconds(30)).Until(
driver => driver.FindElement(By.TagName("app")).Text != "Loading...");
var app = Browser.Exists(By.TagName("app"));
Browser.NotEqual("Loading...", () => app.Text);
}
public void Dispose()

View File

@ -66,13 +66,10 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
{
// Navigate to a page with lazy loaded assemblies for the first time
SetUrlViaPushState("/WithLazyAssembly");
var app = Browser.MountTestComponent<TestRouterWithLazyAssembly>();
Browser.MountTestComponent<TestRouterWithLazyAssembly>();
// Wait for the page to finish loading
new WebDriverWait(Browser, TimeSpan.FromSeconds(2)).Until(
driver => driver.FindElement(By.Id("use-package-button")) != null);
var button = app.FindElement(By.Id("use-package-button"));
var button = Browser.Exists(By.Id("use-package-button"));
// We should have requested the DLL
Assert.True(HasLoadedAssembly("Newtonsoft.Json.dll"));
@ -98,8 +95,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
SetUrlViaPushState("/WithLazyLoadedRoutes");
// Wait for the page to finish loading
new WebDriverWait(Browser, TimeSpan.FromSeconds(2)).Until(
driver => driver.FindElement(By.Id("lazy-load-msg")) != null);
Browser.Exists(By.Id("lazy-load-msg"));
// Now the assembly has been loaded
Assert.True(HasLoadedAssembly("LazyTestContentPackage.dll"));

View File

@ -26,6 +26,7 @@
</div>
<!-- Used for specific test cases -->
<script src="js/seleniumworkaround.js"></script>
<script src="js/jsinteroptests.js"></script>
<script src="js/renderattributestest.js"></script>
<script src="js/webComponentPerformingJsInterop.js"></script>

View File

@ -0,0 +1,26 @@
(function () {
// Note: there are multiple copies of this file throughout the repo. If you're editing it, please look for
// other seleniumworkaround.js files and keep them all in sync.
const logs = [];
const defaultLog = console.log;
console.log = function () {
defaultLog.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
const defaultError = console.error;
console.error = function () {
defaultError.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
const defaultWarn = console.warn;
console.warn = function () {
defaultWarn.apply(console, arguments);
logs.push(Array.from(arguments).join(' '));
}
window.getBrowserLogs = () => logs;
})();

View File

@ -14,12 +14,12 @@ namespace OpenQA.Selenium
// case.
public class BrowserAssertFailedException : XunitException
{
public BrowserAssertFailedException(IReadOnlyList<LogEntry> logs, Exception innerException, string screenShotPath, string innerHTML)
public BrowserAssertFailedException(IReadOnlyCollection<string> logs, Exception innerException, string screenShotPath, string innerHTML)
: base(BuildMessage(innerException, logs, screenShotPath, innerHTML), innerException)
{
}
private static string BuildMessage(Exception exception, IReadOnlyList<LogEntry> logs, string screenShotPath, string innerHTML)
private static string BuildMessage(Exception exception, IReadOnlyCollection<string> logs, string screenShotPath, string innerHTML)
{
var builder = new StringBuilder();
builder.AppendLine(exception.ToString());

View File

@ -5,8 +5,11 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.ExceptionServices;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools.Page;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Support.UI;
using Xunit;
@ -117,7 +120,17 @@ namespace Microsoft.AspNetCore.E2ETesting
var fileId = $"{Guid.NewGuid():N}.png";
var screenShotPath = Path.Combine(Path.GetFullPath(E2ETestOptions.Instance.ScreenShotsPath), fileId);
var errors = driver.GetBrowserLogs(LogLevel.All);
var errors = driver.GetBrowserLogs(LogLevel.All).Select(c => c.ToString()).ToList();
if (errors.Count == 0)
{
// Workaround for selenium bug https://github.com/SeleniumHQ/selenium/issues/8229. Getting log does
// not work. However some of our test apps provide a mechnanism to read the logs. Try that.
var logs = (IReadOnlyCollection<object>)((IJavaScriptExecutor)driver).ExecuteScript(
"return window.getBrowserLogs && window.getBrowserLogs() || []");
errors = logs.Select(l => l.ToString()).ToList();
}
TakeScreenShot(driver, screenShotPath);
var exceptionInfo = lastException != null ? ExceptionDispatchInfo.Capture(lastException) :