amplify-swift/AmplifyPlugins/API/Tests/APIHostApp/AWSAPIPluginFunctionalTests/GraphQLConnectionScenario5T...

273 lines
10 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import XCTest
@testable import AWSAPIPlugin
@testable import Amplify
@testable import APIHostApp
/*
(Many-to-many) Using two one-to-many connections, an @key, and a joining @model, you can create a many-to-many
connection.
```
type Post5 @model {
id: ID!
title: String!
editors: [PostEditor5] @connection(keyName: "byPost5", fields: ["id"])
}
# Create a join model
type PostEditor5
@model
@key(name: "byPost5", fields: ["postID", "editorID"])
@key(name: "byEditor5", fields: ["editorID", "postID"]) {
id: ID!
postID: ID!
editorID: ID!
post: Post5! @connection(fields: ["postID"])
editor: User5! @connection(fields: ["editorID"])
}
type User5 @model {
id: ID!
username: String!
posts: [PostEditor5] @connection(keyName: "byEditor5", fields: ["id"])
}
```
See https://docs.amplify.aws/cli/graphql-transformer/connection for more details.
*/
class GraphQLConnectionScenario5Tests: XCTestCase {
override func setUp() {
do {
Amplify.Logging.logLevel = .verbose
try Amplify.add(plugin: AWSAPIPlugin())
let amplifyConfig = try TestConfigHelper.retrieveAmplifyConfiguration(
forResource: GraphQLModelBasedTests.amplifyConfiguration)
try Amplify.configure(amplifyConfig)
ModelRegistry.register(modelType: Post5.self)
ModelRegistry.register(modelType: PostEditor5.self)
ModelRegistry.register(modelType: User5.self)
} catch {
XCTFail("Error during setup: \(error)")
}
}
override func tearDown() async throws {
await Amplify.reset()
}
func testListPostEditorByPost() async throws {
guard let post = try await createPost(title: "title") else {
XCTFail("Could not create post")
return
}
guard let user = try await createUser(username: "username") else {
XCTFail("Could not create user")
return
}
guard try await createPostEditor(post: post, editor: user) != nil else {
XCTFail("Could not create user")
return
}
let predicateByPostId = PostEditor5.keys.post.eq(post.id)
let result = try await Amplify.API.query(request: .list(PostEditor5.self, where: predicateByPostId))
switch result {
case .success(let projects):
XCTAssertNotNil(projects)
case .failure(let response):
XCTFail("Failed with: \(response)")
}
}
func testListPostEditorByUser() async throws {
guard let post = try await createPost(title: "title") else {
XCTFail("Could not create post")
return
}
guard let user = try await createUser(username: "username") else {
XCTFail("Could not create user")
return
}
guard try await createPostEditor(post: post, editor: user) != nil else {
XCTFail("Could not create user")
return
}
let predicateByUserId = PostEditor5.keys.editor.eq(user.id)
let result = try await Amplify.API.query(request: .list(PostEditor5.self, where: predicateByUserId))
switch result {
case .success(let projects):
XCTAssertNotNil(projects)
case .failure(let response):
XCTFail("Failed with: \(response)")
}
}
// Create a Post and a User, Create a PostEditor with the post and user
// Get the post and fetch the PostEditors for that post
// The Posteditor contains the user which is connected the post
func testGetPostThenFetchPostEditorsToRetrieveUser() async throws {
guard let post = try await createPost(title: "title") else {
XCTFail("Could not create post")
return
}
guard let user = try await createUser(username: "username") else {
XCTFail("Could not create user")
return
}
guard try await createPostEditor(post: post, editor: user) != nil else {
XCTFail("Could not create user")
return
}
let getPostCompleted = expectation(description: "get post complete")
let fetchPostEditorCompleted = expectation(description: "fetch postEditors complete")
var results: List<PostEditor5>?
let response = try await Amplify.API.query(request: .get(Post5.self, byId: post.id))
switch response {
case .success(let queriedPostOptional):
guard let queriedPost = queriedPostOptional else {
XCTFail("Could not get post")
return
}
XCTAssertEqual(queriedPost.id, post.id)
getPostCompleted.fulfill()
guard let editors = queriedPost.editors else {
XCTFail("Could not get postEditors")
return
}
try await editors.fetch()
results = editors
fetchPostEditorCompleted.fulfill()
case .failure(let response):
XCTFail("Failed with: \(response)")
}
wait(for: [getPostCompleted, fetchPostEditorCompleted], timeout: TestCommonConstants.networkTimeout)
guard var subsequentResults = results else {
XCTFail("Could not get first results")
return
}
var resultsArray: [PostEditor5] = []
resultsArray.append(contentsOf: subsequentResults)
while subsequentResults.hasNextPage() {
let listResult = try await subsequentResults.getNextPage()
subsequentResults = listResult
resultsArray.append(contentsOf: subsequentResults)
}
XCTAssertEqual(resultsArray.count, 1)
guard let postEditor = resultsArray.first else {
XCTFail("Could not get editor")
return
}
XCTAssertEqual(postEditor.editor.id, user.id)
}
// Create two posts (`post1` and `post2`) and a user
// create first PostEditor with the `post1` and user and create second postEditor with `post2` and user.
// Get the user and fetch the PostEditors for that user
// The PostEditors should contain the two posts `post1` and `post2`
func testGetUserThenFetchPostEditorsToRetrievePosts() async throws {
guard let post1 = try await createPost(title: "title") else {
XCTFail("Could not create post")
return
}
guard let post2 = try await createPost(title: "title") else {
XCTFail("Could not create post")
return
}
guard let user = try await createUser(username: "username") else {
XCTFail("Could not create user")
return
}
guard try await createPostEditor(post: post1, editor: user) != nil else {
XCTFail("Could not create postEditor with `post1`")
return
}
guard try await createPostEditor(post: post2, editor: user) != nil else {
XCTFail("Could not create postEditor with `post2`")
return
}
let getUserCompleted = expectation(description: "get user complete")
let fetchPostEditorCompleted = expectation(description: "fetch postEditors complete")
var results: List<PostEditor5>?
let response = try await Amplify.API.query(request: .get(User5.self, byId: user.id))
switch response {
case .success(let queriedUserOptional):
guard let queriedUser = queriedUserOptional else {
XCTFail("Could not get post")
return
}
XCTAssertEqual(queriedUser.id, user.id)
getUserCompleted.fulfill()
guard let posts = queriedUser.posts else {
XCTFail("Could not get postEditors")
return
}
try await posts.fetch()
results = posts
fetchPostEditorCompleted.fulfill()
case .failure(let response):
XCTFail("Failed with: \(response)")
}
wait(for: [getUserCompleted, fetchPostEditorCompleted], timeout: TestCommonConstants.networkTimeout)
guard var subsequentResults = results else {
XCTFail("Could not get first results")
return
}
var resultsArray: [PostEditor5] = []
resultsArray.append(contentsOf: subsequentResults)
while subsequentResults.hasNextPage() {
let listResult = try await subsequentResults.getNextPage()
subsequentResults = listResult
resultsArray.append(contentsOf: subsequentResults)
}
XCTAssertEqual(resultsArray.count, 2)
XCTAssertTrue(resultsArray.contains(where: { (postEditor) -> Bool in
postEditor.post.id == post1.id
}))
XCTAssertTrue(resultsArray.contains(where: { (postEditor) -> Bool in
postEditor.post.id == post2.id
}))
}
func createPost(id: String = UUID().uuidString, title: String) async throws -> Post5? {
let post = Post5(id: id, title: title)
let data = try await Amplify.API.mutate(request: .create(post))
switch data {
case .success(let post):
return post
case .failure(let error):
throw error
}
}
func createUser(id: String = UUID().uuidString, username: String) async throws -> User5? {
let user = User5(id: id, username: username)
let data = try await Amplify.API.mutate(request: .create(user))
switch data {
case .success(let user):
return user
case .failure(let error):
throw error
}
}
func createPostEditor(id: String = UUID().uuidString, post: Post5, editor: User5) async throws -> PostEditor5? {
let postEditor = PostEditor5(id: id, post: post, editor: editor)
let data = try await Amplify.API.mutate(request: .create(postEditor))
switch data {
case .success(let postEditor):
return postEditor
case .failure(let error):
throw error
}
}
}