public async Task Can_create_OneToOne_relationship_from_principal_side() { // Arrange WorkItemGroup existingGroup = _fakers.WorkItemGroup.Generate(); existingGroup.Color = _fakers.RgbColor.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Groups.Add(existingGroup); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "workItemGroups", relationships = new { color = new { data = new { type = "rgbColors", id = existingGroup.Color.StringId } } } } }; const string route = "/workItemGroups"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes.Should().NotBeEmpty(); responseDocument.SingleData.Relationships.Should().NotBeEmpty(); string newGroupId = responseDocument.SingleData.Id; newGroupId.Should().NotBeNullOrEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { List <WorkItemGroup> groupsInDatabase = await dbContext.Groups.Include(group => group.Color).ToListAsync(); WorkItemGroup newGroupInDatabase = groupsInDatabase.Single(group => group.StringId == newGroupId); newGroupInDatabase.Color.Should().NotBeNull(); newGroupInDatabase.Color.Id.Should().Be(existingGroup.Color.Id); WorkItemGroup existingGroupInDatabase = groupsInDatabase.Single(group => group.Id == existingGroup.Id); existingGroupInDatabase.Color.Should().BeNull(); }); }
public async Task Can_create_user_with_password() { // Arrange var user = _fakers.User.Generate(); var serializer = GetRequestSerializer <User>(p => new { p.Password, p.UserName }); string requestBody = serializer.Serialize(user); var route = "/api/v1/users"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); var responseUser = GetResponseDeserializer().DeserializeSingle <User>(responseDocument).Data; var document = JsonConvert.DeserializeObject <Document>(responseDocument); document.SingleData.Attributes.Should().NotContainKey("password"); document.SingleData.Attributes["userName"].Should().Be(user.UserName); await _testContext.RunOnDatabaseAsync(async dbContext => { var userInDatabase = await dbContext.Users.FirstAsync(u => u.Id == responseUser.Id); userInDatabase.UserName.Should().Be(user.UserName); userInDatabase.Password.Should().Be(user.Password); }); }
public async Task Cannot_create_resource_with_omitted_required_attribute() { // Arrange var requestBody = new { data = new { type = "systemDirectories", attributes = new { isCaseSensitive = true } } }; const string route = "/systemDirectories"; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecutePostAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.UnprocessableEntity); responseDocument.Errors.Should().HaveCount(1); Error error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity); error.Title.Should().Be("Input validation failed."); error.Detail.Should().Be("The Name field is required."); error.Source.Pointer.Should().Be("/data/attributes/name"); }
public async Task Cannot_create_dependent_side_of_required_ManyToOne_relationship_without_providing_principal_side() { // Arrange var order = _fakers.Orders.Generate(); var requestBody = new { data = new { type = "orders", attributes = new { order = order.Amount } } }; const string route = "/orders"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.InternalServerError); responseDocument.Errors.Should().HaveCount(1); var error = responseDocument.Errors[0]; error.StatusCode.Should().Be(HttpStatusCode.InternalServerError); error.Title.Should().Be("An unhandled error occurred while processing this request."); error.Detail.Should().Be("Failed to persist changes in the underlying data store."); }
public async Task Permits_no_Accept_headers_at_operations_endpoint() { // Arrange var requestBody = new { atomic__operations = new[] { new { op = "add", data = new { type = "policies", attributes = new { name = "some" } } } } }; const string route = "/operations"; const string contentType = HeaderConstants.AtomicOperationsMediaType; // Act (HttpResponseMessage httpResponse, _) = await _testContext.ExecutePostAsync <ErrorDocument>(route, requestBody, contentType); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.OK); }
public async Task Denies_unknown_ContentType_header() { // Arrange var requestBody = new { data = new { type = "policies", attributes = new { name = "some" } } }; var route = "/policies"; var contentType = "text/html"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <ErrorDocument>(route, requestBody, contentType); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.UnsupportedMediaType); responseDocument.Errors.Should().HaveCount(1); responseDocument.Errors[0].StatusCode.Should().Be(HttpStatusCode.UnsupportedMediaType); responseDocument.Errors[0].Title.Should().Be("The specified Content-Type header value is not supported."); responseDocument.Errors[0].Detail.Should().Be("Please specify 'application/vnd.api+json' instead of 'text/html' for the Content-Type header value."); }
public async Task Sets_location_header_for_created_resource() { // Arrange WorkItem newWorkItem = _fakers.WorkItem.Generate(); var requestBody = new { data = new { type = "workItems", attributes = new { description = newWorkItem.Description } } }; const string route = "/workItems"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); string newWorkItemId = responseDocument.SingleData.Id; httpResponse.Headers.Location.Should().Be("/workItems/" + newWorkItemId); responseDocument.Links.Self.Should().Be("http://localhost/workItems"); responseDocument.Links.First.Should().BeNull(); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Links.Self.Should().Be("http://localhost" + httpResponse.Headers.Location); }
public async Task Can_create_resource_with_inherited_attributes() { // Arrange var man = new Man { FamilyName = "Smith", IsRetired = true, HasBeard = true }; var requestBody = new { data = new { type = "men", attributes = new { familyName = man.FamilyName, isRetired = man.IsRetired, hasBeard = man.HasBeard } } }; var route = "/men"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Type.Should().Be("men"); responseDocument.SingleData.Attributes["familyName"].Should().Be(man.FamilyName); responseDocument.SingleData.Attributes["isRetired"].Should().Be(man.IsRetired); responseDocument.SingleData.Attributes["hasBeard"].Should().Be(man.HasBeard); var newManId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { var manInDatabase = await dbContext.Men .FirstAsync(m => m.Id == newManId); manInDatabase.FamilyName.Should().Be(man.FamilyName); manInDatabase.IsRetired.Should().Be(man.IsRetired); manInDatabase.HasBeard.Should().Be(man.HasBeard); }); }
public async Task Decrypts_on_create_resource() { // Arrange var encryptionService = _testContext.Factory.Services.GetRequiredService <IEncryptionService>(); var hitCounter = _testContext.Factory.Services.GetRequiredService <SerializationHitCounter>(); string newName = _fakers.Student.Generate().Name; string newSocialSecurityNumber = _fakers.Student.Generate().SocialSecurityNumber; var requestBody = new { data = new { type = "students", attributes = new { name = newName, socialSecurityNumber = encryptionService.Encrypt(newSocialSecurityNumber) } } }; const string route = "/students"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); string socialSecurityNumber = encryptionService.Decrypt((string)responseDocument.SingleData.Attributes["socialSecurityNumber"]); socialSecurityNumber.Should().Be(newSocialSecurityNumber); int newStudentId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { Student studentInDatabase = await dbContext.Students.FirstWithIdAsync(newStudentId); studentInDatabase.SocialSecurityNumber.Should().Be(newSocialSecurityNumber); }); hitCounter.DeserializeCount.Should().Be(1); hitCounter.SerializeCount.Should().Be(1); }
public async Task Create_resource_with_side_effects_and_include_returns_relative_links() { // Arrange var existingPhoto = _fakers.Photo.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.Photos.Add(existingPhoto); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "photoAlbums", relationships = new { photos = new { data = new[] { new { type = "photos", id = existingPhoto.StringId } } } } } }; var route = "/api/photoAlbums?include=photos"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.Links.Self.Should().Be("/api/photoAlbums?include=photos"); responseDocument.Links.Related.Should().BeNull(); responseDocument.Links.First.Should().BeNull(); responseDocument.Links.Last.Should().BeNull(); responseDocument.Links.Prev.Should().BeNull(); responseDocument.Links.Next.Should().BeNull(); var newAlbumId = responseDocument.SingleData.Id; responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Links.Self.Should().Be($"/api/photoAlbums/{newAlbumId}"); responseDocument.SingleData.Relationships["photos"].Links.Self.Should().Be($"/api/photoAlbums/{newAlbumId}/relationships/photos"); responseDocument.SingleData.Relationships["photos"].Links.Related.Should().Be($"/api/photoAlbums/{newAlbumId}/photos"); responseDocument.Included.Should().HaveCount(1); responseDocument.Included[0].Links.Self.Should().Be($"/api/photos/{existingPhoto.StringId}"); responseDocument.Included[0].Relationships["album"].Links.Self.Should().Be($"/api/photos/{existingPhoto.StringId}/relationships/album"); responseDocument.Included[0].Relationships["album"].Links.Related.Should().Be($"/api/photos/{existingPhoto.StringId}/album"); }
public async Task Cannot_create_resource() { // Arrange var requestBody = new { data = new { type = "beds", attributes = new { } } }; var route = "/beds"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <ErrorDocument>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.MethodNotAllowed); responseDocument.Errors.Should().HaveCount(1); responseDocument.Errors[0].StatusCode.Should().Be(HttpStatusCode.MethodNotAllowed); responseDocument.Errors[0].Title.Should().Be("The request method is not allowed."); responseDocument.Errors[0].Detail.Should().Be("Resource does not support POST requests."); }
public async Task Can_create_resource_with_invalid_attribute_value() { // Arrange var requestBody = new { data = new { type = "systemDirectories", attributes = new { name = "!@#$%^&*().-", isCaseSensitive = "false" } } }; const string route = "/systemDirectories"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes["name"].Should().Be("!@#$%^&*().-"); }
public async Task Returns_no_ETag_for_POST_request() { // Arrange string newTitle = _fakers.Meeting.Generate().Title; var requestBody = new { data = new { type = "meetings", attributes = new { title = newTitle } } }; const string route = "/meetings"; // Act (HttpResponseMessage httpResponse, string responseDocument) = await _testContext.ExecutePostAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); httpResponse.Headers.ETag.Should().BeNull(); responseDocument.Should().NotBeEmpty(); }
public async Task Hides_resource_count_in_create_resource_response() { // Arrange var newDescription = _fakers.SupportTicket.Generate().Description; var requestBody = new { data = new { type = "supportTickets", attributes = new { description = newDescription } } }; var route = "/supportTickets"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.Meta.Should().BeNull(); }
public async Task Can_create_in_valid_stage() { // Arrange var requestBody = new { data = new { type = "workflows", attributes = new { stage = WorkflowStage.Created } } }; const string route = "/workflows"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); }
public async Task Can_create_unarchived_resource() { // Arrange TelevisionBroadcast newBroadcast = _fakers.TelevisionBroadcast.Generate(); var requestBody = new { data = new { type = "televisionBroadcasts", attributes = new { title = newBroadcast.Title, airedAt = newBroadcast.AiredAt } } }; const string route = "/televisionBroadcasts"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes["title"].Should().Be(newBroadcast.Title); responseDocument.SingleData.Attributes["airedAt"].Should().BeCloseTo(newBroadcast.AiredAt); responseDocument.SingleData.Attributes["archivedAt"].Should().BeNull(); }
public async Task Can_create_resource_with_client_generated_guid_ID_having_side_effects() { // Arrange var newGroup = _fakers.WorkItemGroup.Generate(); newGroup.Id = Guid.NewGuid(); var requestBody = new { data = new { type = "workItemGroups", id = newGroup.StringId, attributes = new { name = newGroup.Name } } }; var route = "/workItemGroups"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Type.Should().Be("workItemGroups"); responseDocument.SingleData.Id.Should().Be(newGroup.StringId); responseDocument.SingleData.Attributes["name"].Should().Be(newGroup.Name); responseDocument.SingleData.Relationships.Should().NotBeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var groupInDatabase = await dbContext.Groups .FirstAsync(group => group.Id == newGroup.Id); groupInDatabase.Name.Should().Be(newGroup.Name); }); var property = typeof(WorkItemGroup).GetProperty(nameof(Identifiable.Id)); property.Should().NotBeNull().And.Subject.PropertyType.Should().Be(typeof(Guid)); }
public async Task Can_create_resource_with_zero_ID() { // Arrange var newTitle = _fakers.Game.Generate().Title; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Game>(); }); var requestBody = new { data = new { type = "games", id = "0", attributes = new { title = newTitle } } }; var route = "/games"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); httpResponse.Headers.Location.Should().Be("/games/0"); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Id.Should().Be("0"); await _testContext.RunOnDatabaseAsync(async dbContext => { var gameInDatabase = await dbContext.Games .FirstAsync(game => game.Id == 0); gameInDatabase.Should().NotBeNull(); gameInDatabase.Title.Should().Be(newTitle); }); }
public async Task Can_create_resource() { // Arrange var newPool = _fakers.SwimmingPool.Generate(); var requestBody = new { data = new { type = "swimming-pools", attributes = new Dictionary <string, object> { ["is-indoor"] = newPool.IsIndoor } } }; const string route = "/public-api/swimming-pools"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Type.Should().Be("swimming-pools"); responseDocument.SingleData.Attributes["is-indoor"].Should().Be(newPool.IsIndoor); var newPoolId = int.Parse(responseDocument.SingleData.Id); string poolLink = route + $"/{newPoolId}"; responseDocument.SingleData.Relationships.Should().NotBeEmpty(); responseDocument.SingleData.Relationships["water-slides"].Links.Self.Should().Be(poolLink + "/relationships/water-slides"); responseDocument.SingleData.Relationships["water-slides"].Links.Related.Should().Be(poolLink + "/water-slides"); responseDocument.SingleData.Relationships["diving-boards"].Links.Self.Should().Be(poolLink + "/relationships/diving-boards"); responseDocument.SingleData.Relationships["diving-boards"].Links.Related.Should().Be(poolLink + "/diving-boards"); await _testContext.RunOnDatabaseAsync(async dbContext => { var poolInDatabase = await dbContext.SwimmingPools.FirstWithIdAsync(newPoolId); poolInDatabase.IsIndoor.Should().Be(newPool.IsIndoor); }); }
public async Task Can_create_resource_with_empty_ID() { // Arrange var newName = _fakers.Map.Generate().Name; await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Map>(); }); var requestBody = new { data = new { type = "maps", id = "00000000-0000-0000-0000-000000000000", attributes = new { name = newName } } }; var route = "/maps"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); httpResponse.Headers.Location.Should().Be("/maps/00000000-0000-0000-0000-000000000000"); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var mapInDatabase = await dbContext.Maps .FirstAsync(map => map.Id == Guid.Empty); mapInDatabase.Should().NotBeNull(); mapInDatabase.Name.Should().Be(newName); }); }
public async Task Can_create_resource() { // Arrange Building newBuilding = _fakers.Building.Generate(); var requestBody = new { data = new { type = "buildings", attributes = new { number = newBuilding.Number } } }; const string route = "/buildings"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes["number"].Should().Be(newBuilding.Number); responseDocument.SingleData.Attributes["windowCount"].Should().Be(0); responseDocument.SingleData.Attributes["primaryDoorColor"].Should().BeNull(); responseDocument.SingleData.Attributes["secondaryDoorColor"].Should().BeNull(); int newBuildingId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { // @formatter:wrap_chained_method_calls chop_always // @formatter:keep_existing_linebreaks true Building buildingInDatabase = await dbContext.Buildings .Include(building => building.PrimaryDoor) .Include(building => building.SecondaryDoor) .Include(building => building.Windows) .FirstWithIdOrDefaultAsync(newBuildingId); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore buildingInDatabase.Should().NotBeNull(); buildingInDatabase.Number.Should().Be(newBuilding.Number); buildingInDatabase.PrimaryDoor.Should().NotBeNull(); buildingInDatabase.SecondaryDoor.Should().BeNull(); buildingInDatabase.Windows.Should().BeEmpty(); }); }
public async Task Can_create_resource() { // Arrange await _testContext.RunOnDatabaseAsync(async dbContext => { await dbContext.ClearTableAsync <Car>(); }); var requestBody = new { data = new { type = "cars", attributes = new { regionId = 123, licensePlate = "AA-BB-11" } } }; const string route = "/cars"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.NoContent); responseDocument.Should().BeEmpty(); await _testContext.RunOnDatabaseAsync(async dbContext => { var carInDatabase = await dbContext.Cars .FirstOrDefaultAsync(car => car.RegionId == 123 && car.LicensePlate == "AA-BB-11"); carInDatabase.Should().NotBeNull(); carInDatabase.Id.Should().Be("123:AA-BB-11"); }); }
public async Task Logs_request_body_at_Trace_level() { // Arrange var loggerFactory = _testContext.Factory.Services.GetRequiredService <FakeLoggerFactory>(); loggerFactory.Logger.Clear(); var newEntry = _fakers.AuditEntry.Generate(); var requestBody = new { data = new { type = "auditEntries", attributes = new { userName = newEntry.UserName, createdAt = newEntry.CreatedAt } } }; // Arrange const string route = "/auditEntries"; // Act var(httpResponse, _) = await _testContext.ExecutePostAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); loggerFactory.Logger.Messages.Should().NotBeEmpty(); loggerFactory.Logger.Messages.Should().ContainSingle(message => message.LogLevel == LogLevel.Trace && message.Text.StartsWith("Received request at 'http://localhost/auditEntries' with body: <<", StringComparison.Ordinal)); }
public async Task Can_create_resource() { // Arrange var newBuilding = _fakers.Building.Generate(); var requestBody = new { data = new { type = "buildings", attributes = new { number = newBuilding.Number } } }; var route = "/buildings"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes["number"].Should().Be(newBuilding.Number); responseDocument.SingleData.Attributes["windowCount"].Should().Be(0); responseDocument.SingleData.Attributes["primaryDoorColor"].Should().BeNull(); responseDocument.SingleData.Attributes["secondaryDoorColor"].Should().BeNull(); var newId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { var buildingInDatabase = await dbContext.Buildings .Include(building => building.PrimaryDoor) .Include(building => building.SecondaryDoor) .Include(building => building.Windows) .FirstOrDefaultAsync(building => building.Id == newId); buildingInDatabase.Should().NotBeNull(); buildingInDatabase.Number.Should().Be(newBuilding.Number); buildingInDatabase.PrimaryDoor.Should().NotBeNull(); buildingInDatabase.SecondaryDoor.Should().BeNull(); buildingInDatabase.Windows.Should().BeEmpty(); }); }
public async Task Can_create_resource() { // Arrange var requestBody = new { data = new { type = "chairs", attributes = new { } } }; var route = "/chairs"; // Act var(httpResponse, _) = await _testContext.ExecutePostAsync <string>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); }
public async Task Can_create_resource() { // Arrange string newShopUrl = _fakers.WebShop.Generate().Url; var requestBody = new { data = new { type = "webShops", attributes = new { url = newShopUrl } } }; const string route = "/nld/shops"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes["url"].Should().Be(newShopUrl); responseDocument.SingleData.Relationships.Should().NotBeNull(); int newShopId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { WebShop shopInDatabase = await dbContext.WebShops.IgnoreQueryFilters().FirstWithIdAsync(newShopId); shopInDatabase.Url.Should().Be(newShopUrl); shopInDatabase.TenantId.Should().Be(ThisTenantId); }); }
public async Task Cannot_add_to_HasOne_relationship() { // Arrange WorkItem existingWorkItem = _fakers.WorkItem.Generate(); UserAccount existingUserAccount = _fakers.UserAccount.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.AddRange(existingWorkItem, existingUserAccount); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "userAccounts", id = existingUserAccount.StringId } }; string route = $"/workItems/{existingWorkItem.StringId}/relationships/assignee"; // Act (HttpResponseMessage httpResponse, ErrorDocument responseDocument) = await _testContext.ExecutePostAsync <ErrorDocument>(route, requestBody); // 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("Only to-many relationships can be updated through this endpoint."); error.Detail.Should().Be("Relationship 'assignee' must be a to-many relationship."); }
public async Task Can_create_HasMany_relationship() { // Arrange var existingUserAccounts = _fakers.UserAccount.Generate(2); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.UserAccounts.AddRange(existingUserAccounts); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "workItems", relationships = new { subscribers = new { data = new[] { new { type = "userAccounts", id = existingUserAccounts[0].StringId }, new { type = "userAccounts", id = existingUserAccounts[1].StringId } } } } } }; var route = "/workItems"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes.Should().NotBeEmpty(); responseDocument.SingleData.Relationships.Should().NotBeEmpty(); responseDocument.Included.Should().BeNull(); var newWorkItemId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { var workItemInDatabase = await dbContext.WorkItems .Include(workItem => workItem.Subscribers) .FirstAsync(workItem => workItem.Id == newWorkItemId); workItemInDatabase.Subscribers.Should().HaveCount(2); workItemInDatabase.Subscribers.Should().ContainSingle(subscriber => subscriber.Id == existingUserAccounts[0].Id); workItemInDatabase.Subscribers.Should().ContainSingle(subscriber => subscriber.Id == existingUserAccounts[1].Id); }); }
public async Task Can_create_resource_with_relationship() { // Arrange var existingBankAccount = _fakers.BankAccount.Generate(); var newDebitCard = _fakers.DebitCard.Generate(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.BankAccounts.Add(existingBankAccount); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "debitCards", attributes = new { ownerName = newDebitCard.OwnerName, pinCode = newDebitCard.PinCode }, relationships = new { account = new { data = new { type = "bankAccounts", id = existingBankAccount.StringId } } } } }; var route = "/debitCards"; // Act var(httpResponse, responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Attributes["ownerName"].Should().Be(newDebitCard.OwnerName); responseDocument.SingleData.Attributes["pinCode"].Should().Be(newDebitCard.PinCode); var newDebitCardId = HexadecimalCodec.Decode(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { var debitCardInDatabase = await dbContext.DebitCards .Include(debitCard => debitCard.Account) .FirstAsync(debitCard => debitCard.Id == newDebitCardId); debitCardInDatabase.OwnerName.Should().Be(newDebitCard.OwnerName); debitCardInDatabase.PinCode.Should().Be(newDebitCard.PinCode); debitCardInDatabase.Account.Should().NotBeNull(); debitCardInDatabase.Account.Id.Should().Be(existingBankAccount.Id); debitCardInDatabase.Account.StringId.Should().Be(existingBankAccount.StringId); }); }
public async Task Can_create_resource_with_ToOne_relationship_and_include() { // Arrange var clock = (FrozenSystemClock)_testContext.Factory.Services.GetRequiredService <ISystemClock>(); clock.UtcNow = 19.March(1998).At(6, 34); PostOffice existingOffice = _fakers.PostOffice.Generate(); var newIssueDate = 18.March(1997).ToDateTimeOffset(); await _testContext.RunOnDatabaseAsync(async dbContext => { dbContext.PostOffice.Add(existingOffice); await dbContext.SaveChangesAsync(); }); var requestBody = new { data = new { type = "giftCertificates", attributes = new { issueDate = newIssueDate }, relationships = new { issuer = new { data = new { type = "postOffices", id = existingOffice.StringId } } } } }; const string route = "/giftCertificates?include=issuer"; // Act (HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecutePostAsync <Document>(route, requestBody); // Assert httpResponse.Should().HaveStatusCode(HttpStatusCode.Created); responseDocument.SingleData.Should().NotBeNull(); responseDocument.SingleData.Attributes["issueDate"].Should().BeCloseTo(newIssueDate); responseDocument.SingleData.Attributes["hasExpired"].Should().Be(true); responseDocument.SingleData.Relationships["issuer"].SingleData.Id.Should().Be(existingOffice.StringId); responseDocument.Included.Should().HaveCount(1); responseDocument.Included[0].Id.Should().Be(existingOffice.StringId); responseDocument.Included[0].Attributes["address"].Should().Be(existingOffice.Address); responseDocument.Included[0].Attributes["isOpen"].Should().Be(false); int newCertificateId = int.Parse(responseDocument.SingleData.Id); await _testContext.RunOnDatabaseAsync(async dbContext => { GiftCertificate certificateInDatabase = await dbContext.GiftCertificates .Include(certificate => certificate.Issuer).FirstWithIdAsync(newCertificateId); certificateInDatabase.IssueDate.Should().Be(newIssueDate); certificateInDatabase.Issuer.Should().NotBeNull(); certificateInDatabase.Issuer.Id.Should().Be(existingOffice.Id); }); }