Fail faster in Blazor E2E tests

This change adds a fail-fast mechanism to our E2E tests based on
the browser console. This will fail super hard if an unhandled exception
is thrown.

I think it would be interesting to also see if we could do the same
thing for 404s.

The goal of this change is to make it so that the E2E tests can fail
faster (3-4s) than the 30s timeout in the case that something
catastrophic happens. As a nice side benefit you get to see the
exception message.
This commit is contained in:
Ryan Nowak 2019-07-11 11:29:26 -07:00
parent 40e268f59e
commit 3cc6e8373b
2 changed files with 67 additions and 11 deletions

View File

@ -1,13 +1,12 @@
// 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.Linq;
using BasicTestApp;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
using System.Linq;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure
@ -38,18 +37,10 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure
protected SelectElement WaitUntilTestSelectorReady()
{
var elemToFind = By.CssSelector("#test-selector > select");
WaitUntilExists(elemToFind, timeoutSeconds: 30);
WaitUntilExists(elemToFind, timeoutSeconds: 30, throwOnError: true);
return new SelectElement(Browser.FindElement(elemToFind));
}
protected IWebElement WaitUntilExists(By findBy, int timeoutSeconds = 10)
{
IWebElement result = null;
new WebDriverWait(Browser, TimeSpan.FromSeconds(timeoutSeconds))
.Until(driver => (result = driver.FindElement(findBy)) != null);
return result;
}
protected void SignInAs(string usernameOrNull, string rolesOrNull, bool useSeparateTab = false)
{
const string authenticationPageUrl = "/Authentication";

View File

@ -1,11 +1,16 @@
// 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;
using System.Threading;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Microsoft.AspNetCore.E2ETesting
{
@ -55,6 +60,66 @@ namespace Microsoft.AspNetCore.E2ETesting
protected virtual void InitializeAsyncCore()
{
// Clear logs - we check these during tests in some cases.
// Make sure each test starts clean.
((IJavaScriptExecutor)Browser).ExecuteScript("console.clear()");
}
protected IWebElement WaitUntilExists(By findBy, int timeoutSeconds = 10, bool throwOnError = false)
{
List<LogEntry> 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();
if (errors.Count > 0)
{
return true;
}
}
return (result = driver.FindElement(findBy)) != null;
});
if (errors?.Count > 0)
{
var message =
$"Encountered errors while looking for '{findBy}'." + Environment.NewLine +
string.Join(Environment.NewLine, errors);
throw new XunitException(message);
}
return result;
}
private static bool IsError(LogEntry entry)
{
if (entry.Level < LogLevel.Severe)
{
return false;
}
// Don't fail if we're missing the favicon, that's not super important.
if (entry.Message.Contains("favicon.ico"))
{
return false;
}
// 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 false;
}
if (entry.Message.Contains("WASM: falling back to ArrayBuffer instantiation"))
{
return false;
}
return true;
}
}
}