public async Task Can_filter_by_empty_ID_on_primary_resources() { // Arrange var maps = _fakers.Map.Generate(2); maps[0].Id = Guid.Empty; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Map>(); dbContext.Maps.AddRange(maps); await dbContext.SaveChangesAsync(); }); const string route = "/maps?filter=equals(id,'00000000-0000-0000-0000-000000000000')"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be("00000000-0000-0000-0000-000000000000"); responseDocument.ManyData[0].Links.Self.Should().Be("/maps/00000000-0000-0000-0000-000000000000"); }
public async Task Can_get_resource_at_custom_route() { // Arrange Town town = _fakers.Town.Generate(); town.Civilians = _fakers.Civilian.Generate(1).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Towns.Add(town); await dbContext.SaveChangesAsync(); }); string route = "/world-api/civilization/popular/towns/" + town.StringId; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Type.Should().Be("towns"); responseDocument.SingleData.Id.Should().Be(town.StringId); responseDocument.SingleData.Attributes["name"].Should().Be(town.Name); responseDocument.SingleData.Attributes["latitude"].Should().Be(town.Latitude); responseDocument.SingleData.Attributes["longitude"].Should().Be(town.Longitude); responseDocument.SingleData.Relationships["civilians"].Links.Self.Should().Be(HostPrefix + route + "/relationships/civilians"); responseDocument.SingleData.Relationships["civilians"].Links.Related.Should().Be(HostPrefix + route + "/civilians"); responseDocument.SingleData.Links.Self.Should().Be(HostPrefix + route); responseDocument.Links.Self.Should().Be(HostPrefix + route); }
public async Task Returns_ETag_for_GET_request() { // Arrange List <Meeting> meetings = _fakers.Meeting.Generate(2); await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Meeting>(); dbContext.Meetings.AddRange(meetings); await dbContext.SaveChangesAsync(); }); const string route = "/meetings"; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecuteGetAsync <string>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); httpResponse.Headers.ETag.Should().NotBeNull(); httpResponse.Headers.ETag.IsWeak.Should().BeFalse(); httpResponse.Headers.ETag.Tag.Should().NotBeNullOrEmpty(); responseDocument.Should().NotBeEmpty(); }
public async Task Can_filter_by_zero_ID_on_primary_resources() { // Arrange var games = _fakers.Game.Generate(2); games[0].Id = 0; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Game>(); dbContext.Games.AddRange(games); await dbContext.SaveChangesAsync(); }); var route = "/games?filter=equals(id,'0')"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be("0"); responseDocument.ManyData[0].Links.Self.Should().Be("/games/0"); }
public async Task Can_get_resource_by_ID() { // Arrange var clock = (FrozenSystemClock)_testContext.Factory.Services.GetRequiredService <ISystemClock>(); clock.UtcNow = 27.January(2021); GiftCertificate certificate = _fakers.GiftCertificate.Generate(); certificate.IssueDate = 28.January(2020); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.GiftCertificates.Add(certificate); await dbContext.SaveChangesAsync(); }); string route = "/giftCertificates/" + certificate.StringId; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Id.Should().Be(certificate.StringId); responseDocument.SingleData.Attributes["issueDate"].Should().BeCloseTo(certificate.IssueDate); responseDocument.SingleData.Attributes["hasExpired"].Should().Be(false); }
public async Task Cannot_use_unknown_query_string_parameter() { // Arrange var options = (JsonApiOptions)_testContext.Factory.Services.GetRequiredService <IJsonApiOptions>(); options.AllowUnknownQueryStringParameters = false; const string route = "/calendars?foo=bar"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.BadRequest); responseDocument.Errors.Should().HaveCount(1); var error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.BadRequest); error.Title.Should().Be("Unknown query string parameter."); error.Detail.Should().Be("Query string parameter 'foo' is unknown. " + "Set 'AllowUnknownQueryStringParameters' to 'true' in options to ignore unknown parameters."); error.Source.Parameter.Should().Be("foo"); }
public async Task Can_get_primary_resource_with_eager_loads() { // Arrange Building building = _fakers.Building.Generate(); building.Windows = _fakers.Window.Generate(4); building.PrimaryDoor = _fakers.Door.Generate(); building.SecondaryDoor = _fakers.Door.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Buildings.Add(building); await dbContext.SaveChangesAsync(); }); string route = "/buildings/" + building.StringId; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Id.Should().Be(building.StringId); responseDocument.SingleData.Attributes["number"].Should().Be(building.Number); responseDocument.SingleData.Attributes["windowCount"].Should().Be(4); responseDocument.SingleData.Attributes["primaryDoorColor"].Should().Be(building.PrimaryDoor.Color); responseDocument.SingleData.Attributes["secondaryDoorColor"].Should().Be(building.SecondaryDoor.Color); }
public async Task Can_filter_on_ID_in_primary_resources() { // Arrange var car = new Car { RegionId = 123, LicensePlate = "AA-BB-11" }; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Car>(); dbContext.Cars.Add(car); await dbContext.SaveChangesAsync(); }); const string route = "/cars?filter=any(id,'123:AA-BB-11','999:XX-YY-22')"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be(car.StringId); }
public async Task Get_primary_resources_hides_other_tenants() { // Arrange List <WebShop> shops = _fakers.WebShop.Generate(2); shops[0].TenantId = OtherTenantId; shops[1].TenantId = ThisTenantId; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <WebShop>(); dbContext.WebShops.AddRange(shops); await dbContext.SaveChangesAsync(); }); const string route = "/nld/shops"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be(shops[1].StringId); }
public async Task Can_get_resource_at_custom_route() { // Arrange var town = _fakers.Town.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Towns.Add(town); await dbContext.SaveChangesAsync(); }); var route = "/world-api/civilization/popular/towns/" + town.StringId; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Type.Should().Be("towns"); responseDocument.SingleData.Id.Should().Be(town.StringId); responseDocument.SingleData.Attributes["name"].Should().Be(town.Name); responseDocument.SingleData.Attributes["latitude"].Should().Be(town.Latitude); responseDocument.SingleData.Attributes["longitude"].Should().Be(town.Longitude); responseDocument.SingleData.Relationships["civilians"].Links.Self.Should().Be($"http://localhost/world-api/civilization/popular/towns/{town.Id}/relationships/civilians"); responseDocument.SingleData.Relationships["civilians"].Links.Related.Should().Be($"http://localhost/world-api/civilization/popular/towns/{town.Id}/civilians"); responseDocument.SingleData.Links.Self.Should().Be($"http://localhost/world-api/civilization/popular/towns/{town.Id}"); responseDocument.Links.Self.Should().Be($"http://localhost/world-api/civilization/popular/towns/{town.Id}"); }
public async Task Returns_resource_meta_from_ResourceDefinition() { // Arrange List <SupportTicket> tickets = _fakers.SupportTicket.Generate(3); tickets[0].Description = "Critical: " + tickets[0].Description; tickets[2].Description = "Critical: " + tickets[2].Description; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <SupportTicket>(); dbContext.SupportTickets.AddRange(tickets); await dbContext.SaveChangesAsync(); }); const string route = "/supportTickets"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(3); responseDocument.ManyData[0].Meta.Should().ContainKey("hasHighPriority"); responseDocument.ManyData[1].Meta.Should().BeNull(); responseDocument.ManyData[2].Meta.Should().ContainKey("hasHighPriority"); }
public async Task Can_get_primary_resources() { // Arrange var departments = new List <Department> { new Department { Name = "Sales", IsSoftDeleted = true }, new Department { Name = "Marketing" } }; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Department>(); dbContext.Departments.AddRange(departments); await dbContext.SaveChangesAsync(); }); const string route = "/departments"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be(departments[1].StringId); }
public async Task Can_get_HasOne_relationship() { var workItem = _fakers.WorkItem.Generate(); workItem.Assignee = _fakers.UserAccount.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.WorkItems.Add(workItem); await dbContext.SaveChangesAsync(); }); var route = $"/workItems/{workItem.StringId}/relationships/assignee"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Type.Should().Be("userAccounts"); responseDocument.SingleData.Id.Should().Be(workItem.Assignee.StringId); responseDocument.SingleData.Attributes.Should().BeNull(); responseDocument.SingleData.Relationships.Should().BeNull(); }
public async Task Can_filter_equality_on_type(string propertyName, object value) { // Arrange var resource = new FilterableResource(); var property = typeof(FilterableResource).GetProperty(propertyName); property?.SetValue(resource, value); await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <FilterableResource>(); dbContext.FilterableResources.AddRange(resource, new FilterableResource()); await dbContext.SaveChangesAsync(); }); var attributeName = propertyName.Camelize(); var route = $"/filterableResources?filter=equals({attributeName},'{value}')"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Attributes[attributeName].Should().Be(value is Enum ? value.ToString() : value); }
public async Task Permits_no_Accept_headers() { // Arrange const string route = "/policies"; // Act (HttpResponseMessage httpResponse, _) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); }
public async Task Can_use_page_number_below_maximum() { // Arrange const int pageNumber = MaximumPageNumber - 1; string route = "/blogs?page[number]=" + pageNumber; // Act (HttpResponseMessage httpResponse, _) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); }
public async Task Permits_no_Accept_headers() { // Arrange var route = "/policies"; var acceptHeaders = new MediaTypeWithQualityHeaderValue[0]; // Act var(httpResponse, _) = await _testContext.ExecuteGetAsync <Document>(route, acceptHeaders); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); }
public async Task Can_use_Queryable_handler_on_resource_endpoint() { // Arrange var musicTracks = _fakers.MusicTrack.Generate(3); musicTracks[0].ReleasedAt = FrozenTime.AddMonths(5); musicTracks[1].ReleasedAt = FrozenTime.AddMonths(-5); musicTracks[2].ReleasedAt = FrozenTime.AddMonths(-1); await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <MusicTrack>(); dbContext.MusicTracks.AddRange(musicTracks); await dbContext.SaveChangesAsync(); }); const string route = "/musicTracks?isRecentlyReleased=true"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be(musicTracks[2].StringId); }
public async Task Encrypts_on_get_primary_resources() { // Arrange var encryptionService = _testContext.Factory.Services.GetRequiredService <IEncryptionService>(); var hitCounter = _testContext.Factory.Services.GetRequiredService <ResourceDefinitionHitCounter>(); List <Student> students = _fakers.Student.Generate(2); await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Student>(); dbContext.Students.AddRange(students); await dbContext.SaveChangesAsync(); }); const string route = "/students"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(2); string socialSecurityNumber1 = encryptionService.Decrypt((string)responseDocument.ManyData[0].Attributes["socialSecurityNumber"]); socialSecurityNumber1.Should().Be(students[0].SocialSecurityNumber); string socialSecurityNumber2 = encryptionService.Decrypt((string)responseDocument.ManyData[1].Attributes["socialSecurityNumber"]); socialSecurityNumber2.Should().Be(students[1].SocialSecurityNumber); hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
public async Task Returns_top_level_meta() { // Arrange await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <SupportTicket>(); }); const string route = "/supportTickets"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <string>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.Should().BeJson(@"{ ""meta"": { ""license"": ""MIT"", ""projectUrl"": ""https://github.com/json-api-dotnet/JsonApiDotNetCore/"", ""versions"": [ ""v4.0.0"", ""v3.1.0"", ""v2.5.2"", ""v1.3.1"" ] }, ""links"": { ""self"": ""http://localhost/supportTickets"", ""first"": ""http://localhost/supportTickets"" }, ""data"": [] }"); }
public async Task Cannot_filter_in_unknown_scope() { // Arrange var route = "/webAccounts?filter[doesNotExist]=equals(title,null)"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.BadRequest); responseDocument.Errors.Should().HaveCount(1); responseDocument.Errors[0].StatusCode.Should().Be(HttpStatusCode.BadRequest); responseDocument.Errors[0].Title.Should().Be("The specified filter is invalid."); responseDocument.Errors[0].Detail.Should().Be("Relationship 'doesNotExist' does not exist on resource 'webAccounts'."); responseDocument.Errors[0].Source.Parameter.Should().Be("filter[doesNotExist]"); }
public async Task Cannot_sort_if_query_string_parameter_is_blocked_by_controller() { // Arrange var route = "/sofas?sort=id"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.BadRequest); responseDocument.Errors.Should().HaveCount(1); responseDocument.Errors[0].StatusCode.Should().Be(HttpStatusCode.BadRequest); responseDocument.Errors[0].Title.Should().Be("Usage of one or more query string parameters is not allowed at the requested endpoint."); responseDocument.Errors[0].Detail.Should().Be("The parameter 'sort' cannot be used at this endpoint."); responseDocument.Errors[0].Source.Parameter.Should().Be("sort"); }
public async Task Get_primary_resources_with_include_returns_links() { // Arrange ArtGallery gallery = _fakers.ArtGallery.Generate(); gallery.Paintings = _fakers.Painting.Generate(1).ToHashSet(); await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <ArtGallery>(); dbContext.ArtGalleries.Add(gallery); await dbContext.SaveChangesAsync(); }); const string route = "/iis-application-virtual-directory/public-api/artGalleries?include=paintings"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.Links.Self.Should().Be(HostPrefix + route); responseDocument.Links.Related.Should().BeNull(); responseDocument.Links.First.Should().Be(HostPrefix + route); responseDocument.Links.Last.Should().Be(HostPrefix + route); responseDocument.Links.Prev.Should().BeNull(); responseDocument.Links.Next.Should().BeNull(); string galleryLink = HostPrefix + $"/iis-application-virtual-directory/public-api/artGalleries/{gallery.StringId}"; responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Links.Self.Should().Be(galleryLink); responseDocument.ManyData[0].Relationships["paintings"].Links.Self.Should().Be(galleryLink + "/relationships/paintings"); responseDocument.ManyData[0].Relationships["paintings"].Links.Related.Should().Be(galleryLink + "/paintings"); // TODO: The next link is wrong: it should use the custom route. // https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/956 string paintingLink = HostPrefix + $"/iis-application-virtual-directory/public-api/paintings/{gallery.Paintings.ElementAt(0).StringId}"; responseDocument.Included.Should().HaveCount(1); responseDocument.Included[0].Links.Self.Should().Be(paintingLink); responseDocument.Included[0].Relationships["exposedAt"].Links.Self.Should().Be(paintingLink + "/relationships/exposedAt"); responseDocument.Included[0].Relationships["exposedAt"].Links.Related.Should().Be(paintingLink + "/exposedAt"); }
public async Task Get_primary_resources_excludes_soft_deleted() { // Arrange List <Department> departments = _fakers.Department.Generate(2); departments[0].SoftDeletedAt = SoftDeletionTime; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Department>(); dbContext.Departments.AddRange(departments); await dbContext.SaveChangesAsync(); }); const string route = "/departments"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); responseDocument.ManyData.Should().HaveCount(1); responseDocument.ManyData[0].Id.Should().Be(departments[1].StringId); }
public async Task Can_block_access_to_resource_from_GetSingle_endpoint_using_BeforeRead_hook() { // Arrange const string route = "/api/v1/todoItems/1337"; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Forbidden); responseDocument.Errors.Should().HaveCount(1); Error error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.Forbidden); error.Title.Should().Be("You are not allowed to update the author of todo items."); error.Detail.Should().BeNull(); }
public async Task Can_get_resources() { // Arrange var route = "/chairs"; // Act var(httpResponse, _) = await _testContext.ExecuteGetAsync <string>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); }
public async Task Can_get_resources() { // Arrange const string route = "/tables"; // Act (HttpResponseMessage httpResponse, _) = await _testContext.ExecuteGetAsync <string>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); }
public async Task Cannot_use_negative_page_number() { // Arrange const string route = "/blogs?page[number]=-1"; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.BadRequest); responseDocument.Errors.Should().HaveCount(1); Error error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.BadRequest); error.Title.Should().Be("The specified paging is invalid."); error.Detail.Should().Be("Page number cannot be negative or zero."); error.Source.Parameter.Should().Be("page[number]"); }
public async Task Returns_JsonApi_ContentType_header() { // Arrange var route = "/policies"; // Act var(httpResponse, _) = await _testContext.ExecuteGetAsync <Document>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); httpResponse.Content.Headers.ContentType.ToString().Should().Be(HeaderConstants.MediaType); }
public async Task Cannot_override_from_query_string() { // Arrange var options = (JsonApiOptions)_testContext.Factory.Services.GetRequiredService <IJsonApiOptions>(); options.AllowQueryStringOverrideForSerializerNullValueHandling = false; var route = "/calendars?nulls=true"; // Act var(httpResponse, responseDocument) = await _testContext.ExecuteGetAsync <ErrorDocument>(route); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.BadRequest); responseDocument.Errors.Should().HaveCount(1); responseDocument.Errors[0].StatusCode.Should().Be(HttpStatusCode.BadRequest); responseDocument.Errors[0].Title.Should().Be("Usage of one or more query string parameters is not allowed at the requested endpoint."); responseDocument.Errors[0].Detail.Should().Be("The parameter 'nulls' cannot be used at this endpoint."); responseDocument.Errors[0].Source.Parameter.Should().Be("nulls"); }