diff --git a/src/GraphiQl/GraphiQlExtensions.cs b/src/GraphiQl/GraphiQlExtensions.cs
index 3f1242c..66b4d3d 100644
--- a/src/GraphiQl/GraphiQlExtensions.cs
+++ b/src/GraphiQl/GraphiQlExtensions.cs
@@ -3,80 +3,75 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Options;
namespace GraphiQl
{
public static class GraphiQlExtensions
{
- private const string DefaultPath = "/graphql";
+ private const string DefaultGraphQlPath = "/graphql";
- public static IApplicationBuilder UseGraphiQl(this IApplicationBuilder app)
- => UseGraphiQl(app, DefaultPath);
-
- public static IApplicationBuilder UseGraphiQl(this IApplicationBuilder app, string path)
- => UseGraphiQl(app, path, null);
+ public static IServiceCollection AddGraphiQl(this IServiceCollection services)
+ => services.AddGraphiQl(null);
- ///
- /// In some scenarios it makes sense to specify the API path and file server path independently
- /// Examples: hosting in IIS in a virtual application (myapp.com/1.0/...) or hosting API and documentation separately
- public static IApplicationBuilder UseGraphiQl(this IApplicationBuilder app, string path, string apiPath)
+ public static IServiceCollection AddGraphiQl(this IServiceCollection services, Action configure)
{
- if (string.IsNullOrWhiteSpace(path))
- throw new ArgumentException(nameof(path));
+ if (configure != null)
+ {
+ services.Configure(configure);
+ }
+
+ services.TryAdd(ServiceDescriptor.Transient, GraphiQlOptionsSetup>());
+
+ return services;
+ }
- if (path.EndsWith("/"))
- throw new ArgumentException("GraphiQL path must not end in a slash", nameof(path));
+ public static IApplicationBuilder UseGraphiQl(this IApplicationBuilder app)
+ {
+ var options = app.ApplicationServices.GetService>().Value;
- var filePath = $"{path}/graphql-path.js";
- var uri = !string.IsNullOrWhiteSpace(apiPath) ? apiPath : path;
- app.Map(filePath, x => WritePathJavaScript(x, uri));
+ var filePath = $"{options.GraphiQlPath.TrimEnd('/')}/graphql-path.js";
+ var graphQlPath = !string.IsNullOrWhiteSpace(options.GraphQlApiPath) ? options.GraphQlApiPath : DefaultGraphQlPath;
+ app.Map(filePath, x => WritePathJavaScript(x, graphQlPath));
- return UseGraphiQlImp(app, x => x.SetPath(path));
+ return UseGraphiQlImp(app, options);
}
- private static IApplicationBuilder UseGraphiQlImp(this IApplicationBuilder app, Action setConfig)
+ private static IApplicationBuilder UseGraphiQlImp(this IApplicationBuilder app, GraphiQlOptions options)
{
if (app == null)
throw new ArgumentNullException(nameof(app));
- if (setConfig == null)
- throw new ArgumentNullException(nameof(setConfig));
-
- var config = new GraphiQlConfig();
- setConfig(config);
var fileServerOptions = new FileServerOptions
{
- RequestPath = config.Path,
- FileProvider = BuildFileProvider(),
+ RequestPath = options.GraphiQlPath,
+ FileProvider = new EmbeddedFileProvider(typeof(GraphiQlExtensions).GetTypeInfo().Assembly, "GraphiQl.assets"),
EnableDefaultFiles = true,
StaticFileOptions = {ContentTypeProvider = new FileExtensionContentTypeProvider()}
};
+ app.UseMiddleware();
app.UseFileServer(fileServerOptions);
return app;
}
- private static IFileProvider BuildFileProvider()
- {
- var assembly = typeof(GraphiQlExtensions).GetTypeInfo().Assembly;
- var embeddedFileProvider = new EmbeddedFileProvider(assembly, "GraphiQl.assets");
-
- var fileProvider = new CompositeFileProvider(
- embeddedFileProvider
- );
-
- return fileProvider;
- }
-
- private static void WritePathJavaScript(IApplicationBuilder app, string path)
- {
+ private static void WritePathJavaScript(IApplicationBuilder app, string path) =>
app.Run(h =>
{
h.Response.ContentType = "application/javascript";
return h.Response.WriteAsync($"var graphqlPath='{path}';");
});
- }
+
+ [Obsolete("This overload has been marked as obsolete, please configure via IServiceCollection.AddGraphiQl(..) instead or consult the documentation", true)]
+ public static IApplicationBuilder UseGraphiQl(this IApplicationBuilder app, string path)
+ => throw new NotImplementedException();
+
+ [Obsolete("This overload has been marked as obsolete, please configure via IServiceCollection.AddGraphiQl(..) instead or consult the documentation", true)]
+ public static IApplicationBuilder UseGraphiQl(this IApplicationBuilder app, string path, string apiPath)
+ => throw new NotImplementedException();
}
}
\ No newline at end of file
diff --git a/src/GraphiQl/GraphiQlMiddleware.cs b/src/GraphiQl/GraphiQlMiddleware.cs
new file mode 100644
index 0000000..d177f48
--- /dev/null
+++ b/src/GraphiQl/GraphiQlMiddleware.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+
+namespace GraphiQl
+{
+ public class GraphiQlMiddleware
+ {
+ private readonly RequestDelegate _next;
+ private readonly GraphiQlOptions _options;
+
+ public GraphiQlMiddleware(RequestDelegate next, IOptions options)
+ {
+ _next = next;
+ _options = options.Value;
+ }
+
+ public async Task Invoke(HttpContext context)
+ {
+ if (context.Request.Path.Equals(_options.GraphiQlPath, StringComparison.OrdinalIgnoreCase)
+ && _options.IsAuthenticated != null
+ && !await _options.IsAuthenticated.Invoke(context))
+ {
+ return;
+ }
+
+ await _next(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GraphiQl/GraphiQlOptions.cs b/src/GraphiQl/GraphiQlOptions.cs
new file mode 100644
index 0000000..decb0c3
--- /dev/null
+++ b/src/GraphiQl/GraphiQlOptions.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+
+namespace GraphiQl
+{
+ public class GraphiQlOptions
+ {
+ public string GraphiQlPath { get; set; }
+
+ public string GraphQlApiPath { get; set; }
+
+ public Func> IsAuthenticated { get; set; }
+
+ public GraphiQlOptions()
+ {
+ GraphiQlPath = "/graphql";
+ GraphQlApiPath = "/graphql";
+ }
+ }
+
+ public class GraphiQlOptionsSetup : IConfigureOptions
+ {
+ public void Configure(GraphiQlOptions options)
+ {
+ if (options.GraphiQlPath == null)
+ {
+ options.GraphiQlPath = "/graphql";
+ }
+
+ if (options.GraphQlApiPath == null)
+ {
+ options.GraphQlApiPath = "/graphql";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Demo/Controllers/GraphQlController.cs b/tests/GraphiQl.Demo/Controllers/GraphQlController.cs
index a7ea569..12255e7 100644
--- a/tests/GraphiQl.Demo/Controllers/GraphQlController.cs
+++ b/tests/GraphiQl.Demo/Controllers/GraphQlController.cs
@@ -8,6 +8,7 @@
namespace GraphiQl.Demo.Controllers
{
[Route(Startup.GraphQlPath)]
+ [Route(Startup.CustomGraphQlPath)]
public class GraphQlController : Controller
{
[HttpPost]
diff --git a/tests/GraphiQl.Demo/GraphiQl.Demo.csproj b/tests/GraphiQl.Demo/GraphiQl.Demo.csproj
index c5434be..57ce1f0 100644
--- a/tests/GraphiQl.Demo/GraphiQl.Demo.csproj
+++ b/tests/GraphiQl.Demo/GraphiQl.Demo.csproj
@@ -2,9 +2,6 @@
netcoreapp3.1
-
-
-
diff --git a/tests/GraphiQl.Demo/Startup.cs b/tests/GraphiQl.Demo/Startup.cs
index b9b83b6..e95d259 100644
--- a/tests/GraphiQl.Demo/Startup.cs
+++ b/tests/GraphiQl.Demo/Startup.cs
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -11,6 +10,7 @@ namespace GraphiQl.Demo
public class Startup
{
public const string GraphQlPath = "/graphql";
+ public const string CustomGraphQlPath = "/custom-path";
public Startup(IConfiguration configuration)
{
@@ -19,6 +19,9 @@ public Startup(IConfiguration configuration)
public IConfiguration Configuration { get; }
+ public virtual void ConfigureGraphQl(IServiceCollection services)
+ => services.AddGraphiQl();
+
public void ConfigureServices(IServiceCollection services)
{
services
@@ -26,19 +29,13 @@ public void ConfigureServices(IServiceCollection services)
.AddNewtonsoftJson(
options => options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore
);
+
+ ConfigureGraphQl(services);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
-
- /*
- app.Run(async context =>
- {
- await context.Response.WriteAsync("Hello, World!");
- });
- */
-
- app.UseGraphiQl(GraphQlPath);
+ app.UseGraphiQl();
app.UseRouting().UseEndpoints(
routing => routing.MapControllers()
);
diff --git a/tests/GraphiQl.Tests/AuthenticationTest/ConfigureOptionsSetup.cs b/tests/GraphiQl.Tests/AuthenticationTest/ConfigureOptionsSetup.cs
new file mode 100644
index 0000000..3d02176
--- /dev/null
+++ b/tests/GraphiQl.Tests/AuthenticationTest/ConfigureOptionsSetup.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using GraphiQl.Demo;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Shouldly;
+using Xunit;
+
+namespace GraphiQl.Tests.AuthenticationTest
+{
+ public class ConfigureOptionsSetup : SeleniumTest, IAsyncLifetime
+ {
+ private readonly IWebHost _host;
+
+ public ConfigureOptionsSetup()
+ {
+ _host = WebHost.CreateDefaultBuilder()
+ .ConfigureServices(x => { x.AddTransient,GraphiQlTestOptionsSetup>(); })
+ .UseStartup()
+ .UseKestrel()
+ .UseUrls("http://*:5001")
+ .Build();
+ }
+
+ [Fact]
+ public void RequiresAuthentication()
+ {
+ // Arrange + Act
+ var result = string.Empty;
+ RunTest(driver =>
+ {
+ driver.Navigate().GoToUrl("http://localhost:5001/graphql");
+
+ driver.Manage()
+ .Timeouts()
+ .ImplicitWait = TimeSpan.FromSeconds(2);
+
+ result = driver.PageSource;
+ });
+
+ // Assert
+ result.ShouldContain("This page requires authentication");
+ }
+
+ public async Task InitializeAsync()
+ => await _host.StartAsync().ConfigureAwait(false);
+
+ public Task DisposeAsync()
+ {
+ _host.Dispose();
+ return Task.CompletedTask;
+ }
+
+ internal class GraphiQlTestOptionsSetup : IConfigureOptions
+ {
+ public void Configure(GraphiQlOptions options)
+ {
+ options.IsAuthenticated = context =>
+ {
+ context.Response.Clear();
+ context.Response.StatusCode = 400;
+ context.Response.WriteAsync("This page requires authentication");
+
+ return Task.FromResult(false);
+ };
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/AuthenticationTest/DelegateSetup.cs b/tests/GraphiQl.Tests/AuthenticationTest/DelegateSetup.cs
new file mode 100644
index 0000000..c291f28
--- /dev/null
+++ b/tests/GraphiQl.Tests/AuthenticationTest/DelegateSetup.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using GraphiQl.Demo;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Shouldly;
+using Xunit;
+
+namespace GraphiQl.Tests.AuthenticationTest
+{
+ public class CustomStartup : Startup
+ {
+ public CustomStartup(IConfiguration configuration) : base(configuration) {}
+
+ public override void ConfigureGraphQl(IServiceCollection services)
+ => services.AddGraphiQl(x => x.IsAuthenticated = context =>
+ {
+ context.Response.Clear();
+ context.Response.StatusCode = 400;
+ context.Response.WriteAsync("This page requires authentication");
+
+ return Task.FromResult(false);
+ });
+ }
+
+ public class DelegateSetup : SeleniumTest, IAsyncLifetime
+ {
+ private readonly IWebHost _host;
+
+ public DelegateSetup()
+ {
+ _host = WebHost.CreateDefaultBuilder()
+ .UseStartup()
+ .UseKestrel()
+ .UseUrls("http://*:5001")
+ .Build();
+ }
+
+ [Fact]
+ public void RequiresAuthentication()
+ {
+ // Arrange + Act
+ var result = string.Empty;
+ RunTest(driver =>
+ {
+ driver.Navigate().GoToUrl("http://localhost:5001/graphql");
+
+ driver.Manage()
+ .Timeouts()
+ .ImplicitWait = TimeSpan.FromSeconds(2);
+
+ result = driver.PageSource;
+ });
+
+ // Assert
+ result.ShouldContain("This page requires authentication");
+ }
+
+ public async Task InitializeAsync()
+ => await _host.StartAsync().ConfigureAwait(false);
+
+ public Task DisposeAsync()
+ {
+ _host.Dispose();
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/GraphQlTests.cs b/tests/GraphiQl.Tests/BasicTest.cs
similarity index 62%
rename from tests/GraphiQl.Tests/GraphQlTests.cs
rename to tests/GraphiQl.Tests/BasicTest.cs
index ef15eb8..d7671cc 100644
--- a/tests/GraphiQl.Tests/GraphQlTests.cs
+++ b/tests/GraphiQl.Tests/BasicTest.cs
@@ -1,23 +1,23 @@
using System;
using System.Text.Json;
-using System.Threading.Tasks;
+using System.Threading;
using GraphiQl.Tests.Fixtures;
using Shouldly;
using Xunit;
namespace GraphiQl.Tests
{
- public class GraphQlTests : BaseTest, IClassFixture
+ public class BasicTest : SeleniumTest, IClassFixture
{
private readonly HostFixture _fixture;
- public GraphQlTests(HostFixture fixture) : base(runHeadless: true)
+ public BasicTest(HostFixture fixture)
{
_fixture = fixture;
}
[Fact]
- public async Task CanQueryGraphQl()
+ public void CanQueryGraphQl()
{
// TODO: Use PageModel
@@ -26,17 +26,17 @@ public async Task CanQueryGraphQl()
var query = @"{hero{id,name}}";
// Act
- await RunTest(async driver =>
+ RunTest( driver =>
{
- Driver.Navigate().GoToUrl(_fixture.GraphiQlUri + Uri.EscapeDataString(query));
- var button = Driver.FindElementByClassName("execute-button");
+ driver.Navigate().GoToUrl(_fixture.GraphiQlUri + Uri.EscapeDataString(query));
+ var button = driver.FindElementByClassName("execute-button");
button?.Click();
-
- await Task.Delay(2000);
+
+ //TODO: https://www.selenium.dev/documentation/en/webdriver/waits/
+ Thread.Sleep(2000);
// UGH!
- result = Driver
- .FindElementByClassName("result-window").Text
+ result = driver.FindElementByClassName("result-window").Text
.Replace("\n", "")
.Replace(" ", "");
});
diff --git a/tests/GraphiQl.Tests/Fixtures/GraphQlFixture.cs b/tests/GraphiQl.Tests/Fixtures/GraphQlFixture.cs
index 49ff1b1..91960be 100644
--- a/tests/GraphiQl.Tests/Fixtures/GraphQlFixture.cs
+++ b/tests/GraphiQl.Tests/Fixtures/GraphQlFixture.cs
@@ -45,7 +45,7 @@ public IWebHost CreateWebHostOld()
})
.Configure(app =>
{
- app.UseGraphiQl("/graphql");
+ app.UseGraphiQl();
app.UseRouting().UseEndpoints(routing => routing.MapControllers());
});
diff --git a/tests/GraphiQl.Tests/Fixtures/HostFixture.cs b/tests/GraphiQl.Tests/Fixtures/HostFixture.cs
index 1e13942..a716bfb 100644
--- a/tests/GraphiQl.Tests/Fixtures/HostFixture.cs
+++ b/tests/GraphiQl.Tests/Fixtures/HostFixture.cs
@@ -21,39 +21,13 @@ public HostFixture()
.Build();
}
- /*
- public IWebHost Build()
- {
- var config = new ConfigurationBuilder().Build();
- var host = new WebHostBuilder()
- .UseConfiguration(config)
- .UseKestrel()
- .UseUrls("http://*:5001")
- .ConfigureServices(s =>
- {
- s.AddMvc()
- .AddNewtonsoftJson(o =>
- o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
- s.AddControllers()
- .PartManager.ApplicationParts.Add(new AssemblyPart(typeof(GraphQlController).Assembly));
- })
- .Configure(app =>
- {
- app.UseGraphiQl("/graphql");
- app.UseRouting().UseEndpoints(routing => routing.MapControllers());
- });
-
- return host.Build();
- }
- */
-
public async Task InitializeAsync()
=> await _host.StartAsync().ConfigureAwait(false);
- public Task DisposeAsync()
+ public async Task DisposeAsync()
{
+ await _host.StopAsync().ConfigureAwait(false);
_host.Dispose();
- return Task.CompletedTask;
}
}
}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/GraphiQl.Tests.csproj b/tests/GraphiQl.Tests/GraphiQl.Tests.csproj
index 925f409..bcc4f04 100644
--- a/tests/GraphiQl.Tests/GraphiQl.Tests.csproj
+++ b/tests/GraphiQl.Tests/GraphiQl.Tests.csproj
@@ -1,4 +1,4 @@
-
+
netcoreapp3.1
diff --git a/tests/GraphiQl.Tests/OverrideGraphQlPathTests/ConfigureOptionsSetup.cs b/tests/GraphiQl.Tests/OverrideGraphQlPathTests/ConfigureOptionsSetup.cs
new file mode 100644
index 0000000..9c6adae
--- /dev/null
+++ b/tests/GraphiQl.Tests/OverrideGraphQlPathTests/ConfigureOptionsSetup.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using GraphiQl.Demo;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Shouldly;
+using Xunit;
+
+namespace GraphiQl.Tests.OverrideGraphQlPathTests
+{
+ public class ConfigureOptionsSetup : SeleniumTest, IAsyncLifetime
+ {
+ private readonly IWebHost _host;
+
+ public ConfigureOptionsSetup()
+ {
+ _host = WebHost.CreateDefaultBuilder()
+ .ConfigureServices(serviceCollection =>
+ {
+ serviceCollection.AddTransient, GraphiQlTestOptionsSetup>();
+ })
+ .UseStartup()
+ .UseKestrel()
+ .UseUrls("http://*:5001")
+ .Build();
+ }
+
+ public async Task InitializeAsync()
+ => await _host.StartAsync().ConfigureAwait(false);
+
+ [Fact]
+ public void CanOverrideGraphQlPath()
+ {
+ // TODO: Use PageModel
+
+ // Arrange
+ var result = string.Empty;
+ var query = @"{hero{id,name}}";
+
+ // Act
+ RunTest( driver =>
+ {
+ driver.Navigate().GoToUrl($"http://localhost:5001/graphql?query=" + Uri.EscapeDataString(query));
+ var button = driver.FindElementByClassName("execute-button");
+ button?.Click();
+
+ Thread.Sleep(2000);
+
+ /*
+ var x = Driver.FindElement(B)
+ var foo = new WebDriverWait(driver, TimeSpan.FromSeconds(3))
+ .Until(drv => drv.FindElement(By.Name("q")));
+ */
+
+ // UGH!
+ result = driver
+ .FindElementByClassName("result-window").Text
+ .Replace("\n", "")
+ .Replace(" ", "");
+ });
+
+ // Assert
+ using var channelResponse = JsonDocument.Parse(result);
+ var data = channelResponse.RootElement.GetProperty("data");
+
+ data.GetProperty("hero").GetProperty("name").GetString().ShouldBe("R2-D2");
+ }
+
+ public async Task DisposeAsync()
+ {
+ await _host.StopAsync();
+ _host.Dispose();
+ }
+
+ internal class GraphiQlTestOptionsSetup : IConfigureOptions
+ {
+ public void Configure(GraphiQlOptions options)
+ {
+ options.GraphQlApiPath = Startup.CustomGraphQlPath;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/OverrideGraphQlPathTests/DelegateSetup.cs b/tests/GraphiQl.Tests/OverrideGraphQlPathTests/DelegateSetup.cs
new file mode 100644
index 0000000..9e14d37
--- /dev/null
+++ b/tests/GraphiQl.Tests/OverrideGraphQlPathTests/DelegateSetup.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Text.Json;
+using System.Threading.Tasks;
+using GraphiQl.Demo;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Shouldly;
+using Xunit;
+
+namespace GraphiQl.Tests.OverrideGraphQlPathTests
+{
+ public class CustomStartup : Startup
+ {
+ public CustomStartup(IConfiguration configuration) : base(configuration) {}
+
+ public override void ConfigureGraphQl(IServiceCollection services)
+ => services.AddGraphiQl(x => x.GraphQlApiPath = CustomGraphQlPath);
+ }
+
+ public class DelegateSetup : SeleniumTest, IAsyncLifetime
+ {
+ private readonly IWebHost _host;
+
+ public DelegateSetup()
+ {
+ _host = WebHost.CreateDefaultBuilder()
+ .UseStartup()
+ .UseKestrel()
+ .UseUrls("http://*:5001")
+ .Build();
+ }
+
+ public async Task InitializeAsync()
+ => await _host.StartAsync().ConfigureAwait(false);
+
+ [Fact]
+ public void CanOverrideGraphQlPath()
+ {
+ // TODO: Use PageModel
+
+ // Arrange
+ var result = string.Empty;
+ var query = @"{hero{id,name}}";
+
+ // Act
+ RunTest( driver =>
+ {
+ driver.Navigate().GoToUrl("http://localhost:5001/graphql?query=" + Uri.EscapeDataString(query));
+ var button = driver.FindElementByClassName("execute-button");
+ button?.Click();
+
+ driver.Manage()
+ .Timeouts()
+ .ImplicitWait = TimeSpan.FromSeconds(2);
+
+ // UGH!
+ result = driver
+ .FindElementByClassName("result-window").Text
+ .Replace("\n", "")
+ .Replace(" ", "");
+ });
+
+ // Assert
+ using var channelResponse = JsonDocument.Parse(result);
+ var data = channelResponse.RootElement.GetProperty("data");
+
+ data.GetProperty("hero").GetProperty("name").GetString().ShouldBe("R2-D2");
+ }
+
+ public async Task DisposeAsync()
+ {
+ await _host.StopAsync();
+ _host.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/OverrideGraphiQlPathTests/ConfigureOptionsSetup.cs b/tests/GraphiQl.Tests/OverrideGraphiQlPathTests/ConfigureOptionsSetup.cs
new file mode 100644
index 0000000..5d9ed1d
--- /dev/null
+++ b/tests/GraphiQl.Tests/OverrideGraphiQlPathTests/ConfigureOptionsSetup.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using GraphiQl.Demo;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Shouldly;
+using Xunit;
+
+namespace GraphiQl.Tests.OverrideGraphiQlPathTests
+{
+ public class ConfigureOptionsSetup : SeleniumTest, IAsyncLifetime
+ {
+ private readonly IWebHost _host;
+
+ public ConfigureOptionsSetup()
+ {
+ _host = WebHost.CreateDefaultBuilder()
+ .ConfigureServices(serviceCollection =>
+ {
+ serviceCollection.AddTransient, GraphiQlTestOptionsSetup>();
+ })
+ .UseStartup()
+ .UseKestrel()
+ .UseUrls("http://*:5001")
+ .Build();
+ }
+
+ public async Task InitializeAsync()
+ => await _host.StartAsync().ConfigureAwait(false);
+
+ [Fact]
+ public void CanOverrideGraphiQlPath()
+ {
+ // TODO: Use PageModel
+
+ // Arrange
+ var result = string.Empty;
+ var query = @"{hero{id,name}}";
+
+ // Act
+ RunTest( driver =>
+ {
+ driver.Navigate().GoToUrl($"http://localhost:5001{Startup.CustomGraphQlPath}?query=" + Uri.EscapeDataString(query));
+ var button = driver.FindElementByClassName("execute-button");
+ button?.Click();
+
+ Thread.Sleep(2000);
+
+ // UGH!
+ result = driver
+ .FindElementByClassName("result-window").Text
+ .Replace("\n", "")
+ .Replace(" ", "");
+ });
+
+ // Assert
+ using var channelResponse = JsonDocument.Parse(result);
+ var data = channelResponse.RootElement.GetProperty("data");
+
+ data.GetProperty("hero").GetProperty("name").GetString().ShouldBe("R2-D2");
+ }
+
+ public async Task DisposeAsync()
+ {
+ await _host.StopAsync();
+ _host.Dispose();
+ }
+
+ internal class GraphiQlTestOptionsSetup : IConfigureOptions
+ {
+ public void Configure(GraphiQlOptions options)
+ {
+ options.GraphiQlPath = Startup.CustomGraphQlPath;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/OverrideGraphiQlPathTests/DelegateSetup.cs b/tests/GraphiQl.Tests/OverrideGraphiQlPathTests/DelegateSetup.cs
new file mode 100644
index 0000000..78b2260
--- /dev/null
+++ b/tests/GraphiQl.Tests/OverrideGraphiQlPathTests/DelegateSetup.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using GraphiQl.Demo;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Shouldly;
+using Xunit;
+
+namespace GraphiQl.Tests.OverrideGraphiQlPathTests
+{
+ public class CustomStartup : Startup
+ {
+ public CustomStartup(IConfiguration configuration) : base(configuration) {}
+
+ public override void ConfigureGraphQl(IServiceCollection services)
+ => services.AddGraphiQl(x => x.GraphiQlPath = CustomGraphQlPath);
+ }
+
+ public class DelegateSetup : SeleniumTest, IAsyncLifetime
+ {
+ private readonly IWebHost _host;
+
+ public DelegateSetup()
+ {
+ _host = WebHost.CreateDefaultBuilder()
+ .UseStartup()
+ .UseKestrel()
+ .UseUrls("http://*:5001")
+ .Build();
+ }
+
+ public async Task InitializeAsync()
+ => await _host.StartAsync().ConfigureAwait(false);
+
+ [Fact]
+ public void CanOverrideGraphiQlPath()
+ {
+ // TODO: Use PageModel
+
+ // Arrange
+ var result = string.Empty;
+ var query = @"{hero{id,name}}";
+
+ // Act
+ RunTest( driver =>
+ {
+ driver.Navigate().GoToUrl($"http://localhost:5001{Startup.CustomGraphQlPath}?query=" + Uri.EscapeDataString(query));
+ var button = driver.FindElementByClassName("execute-button");
+ button?.Click();
+
+ driver.Manage()
+ .Timeouts()
+ .ImplicitWait = TimeSpan.FromSeconds(2);
+
+ // UGH!
+ result = driver
+ .FindElementByClassName("result-window").Text
+ .Replace("\n", "")
+ .Replace(" ", "");
+ });
+
+ // Assert
+ using var channelResponse = JsonDocument.Parse(result);
+ var data = channelResponse.RootElement.GetProperty("data");
+
+ data.GetProperty("hero").GetProperty("name").GetString().ShouldBe("R2-D2");
+ }
+
+ public async Task DisposeAsync()
+ {
+ await _host.StopAsync();
+ _host.Dispose();
+ }
+
+ internal class GraphiQlTestOptionsSetup : IConfigureOptions
+ {
+ public void Configure(GraphiQlOptions options)
+ {
+ options.GraphiQlPath = Startup.CustomGraphQlPath;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/GraphiQl.Tests/BaseTest.cs b/tests/GraphiQl.Tests/SeleniumTest.cs
similarity index 53%
rename from tests/GraphiQl.Tests/BaseTest.cs
rename to tests/GraphiQl.Tests/SeleniumTest.cs
index dcd1de0..b1f04dd 100644
--- a/tests/GraphiQl.Tests/BaseTest.cs
+++ b/tests/GraphiQl.Tests/SeleniumTest.cs
@@ -1,39 +1,39 @@
using System;
-using System.Threading.Tasks;
+using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
namespace GraphiQl.Tests
{
- public abstract class BaseTest
+ public abstract class SeleniumTest
{
- protected ChromeDriver Driver { get; }
+ private ChromeDriver Driver { get; }
+ protected bool RunHeadless { get; set; } = true;
- protected BaseTest(bool runHeadless)
+ protected SeleniumTest()
{
var options = new ChromeOptions();
- options.AddArgument("--remote-debugging-port=9222");
options.AddArgument("--disable-dev-shm-usage");
options.AddArgument("--no-sandbox");
- if (runHeadless)
+ if (RunHeadless)
options.AddArgument("--headless");
Driver = new ChromeDriver(options);
}
- protected async Task RunTest(Func execute)
+ protected void RunTest(Action execute)
{
try
{
- await execute(Driver);
+ execute(Driver);
}
- catch (Exception)
+ catch (Exception ex)
{
- throw;
+ throw ex;
}
finally
{
- Driver.Close();
+ Driver.Quit();
}
}
}
diff --git a/tests/GraphiQl.Tests/xunit.runner.json b/tests/GraphiQl.Tests/xunit.runner.json
new file mode 100644
index 0000000..369786b
--- /dev/null
+++ b/tests/GraphiQl.Tests/xunit.runner.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
+ "parallelizeTestCollections": false
+}
\ No newline at end of file