diff --git a/Passwordless.sln b/Passwordless.sln index dd09436..1877828 100644 --- a/Passwordless.sln +++ b/Passwordless.sln @@ -32,6 +32,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passwordless.Example", "exa EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passwordless.AspNetIdentity.Example", "examples\Passwordless.AspNetIdentity.Example\Passwordless.AspNetIdentity.Example.csproj", "{F9487727-715D-442F-BE2F-7FB9931606C2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passwordless.Tests.Infra", "tests\Passwordless.Tests.Infra\Passwordless.Tests.Infra.csproj", "{92D2ED44-AC6F-4E10-8300-7E5BFC4890EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passwordless.AspNetCore.Tests.Dummy", "tests\Passwordless.AspNetCore.Tests.Dummy\Passwordless.AspNetCore.Tests.Dummy.csproj", "{9E15DF1C-BD60-4373-9905-C86C16A06553}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -62,6 +66,14 @@ Global {F9487727-715D-442F-BE2F-7FB9931606C2}.Debug|Any CPU.Build.0 = Debug|Any CPU {F9487727-715D-442F-BE2F-7FB9931606C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {F9487727-715D-442F-BE2F-7FB9931606C2}.Release|Any CPU.Build.0 = Release|Any CPU + {92D2ED44-AC6F-4E10-8300-7E5BFC4890EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92D2ED44-AC6F-4E10-8300-7E5BFC4890EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92D2ED44-AC6F-4E10-8300-7E5BFC4890EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92D2ED44-AC6F-4E10-8300-7E5BFC4890EE}.Release|Any CPU.Build.0 = Release|Any CPU + {9E15DF1C-BD60-4373-9905-C86C16A06553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E15DF1C-BD60-4373-9905-C86C16A06553}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E15DF1C-BD60-4373-9905-C86C16A06553}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E15DF1C-BD60-4373-9905-C86C16A06553}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -73,5 +85,7 @@ Global {F64C850E-9923-43F1-BC84-432AFBBA4425} = {8FC08940-3E9D-4AE5-AB1D-940B4D5DC0E6} {15D70E7A-D222-4C60-93B2-06570A2BE5F2} = {6EFECBD2-2BF5-473D-A7C3-A1F3A3F1816A} {F9487727-715D-442F-BE2F-7FB9931606C2} = {6EFECBD2-2BF5-473D-A7C3-A1F3A3F1816A} + {92D2ED44-AC6F-4E10-8300-7E5BFC4890EE} = {8FC08940-3E9D-4AE5-AB1D-940B4D5DC0E6} + {9E15DF1C-BD60-4373-9905-C86C16A06553} = {8FC08940-3E9D-4AE5-AB1D-940B4D5DC0E6} EndGlobalSection EndGlobal diff --git a/examples/Passwordless.AspNetIdentity.Example/Program.cs b/examples/Passwordless.AspNetIdentity.Example/Program.cs index 1abee73..32bfe65 100644 --- a/examples/Passwordless.AspNetIdentity.Example/Program.cs +++ b/examples/Passwordless.AspNetIdentity.Example/Program.cs @@ -24,7 +24,7 @@ // Execute our migrations to generate our `example.db` file with all the required tables. using var scope = app.Services.CreateScope(); -var dbContext = scope.ServiceProvider.GetRequiredService(); +using var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.Database.Migrate(); // Configure the HTTP request pipeline. diff --git a/tests/Passwordless.AspNetCore.Tests.Dummy/Passwordless.AspNetCore.Tests.Dummy.csproj b/tests/Passwordless.AspNetCore.Tests.Dummy/Passwordless.AspNetCore.Tests.Dummy.csproj new file mode 100644 index 0000000..82eae93 --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests.Dummy/Passwordless.AspNetCore.Tests.Dummy.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + + + + + + + + + + + + + + + + diff --git a/tests/Passwordless.AspNetCore.Tests.Dummy/Program.cs b/tests/Passwordless.AspNetCore.Tests.Dummy/Program.cs new file mode 100644 index 0000000..b3a2cb6 --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests.Dummy/Program.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Passwordless.AspNetCore.Tests.Dummy; + +public partial class Program +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + builder.Services.AddDbContext(); + + builder.Services.AddIdentity(o => + { + o.User.RequireUniqueEmail = true; + }) + .AddEntityFrameworkStores() + .AddPasswordless(_ => { }); + + var app = builder.Build(); + + app.MapPasswordless(new PasswordlessEndpointOptions + { + GroupPrefix = "", + RegisterPath = "/register", + LoginPath = "/login" + }); + + app.Run(); + } +} + +public partial class Program +{ + public class PasswordlessDbContext : IdentityDbContext + { + public PasswordlessDbContext(DbContextOptions options) : base(options) + { + Database.EnsureCreated(); + } + + protected override void OnConfiguring(DbContextOptionsBuilder builder) + { + // For some reason, this is required + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + builder.UseSqlite(connection); + } + } +} \ No newline at end of file diff --git a/tests/Passwordless.AspNetCore.Tests/EndpointTests.cs b/tests/Passwordless.AspNetCore.Tests/EndpointTests.cs new file mode 100644 index 0000000..46f4e6b --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests/EndpointTests.cs @@ -0,0 +1,144 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using FluentAssertions; +using Passwordless.AspNetCore.Tests.Infra; +using Xunit; +using Xunit.Abstractions; + +namespace Passwordless.AspNetCore.Tests; + +public class EndpointTests : AppTestBase +{ + public EndpointTests(TestAppFixture app, ITestOutputHelper testOutput) + : base(app, testOutput) + { + } + + [Fact] + public async Task I_can_define_a_register_endpoint() + { + // Arrange + using var http = await App.CreateClientAsync(); + + // Act + using var request = new HttpRequestMessage(HttpMethod.Post, "/register"); + request.Content = new StringContent( + // lang=json + """ + { + "email": "test@passwordless.dev", + "username": "test", + "displayName": "Test User" + } + """, + Encoding.UTF8, + "application/json" + ); + + using var response = await http.SendAsync(request); + var responseJson = await response.Content.ReadFromJsonAsync(); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + responseJson.GetProperty("token").GetString().Should().StartWith("register_"); + } + + [Fact] + public async Task I_can_define_a_register_endpoint_and_it_will_reject_invalid_registration_attempts() + { + // Arrange + using var http = await App.CreateClientAsync(); + + // Act + using var request = new HttpRequestMessage(HttpMethod.Post, "/register"); + request.Content = new StringContent( + // lang=json + """ + { + "email": null + } + """, + Encoding.UTF8, + "application/json" + ); + + using var response = await http.SendAsync(request); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + } + + [Fact(Skip = "Figure out why this fails")] + public async Task I_can_define_a_register_endpoint_and_it_will_reject_duplicate_registration_attempts() + { + // Arrange + using var http = await App.CreateClientAsync(); + + // Act + var responses = new List(); + for (var i = 0; i < 5; i++) + { + using var request = new HttpRequestMessage(HttpMethod.Post, "/register"); + request.Content = new StringContent( + // lang=json + """ + { + "email": "test@passwordless.dev", + "username": "test", + "displayName": "Test User" + } + """, + Encoding.UTF8, + "application/json" + ); + + var response = await http.SendAsync(request); + responses.Add(response); + } + + // Assert + responses.Take(1).Should().OnlyContain(r => r.StatusCode == HttpStatusCode.OK); + responses.Skip(1).Should().OnlyContain(r => r.StatusCode == HttpStatusCode.BadRequest); + } + + [Fact(Skip = "Bug: this currently does not return 400 status code. Task: PAS-260")] + public async Task I_can_define_a_signin_endpoint_and_it_will_reject_invalid_signin_attempts() + { + // Arrange + using var http = await App.CreateClientAsync(); + + const string token = + "verify_" + + "k8Qg4kXVl8D2aunn__jMT7td5endUueS9zEG8zIsu0lqQjfFAQXcABPX_wlDNbBlTNiB2SQ5MjQ0ZmUzYS0wOGExLTRlMTctOTMwZS1i" + + "YWZhNmM0OWJiOGWucGFzc2tleV9zaWduaW7AwMDAwMDA2SQ3NGUxMzFjOS0yNDZhLTRmNzYtYjIxMS1jNzBkZWQ1Mjg2YzLX_wlDJIBl" + + "TNgJv2FkbWluY29uc29sZTAxLmxlc3NwYXNzd29yZC5kZXbZJ2h0dHBzOi8vYWRtaW5jb25zb2xlMDEubGVzc3Bhc3N3b3JkLmRldsOy" + + "Q2hyb21lLCBXaW5kb3dzIDEwolVBqXRlc3Rlc3RzZcQghR4WgXh0HvbrT27GvP0Pkk4HmfL2b0ucVVSRlDElp_fOeb02NQ"; + + // Act + using var request = new HttpRequestMessage(HttpMethod.Post, "/login"); + request.Content = new StringContent( + // lang=json + $$""" + { + "token": "{{token}}" + } + """, + Encoding.UTF8, + "application/json" + ); + + using var response = await http.SendAsync(request); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + } + + // TODO: expand with more tests when magic links endpoint support is added + // https://github.com/bitwarden/passwordless-dotnet/pull/75 +} \ No newline at end of file diff --git a/tests/Passwordless.AspNetCore.Tests/Infra/AppTestBase.cs b/tests/Passwordless.AspNetCore.Tests/Infra/AppTestBase.cs new file mode 100644 index 0000000..4b46307 --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests/Infra/AppTestBase.cs @@ -0,0 +1,26 @@ +using System; +using Xunit; +using Xunit.Abstractions; + +namespace Passwordless.AspNetCore.Tests.Infra; + +[Collection(TestAppFixture.Collection.Name)] +public abstract class AppTestBase : IDisposable +{ + protected TestAppFixture App { get; } + + protected ITestOutputHelper TestOutput { get; } + + protected AppTestBase(TestAppFixture app, ITestOutputHelper testOutput) + { + App = app; + TestOutput = testOutput; + } + + public void Dispose() + { + // Ideally we should route the logs in realtime, but it's a bit tedious + // with the way the TestContainers library is designed. + TestOutput.WriteLine(App.GetLogs()); + } +} \ No newline at end of file diff --git a/tests/Passwordless.AspNetCore.Tests/Infra/TestAppFixture.cs b/tests/Passwordless.AspNetCore.Tests/Infra/TestAppFixture.cs new file mode 100644 index 0000000..c2a5780 --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests/Infra/TestAppFixture.cs @@ -0,0 +1,55 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Passwordless.AspNetCore.Tests.Dummy; +using Passwordless.Tests.Infra; +using Xunit; + +namespace Passwordless.AspNetCore.Tests.Infra; + +// xUnit can't initialize fixture from another assembly, so we have to wrap it +public partial class TestAppFixture : IAsyncLifetime +{ + private readonly TestApi _api = new(); + + public async Task InitializeAsync() => await _api.InitializeAsync(); + + public async Task CreateClientAsync(Action? configure = null) + { + var app = await _api.CreateAppAsync(); + + return new WebApplicationFactory() + .WithWebHostBuilder(c => c + .ConfigureTestServices(s => + { + s.Configure(o => + { + o.ApiUrl = app.ApiUrl; + o.ApiSecret = app.ApiSecret; + o.ApiKey = app.ApiKey; + }); + + configure?.Invoke(s); + }) + ).CreateClient(); + } + + public string GetLogs() => _api.GetLogs(); + + public async Task DisposeAsync() + { + await _api.DisposeAsync(); + } +} + +public partial class TestAppFixture +{ + [CollectionDefinition(Name)] + public class Collection : ICollectionFixture + { + public const string Name = nameof(TestAppFixture); + } +} \ No newline at end of file diff --git a/tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs b/tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs similarity index 99% rename from tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs rename to tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs index 740cfce..3011766 100644 --- a/tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs +++ b/tests/Passwordless.AspNetCore.Tests/OldTests/PasswordlessServiceTests.cs @@ -17,7 +17,7 @@ using Passwordless.Models; using Xunit; -namespace Passwordless.AspNetCore.Tests.Services; +namespace Passwordless.AspNetCore.Tests.OldTests; public class PasswordlessServiceTests { diff --git a/tests/Passwordless.AspNetCore.Tests/OldTests/Readme.md b/tests/Passwordless.AspNetCore.Tests/OldTests/Readme.md new file mode 100644 index 0000000..425fa23 --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests/OldTests/Readme.md @@ -0,0 +1,2 @@ +We currently can't cover all interactions with our integration tests due to limitations in the API. +We should eventually replace these tests, however. \ No newline at end of file diff --git a/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj b/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj index 811ee29..73606ff 100644 --- a/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj +++ b/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj @@ -5,11 +5,16 @@ - - + + + + + + + @@ -19,6 +24,8 @@ + + diff --git a/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs b/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs deleted file mode 100644 index 19311f8..0000000 --- a/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Passwordless.AspNetCore.Services; -using Xunit; - -namespace Passwordless.AspNetCore.Tests; - -public class RegistrationTests -{ - [Fact] - public void AllExpectedServicesAndOptionsResolve() - { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary - { - ["ApiSecret"] = "FakeApiSecret", - ["ApiUrl"] = "https://example.org", - ["SignInScheme"] = "Cookies", - ["Register:Discoverable"] = "false" - }) - .Build(); - - var serviceCollection = new ServiceCollection(); - - serviceCollection.AddDbContext(); - - serviceCollection - .AddIdentity() - .AddEntityFrameworkStores() - .AddPasswordless(configuration); - - var provider = serviceCollection.BuildServiceProvider(); - - _ = provider.GetRequiredService(); - _ = provider.GetRequiredService>(); - var optionsAccessor = provider.GetRequiredService>(); - var options = optionsAccessor.Value; - Assert.Equal("FakeApiSecret", options.ApiSecret); - Assert.Equal("https://example.org", options.ApiUrl); - Assert.Equal("Cookies", options.SignInScheme); - Assert.False(options.Register.Discoverable); - } -} - -public class TestDbContext : IdentityDbContext -{ - -} \ No newline at end of file diff --git a/tests/Passwordless.AspNetCore.Tests/xunit.runner.json b/tests/Passwordless.AspNetCore.Tests/xunit.runner.json new file mode 100644 index 0000000..5ab050c --- /dev/null +++ b/tests/Passwordless.AspNetCore.Tests/xunit.runner.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "methodDisplayOptions": "all", + "methodDisplay": "method" +} \ No newline at end of file diff --git a/tests/Passwordless.Tests.Infra/Passwordless.Tests.Infra.csproj b/tests/Passwordless.Tests.Infra/Passwordless.Tests.Infra.csproj new file mode 100644 index 0000000..1dda393 --- /dev/null +++ b/tests/Passwordless.Tests.Infra/Passwordless.Tests.Infra.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/tests/Passwordless.Tests/Fixtures/TestApiFixture.cs b/tests/Passwordless.Tests.Infra/TestApi.cs similarity index 78% rename from tests/Passwordless.Tests/Fixtures/TestApiFixture.cs rename to tests/Passwordless.Tests.Infra/TestApi.cs index bc818cf..1638cbb 100644 --- a/tests/Passwordless.Tests/Fixtures/TestApiFixture.cs +++ b/tests/Passwordless.Tests.Infra/TestApi.cs @@ -12,11 +12,10 @@ using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Images; using Microsoft.Extensions.DependencyInjection; -using Xunit; -namespace Passwordless.Tests.Fixtures; +namespace Passwordless.Tests.Infra; -public class TestApiFixture : IAsyncLifetime +public class TestApi : IAsyncDisposable { private const string ManagementKey = "yourStrong(!)ManagementKey"; private const ushort ApiPort = 8080; @@ -29,7 +28,7 @@ public class TestApiFixture : IAsyncLifetime private string PublicApiUrl => $"http://{_apiContainer.Hostname}:{_apiContainer.GetMappedPublicPort(ApiPort)}"; - public TestApiFixture() + public TestApi() { _apiContainer = new ContainerBuilder() // https://github.com/passwordless/passwordless-server/pkgs/container/passwordless-test-api @@ -83,13 +82,26 @@ public async Task InitializeAsync() } } - public async Task CreateClientAsync() + public async Task CreateAppAsync() { - using var response = await _http.PostAsJsonAsync( - $"{PublicApiUrl}/admin/apps/app{Guid.NewGuid():N}/create", - new { AdminEmail = "test@passwordless.dev" } + using var request = new HttpRequestMessage( + HttpMethod.Post, + $"{PublicApiUrl}/admin/apps/app{Guid.NewGuid():N}/create" + ); + + request.Content = new StringContent( + // lang=json + """ + { + "adminEmail": "test@passwordless.dev" + } + """, + Encoding.UTF8, + "application/json" ); + using var response = await _http.SendAsync(request); + if (!response.IsSuccessStatusCode) { throw new InvalidOperationException( @@ -103,17 +115,26 @@ public async Task CreateClientAsync() var apiKey = responseContent.GetProperty("apiKey1").GetString(); var apiSecret = responseContent.GetProperty("apiSecret1").GetString(); - var services = new ServiceCollection(); - - services.AddPasswordlessSdk(options => + return new PasswordlessOptions { - options.ApiUrl = PublicApiUrl; - options.ApiKey = apiKey; - options.ApiSecret = apiSecret ?? - throw new InvalidOperationException("Cannot extract API Secret from the response."); - }); + ApiUrl = PublicApiUrl, + ApiKey = apiKey, + ApiSecret = apiSecret ?? + throw new InvalidOperationException("Cannot extract API Secret from the response.") + }; + } - return services.BuildServiceProvider().GetRequiredService(); + public async Task CreateClientAsync() + { + var options = await CreateAppAsync(); + + // Initialize using a service container to cover more code paths + return new ServiceCollection().AddPasswordlessSdk(o => + { + o.ApiUrl = options.ApiUrl; + o.ApiKey = options.ApiKey; + o.ApiSecret = options.ApiSecret; + }).BuildServiceProvider().GetRequiredService(); } public string GetLogs() @@ -138,7 +159,7 @@ public string GetLogs() """; } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { await _apiContainer.DisposeAsync(); _apiContainerStdOut.Dispose(); diff --git a/tests/Passwordless.Tests/Fixtures/TestApiFixtureCollection.cs b/tests/Passwordless.Tests/Fixtures/TestApiFixtureCollection.cs deleted file mode 100644 index 6b67083..0000000 --- a/tests/Passwordless.Tests/Fixtures/TestApiFixtureCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Xunit; - -namespace Passwordless.Tests.Fixtures; - -[CollectionDefinition(nameof(TestApiFixtureCollection))] -public class TestApiFixtureCollection : ICollectionFixture -{ -} \ No newline at end of file diff --git a/tests/Passwordless.Tests/Infra/ApiTestBase.cs b/tests/Passwordless.Tests/Infra/ApiTestBase.cs index d8a84c4..e4373de 100644 --- a/tests/Passwordless.Tests/Infra/ApiTestBase.cs +++ b/tests/Passwordless.Tests/Infra/ApiTestBase.cs @@ -1,11 +1,10 @@ using System; -using Passwordless.Tests.Fixtures; using Xunit; using Xunit.Abstractions; namespace Passwordless.Tests.Infra; -[Collection(nameof(TestApiFixtureCollection))] +[Collection(TestApiFixture.Collection.Name)] public abstract class ApiTestBase : IDisposable { protected TestApiFixture Api { get; } diff --git a/tests/Passwordless.Tests/Infra/TestApiFixture.cs b/tests/Passwordless.Tests/Infra/TestApiFixture.cs new file mode 100644 index 0000000..344aa9d --- /dev/null +++ b/tests/Passwordless.Tests/Infra/TestApiFixture.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Xunit; + +namespace Passwordless.Tests.Infra; + +// xUnit can't initialize fixture from another assembly, so we have to wrap it +public partial class TestApiFixture : TestApi, IAsyncLifetime +{ + async Task IAsyncLifetime.DisposeAsync() => await base.DisposeAsync(); +} + +public partial class TestApiFixture +{ + [CollectionDefinition(Name)] + public class Collection : ICollectionFixture + { + public const string Name = nameof(TestApiFixture); + } +} \ No newline at end of file diff --git a/tests/Passwordless.Tests/Passwordless.Tests.csproj b/tests/Passwordless.Tests/Passwordless.Tests.csproj index 9e10365..d95da88 100644 --- a/tests/Passwordless.Tests/Passwordless.Tests.csproj +++ b/tests/Passwordless.Tests/Passwordless.Tests.csproj @@ -18,13 +18,14 @@ - + + diff --git a/tests/Passwordless.Tests/TokenTests.cs b/tests/Passwordless.Tests/TokenTests.cs index d4be8ec..1106b30 100644 --- a/tests/Passwordless.Tests/TokenTests.cs +++ b/tests/Passwordless.Tests/TokenTests.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using FluentAssertions; -using Passwordless.Tests.Fixtures; using Passwordless.Tests.Infra; using Xunit; using Xunit.Abstractions; diff --git a/tests/Passwordless.Tests/UserTests.cs b/tests/Passwordless.Tests/UserTests.cs index fef3122..4686879 100644 --- a/tests/Passwordless.Tests/UserTests.cs +++ b/tests/Passwordless.Tests/UserTests.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using FluentAssertions; -using Passwordless.Tests.Fixtures; using Passwordless.Tests.Infra; using Xunit; using Xunit.Abstractions;