Skip to content

Commit 814e059

Browse files
authored
Merge pull request #90 from FlaUI/error-handling
Improve error handling of unhandled exceptions and timeouts on loading the main window
2 parents b4ca676 + b230eb9 commit 814e059

File tree

7 files changed

+106
-4
lines changed

7 files changed

+106
-4
lines changed

src/FlaUI.WebDriver.UITests/SessionTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,5 +359,15 @@ public void NewCommandTimeout_InvalidValue_Throws(object value)
359359
Assert.That(() => new RemoteWebDriver(WebDriverFixture.WebDriverUrl, driverOptions),
360360
Throws.TypeOf<WebDriverArgumentException>().With.Message.EqualTo("Capability appium:newCommandTimeout must be a number"));
361361
}
362+
363+
[Test]
364+
public void UnknownCommand_Default_ReturnsError()
365+
{
366+
var driverOptions = FlaUIDriverOptions.TestApp();
367+
using var driver = new RemoteWebDriver(WebDriverFixture.WebDriverUrl, driverOptions);
368+
369+
Assert.That(() => driver.Manage().Cookies.DeleteAllCookies(),
370+
Throws.TypeOf<System.NotImplementedException>().With.Message.EqualTo("Unknown command"));
371+
}
362372
}
363373
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using FlaUI.WebDriver.Models;
2+
using Microsoft.AspNetCore.Diagnostics;
3+
using Microsoft.AspNetCore.Mvc;
4+
5+
namespace FlaUI.WebDriver.Controllers
6+
{
7+
[ApiController]
8+
[ApiExplorerSettings(IgnoreApi = true)]
9+
public class ErrorController : ControllerBase
10+
{
11+
private readonly ILogger<ErrorController> _logger;
12+
13+
14+
public ErrorController(ILogger<ErrorController> logger) {
15+
_logger = logger;
16+
}
17+
18+
[Route("/error")]
19+
public IActionResult HandleError() {
20+
var exceptionHandlerFeature = HttpContext.Features.Get<IExceptionHandlerFeature>()!;
21+
22+
_logger.LogError(exceptionHandlerFeature.Error, "Returning WebDriver error response with error code 'unknown error'");
23+
24+
return new ObjectResult(new ResponseWithValue<ErrorResponse>(new ErrorResponse {
25+
ErrorCode = "unknown error",
26+
Message = exceptionHandlerFeature.Error.Message,
27+
StackTrace = exceptionHandlerFeature.Error.StackTrace ?? "" }))
28+
{
29+
StatusCode = 500
30+
};
31+
}
32+
}
33+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using FlaUI.WebDriver.Models;
2+
3+
namespace FlaUI.WebDriver
4+
{
5+
public class NotFoundMiddleware
6+
{
7+
private readonly RequestDelegate _next;
8+
private readonly ILogger _logger;
9+
10+
public NotFoundMiddleware(RequestDelegate next, ILogger<NotFoundMiddleware> logger)
11+
{
12+
_next = next;
13+
_logger = logger;
14+
}
15+
16+
public async Task Invoke(HttpContext httpContext)
17+
{
18+
await _next(httpContext);
19+
if (!httpContext.Response.HasStarted)
20+
{
21+
if (httpContext.Response.StatusCode == StatusCodes.Status404NotFound)
22+
{
23+
_logger.LogError("Unknown endpoint {Path}", SanitizeForLog(httpContext.Request.Path.ToString()));
24+
await httpContext.Response.WriteAsJsonAsync(new ResponseWithValue<ErrorResponse>(new ErrorResponse
25+
{
26+
ErrorCode = "unknown command",
27+
Message = "Unknown command"
28+
}));
29+
}
30+
else if (httpContext.Response.StatusCode == StatusCodes.Status405MethodNotAllowed)
31+
{
32+
_logger.LogError("Unknown method {Method} for endpoint {Path}", SanitizeForLog(httpContext.Request.Method), SanitizeForLog(httpContext.Request.Path.ToString()));
33+
await httpContext.Response.WriteAsJsonAsync(new ResponseWithValue<ErrorResponse>(new ErrorResponse
34+
{
35+
ErrorCode = "unknown method",
36+
Message = "Unknown method for this endpoint"
37+
}));
38+
}
39+
}
40+
}
41+
42+
private static string SanitizeForLog(string str)
43+
{
44+
return str.Replace("\r", "").Replace("\n", "");
45+
}
46+
}
47+
}

src/FlaUI.WebDriver/Program.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424

2525
var app = builder.Build();
2626

27+
app.UseMiddleware<NotFoundMiddleware>();
28+
29+
app.UseExceptionHandler("/error");
30+
2731
// Configure the HTTP request pipeline.
2832
if (app.Environment.IsDevelopment())
2933
{

src/FlaUI.WebDriver/Session.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ public Session(Application? app, bool isAppOwnedBySession)
2020
if (app != null)
2121
{
2222
// We have to capture the initial window handle to be able to keep it stable
23-
CurrentWindowWithHandle = GetOrAddKnownWindow(app.GetMainWindow(Automation, PageLoadTimeout));
23+
var mainWindow = app.GetMainWindow(Automation, PageLoadTimeout);
24+
if (mainWindow == null)
25+
{
26+
throw WebDriverResponseException.Timeout($"Could not get the main window of the app within the page load timeout (${PageLoadTimeout.TotalMilliseconds}ms)");
27+
}
28+
CurrentWindowWithHandle = GetOrAddKnownWindow(mainWindow);
2429
}
2530
}
2631

src/FlaUI.WebDriver/WebDriverExceptionFilter.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ public void OnActionExecuted(ActionExecutedContext context)
1515
if (context.Exception is WebDriverResponseException exception)
1616
{
1717
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<WebDriverResponseExceptionFilter>>();
18-
logger.LogError(exception, "Returning WebDriver error response with error code {ErrorCode}", exception.ErrorCode);
18+
logger.LogError(exception, "Returning WebDriver error response with error code '{ErrorCode}'", exception.ErrorCode);
1919

20-
context.Result = new ObjectResult(new ResponseWithValue<ErrorResponse>(new ErrorResponse { ErrorCode = exception.ErrorCode, Message = exception.Message })) {
20+
context.Result = new ObjectResult(new ResponseWithValue<ErrorResponse>(new ErrorResponse { ErrorCode = exception.ErrorCode, Message = exception.Message }))
21+
{
2122
StatusCode = exception.StatusCode
2223
};
2324
context.ExceptionHandled = true;
2425
}
2526
}
2627
}
27-
}
28+
}

src/FlaUI.WebDriver/WebDriverResponseException.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ private WebDriverResponseException(string message, string errorCode, int statusC
2424
public static WebDriverResponseException WindowNotFoundByHandle(string windowHandle) => new WebDriverResponseException($"No window found with handle '{windowHandle}'", "no such window", 404);
2525

2626
public static WebDriverResponseException NoWindowsOpenForSession() => new WebDriverResponseException($"No windows are open for the current session", "no such window", 404);
27+
28+
public static WebDriverResponseException Timeout(string message) => new WebDriverResponseException($"Timeout: ${message}", "timeout", 500);
2729
}
2830
}

0 commit comments

Comments
 (0)