Repository: p2panda/aquadoggo (language: rust)

Issue:
Finalize e2e tests from query PRs
The work on the collection query API was realized in multiple large PRs which comes to its end. Some e2e tests are still unfinished and can be finalized now since we implemented everything from backend to frontend.


Discussion / hints:
Examples:

* https://github.com/p2panda/aquadoggo/blob/784a0ef9d45a5df53a01d4ae8b004a9946b3cfd3/aquadoggo/src/graphql/tests.rs#L88
* https://github.com/p2panda/aquadoggo/blob/784a0ef9d45a5df53a01d4ae8b004a9946b3cfd3/aquadoggo/src/graphql/queries/document.rs#L268

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28b524898..56aa6e4e0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,8 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added
 
 - Dial peers discovered via mDNS [#331](https://github.com/p2panda/aquadoggo/pull/331)
-- Simplify network CLI options and configuration [#322](https://github.com/p2panda/aquadoggo/pull/322) 
-- Introduce `autonat` and `relay` network protocols [#314](https://github.com/p2panda/aquadoggo/pull/314) 
+- Simplify network CLI options and configuration [#322](https://github.com/p2panda/aquadoggo/pull/322)
+- Introduce `autonat` and `relay` network protocols [#314](https://github.com/p2panda/aquadoggo/pull/314)
 - Introduce `identify` and `rendezvous` network protocols / behaviours [#304](https://github.com/p2panda/aquadoggo/pull/304)
 - Introduce libp2p networking service and configuration [#282](https://github.com/p2panda/aquadoggo/pull/282)
 - Create and validate abstract queries [#302](https://github.com/p2panda/aquadoggo/pull/302)
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Use new version of `async-graphql` for dynamic schema generation [#287](https://github.com/p2panda/aquadoggo/pull/287)
 - Restructure `graphql` module [#307](https://github.com/p2panda/aquadoggo/pull/307)
 - Removed replication service for now, preparing for new replication protocol [#296](https://github.com/p2panda/aquadoggo/pull/296)
+- Bring back e2e GraphQL API tests [#342](https://github.com/p2panda/aquadoggo/pull/342)
 
 ### Fixed
 
diff --git a/aquadoggo/src/db/stores/query.rs b/aquadoggo/src/db/stores/query.rs
index f2ec414b4..2fb3204b1 100644
--- a/aquadoggo/src/db/stores/query.rs
+++ b/aquadoggo/src/db/stores/query.rs
@@ -1158,7 +1158,9 @@ mod tests {
     use crate::db::stores::{OperationCursor, RelationList};
     use crate::db::types::StorageDocument;
     use crate::graphql::types::OrderDirection;
-    use crate::test_utils::{add_document, add_schema, test_runner, TestNode};
+    use crate::test_utils::{
+        add_document, add_schema, add_schema_and_documents, test_runner, TestNode,
+    };
 
     use super::{convert_rows, PaginationCursor, Query};
 
@@ -1172,50 +1174,6 @@ mod tests {
             .to_owned()
     }
 
-    async fn add_schema_and_documents(
-        node: &mut TestNode,
-        schema_name: &str,
-        documents: Vec<Vec<(&str, OperationValue, Option<SchemaId>)>>,
-        key_pair: &KeyPair,
-    ) -> (Schema, Vec<DocumentViewId>) {
-        assert!(documents.len() > 0);
-
-        // Look at first document to automatically derive schema
-        let schema_fields = documents[0]
-            .iter()
-            .map(|(field_name, field_value, schema_id)| {
-                // Get field type from operation value
-                let field_type = match field_value.field_type() {
-                    "relation" => FieldType::Relation(schema_id.clone().unwrap()),
-                    "pinned_relation" => FieldType::PinnedRelation(schema_id.clone().unwrap()),
-                    "relation_list" => FieldType::RelationList(schema_id.clone().unwrap()),
-                    "pinned_relation_list" => {
-                        FieldType::PinnedRelationList(schema_id.clone().unwrap())
-                    }
-                    _ => field_value.field_type().parse().unwrap(),
-                };
-
-                (*field_name, field_type)
-            })
-            .collect();
-
-        // Create schema
-        let schema = add_schema(node, schema_name, schema_fields, key_pair).await;
-
-        // Add all documents and return created view ids
-        let mut view_ids = Vec::new();
-        for document in documents {
-            let fields = document
-                .iter()
-                .map(|field| (field.0, field.1.clone()))
-                .collect();
-            let view_id = add_document(node, schema.id(), fields, key_pair).await;
-            view_ids.push(view_id);
-        }
-
-        (schema, view_ids)
-    }
-
     async fn create_events_test_data(
         node: &mut TestNode,
         key_pair: &KeyPair,
diff --git a/aquadoggo/src/graphql/queries/document.rs b/aquadoggo/src/graphql/queries/document.rs
index 96dbcc94d..2dcf48e0d 100644
--- a/aquadoggo/src/graphql/queries/document.rs
+++ b/aquadoggo/src/graphql/queries/document.rs
@@ -265,40 +265,38 @@ mod test {
         });
     }
 
-    // @TODO: Needs to be fixed after GraphQL API change:
-    // See issue: https://github.com/p2panda/aquadoggo/issues/330
-    /* #[rstest]
-        fn type_name(#[from(random_key_pair)] key_pair: KeyPair) {
-            // Test availability of `__typename` on all objects.
-            test_runner(move |mut node: TestNode| async move {
-                // Add schema to node.
-                let schema = add_schema(
-                    &mut node,
-                    "schema_name",
-                    vec![("bool", FieldType::Boolean)],
-                    &key_pair,
-                )
-                .await;
+    #[rstest]
+    fn type_name(#[from(random_key_pair)] key_pair: KeyPair) {
+        // Test availability of `__typename` on all objects.
+        test_runner(move |mut node: TestNode| async move {
+            // Add schema to node.
+            let schema = add_schema(
+                &mut node,
+                "schema_name",
+                vec![("bool", FieldType::Boolean)],
+                &key_pair,
+            )
+            .await;
 
-                // Publish document on node.
-                let view_id = add_document(
-                    &mut node,
-                    &schema.id(),
-                    vec![("bool", true.into())],
-                    &key_pair,
-                )
-                .await;
+            // Publish document on node.
+            let view_id = add_document(
+                &mut node,
+                &schema.id(),
+                vec![("bool", true.into())],
+                &key_pair,
+            )
+            .await;
 
-                // Configure and send test query.
-                let client = graphql_test_client(&node).await;
-                let query = format!(
-                    r#"{{
-                    single: {type_name}(id: "{view_id}") {{
+            // Configure and send test query.
+            let client = graphql_test_client(&node).await;
+            let query = format!(
+                r#"{{
+                    single: {schema_id}(id: "{view_id}") {{
                         __typename,
                         meta {{ __typename }}
                         fields {{ __typename }}
                     }},
-                    collection: all_{type_name} {{
+                    collection: all_{schema_id} {{
                         __typename,
                         documents {{
                             __typename,
@@ -307,36 +305,37 @@ mod test {
                         }}
                     }},
                 }}"#,
-                    type_name = schema.id(),
-    e               view_id = view_id,
-                );
-
-                let response = client
-                    .post("/graphql")
-                    .json(&json!({
-                        "query": query,
-                    }))
-                    .send()
-                    .await;
-
-                let response: Response = response.json().await;
-
-                let expected_data = value!({
-                    "single": {
-                        "__typename": schema.id(),
+                schema_id = schema.id(),
+                view_id = view_id,
+            );
+
+            let response = client
+                .post("/graphql")
+                .json(&json!({
+                    "query": query,
+                }))
+                .send()
+                .await;
+
+            let response: Response = response.json().await;
+
+            let expected_data = value!({
+                "single": {
+                    "__typename": schema.id(),
+                    "meta": { "__typename": "DocumentMeta" },
+                    "fields": { "__typename": format!("{}Fields", schema.id()), }
+                },
+                "collection": {
+                    "__typename": format!("{}Collection", schema.id()),
+                    "documents": [{
+                        "__typename" : format!("{}Item", schema.id()),
                         "meta": { "__typename": "DocumentMeta" },
                         "fields": { "__typename": format!("{}Fields", schema.id()), }
-                    },
-                    "collection": [{
-                        "__typename": format!("{}DocumentCollection", schema.id()),
-                        "documents" : {
-                            "__typename" : format!("{}Paginated", schema.id()),
-                            "meta": { "__typename": "DocumentMeta" },
-                            "fields": { "__typename": format!("{}Fields", schema.id()), }
-                        }
                     }]
-                });
-                assert_eq!(response.data, expected_data, "{:#?}", response.errors);
+                }
             });
-        } */
+
+            assert_eq!(response.data, expected_data, "{:#?}", response.errors);
+        });
+    }
 }
diff --git a/aquadoggo/src/graphql/types/document_fields.rs b/aquadoggo/src/graphql/types/document_fields.rs
index e7a08db7e..7bfffd6eb 100644
--- a/aquadoggo/src/graphql/types/document_fields.rs
+++ b/aquadoggo/src/graphql/types/document_fields.rs
@@ -10,14 +10,12 @@ use p2panda_rs::storage_provider::traits::DocumentStore;
 
 use crate::db::stores::RelationList;
 use crate::db::SqlStore;
-use crate::graphql::types::DocumentValue;
+use crate::graphql::types::{DocumentCollection, DocumentValue};
 use crate::graphql::utils::{
     downcast_document, fields_name, gql_scalar, graphql_type, with_collection_arguments,
 };
 use crate::schema::SchemaProvider;
 
-use super::DocumentCollection;
-
 /// A constructor for dynamically building objects describing the application fields of a p2panda
 /// schema. Each generated object has a type name with the formatting `<schema_id>Fields`.
 ///
@@ -165,75 +163,3 @@ impl DocumentFields {
         }
     }
 }
-
-// TODO: We don't actually perform any queries yet, these tests will need to be updated when we do.
-// See issue: https://github.com/p2panda/aquadoggo/issues/330
-/* #[cfg(test)]
-mod test {
-    use async_graphql::{value, Response, Value};
-    use rstest::rstest;
-    use serde_json::json;
-
-    use crate::test_utils::{graphql_test_client, test_runner, TestNode};
-
-    #[rstest]
-    #[case(
-        r#"(
-            first: 10,
-            after: "1_00205406410aefce40c5cbbb04488f50714b7d5657b9f17eed7358da35379bc20331",
-            orderBy: "name",
-            orderDirection: ASC,
-            filter: {
-                name : {
-                    eq: "hello"
-                }
-            },
-        )"#.to_string(),
-        value!({
-            "collection": value!([]),
-        }),
-        vec![]
-    )]
-    fn collection_query(
-        #[case] query_args: String,
-        #[case] expected_data: Value,
-        #[case] _expected_errors: Vec<String>,
-    ) {
-        // Test collection query parameter variations.
-        test_runner(move |node: TestNode| async move {
-            // Configure and send test query.
-            let client = graphql_test_client(&node).await;
-            let query = format!(
-                r#"{{
-                    collection: all_schema_definition_v1 {{
-                        hasNextPage
-                        totalCount
-                        documents {{
-                            cursor
-                            fields {{
-                                fields{query_args} {{
-                                    documents {{
-                                        cursor
-                                    }}
-                                }}
-                            }}
-                        }}
-                    }},
-                }}"#,
-                query_args = query_args
-            );
-
-            let response = client
-                .post("/graphql")
-                .json(&json!({
-                    "query": query,
-                }))
-                .send()
-                .await;
-
-            let response: Response = response.json().await;
-
-            assert_eq!(response.data, expected_data, "{:#?}", response.errors);
-        });
-    }
-} */
diff --git a/aquadoggo/src/graphql/utils.rs b/aquadoggo/src/graphql/utils.rs
index 778c66487..199e2494b 100644
--- a/aquadoggo/src/graphql/utils.rs
+++ b/aquadoggo/src/graphql/utils.rs
@@ -405,8 +405,12 @@ pub fn look_ahead_selected_fields(ctx: &ResolverContext) -> (Vec<PaginationField
             .for_each(|field| match field.name() {
                 // Parse selected application fields
                 constants::FIELDS_FIELD => {
-                    field.selection_set().for_each(|field| {
-                        selected_fields.push(Field::Field(field.name().to_string()));
+                    field.selection_set().for_each(|field| match field.name() {
+                        // Remove special GraphQL meta fields
+                        "__typename" => (),
+                        field_name => {
+                            selected_fields.push(Field::Field(field_name.to_string()));
+                        }
                     });
                 }
                 // Parse selected meta fields


Test patch:
diff --git a/aquadoggo/src/graphql/tests.rs b/aquadoggo/src/graphql/tests.rs
index b69881318..a40e0f900 100644
--- a/aquadoggo/src/graphql/tests.rs
+++ b/aquadoggo/src/graphql/tests.rs
@@ -4,8 +4,9 @@
 use std::convert::TryInto;
 
 use async_graphql::{value, Response};
-use p2panda_rs::schema::FieldType;
 use p2panda_rs::test_utils::fixtures::random_key_pair;
+use p2panda_rs::{document::DocumentId, schema::FieldType};
+use rstest::rstest;
 use serde_json::json;
 
 use crate::test_utils::{add_document, add_schema, graphql_test_client, test_runner, TestNode};
@@ -17,7 +18,7 @@ fn scalar_fields() {
     test_runner(|mut node: TestNode| async move {
         let key_pair = random_key_pair();
 
-        // Add schema to node.
+        // Add schema to node
         let schema = add_schema(
             &mut node,
             "schema_name",
@@ -31,7 +32,7 @@ fn scalar_fields() {
         )
         .await;
 
-        // Publish document on node.
+        // Publish document on node
         let doc_fields = vec![
             ("bool", true.into()),
             ("float", (1.0).into()),
@@ -42,7 +43,7 @@ fn scalar_fields() {
         .unwrap();
         let view_id = add_document(&mut node, schema.id(), doc_fields, &key_pair).await;
 
-        // Configure and send test query.
+        // Configure and send test query
         let client = graphql_test_client(&node).await;
         let query = format!(
             r#"{{
@@ -85,13 +86,12 @@ fn scalar_fields() {
 
 // Test querying application documents across a parent-child relation using different kinds of
 // relation fields.
-// @TODO: Needs updating after API changes: https://github.com/p2panda/aquadoggo/issues/330
-/* #[rstest]
+#[rstest]
 fn relation_fields() {
     test_runner(|mut node: TestNode| async move {
         let key_pair = random_key_pair();
 
-        // Add schemas to node.
+        // Add schemas to node
         let child_schema = add_schema(
             &mut node,
             "child",
@@ -125,7 +125,7 @@ fn relation_fields() {
         )
         .await;
 
-        // Publish child document on node.
+        // Publish child document on node
         let child_view_id = add_document(
             &mut node,
             child_schema.id(),
@@ -133,10 +133,11 @@ fn relation_fields() {
             &key_pair,
         )
         .await;
-        // There is only one operation so view id = doc id.
+
+        // There is only one operation so view id = doc id
         let child_doc_id: DocumentId = child_view_id.to_string().parse().unwrap();
 
-        // Publish parent document on node.
+        // Publish parent document on node
         let parent_fields = vec![
             ("by_relation", child_doc_id.clone().into()),
             ("by_pinned_relation", child_view_id.clone().into()),
@@ -147,7 +148,7 @@ fn relation_fields() {
         let parent_view_id =
             add_document(&mut node, parent_schema.id(), parent_fields, &key_pair).await;
 
-        // Configure and send test query.
+        // Configure and send test query
         let client = graphql_test_client(&node).await;
         let query = format!(
             r#"{{
@@ -155,8 +156,8 @@ fn relation_fields() {
                     fields {{
                         by_relation {{ fields {{ it_works }} }},
                         by_pinned_relation {{ fields {{ it_works }} }},
-                        by_relation_list {{ document {{ fields {{ it_works }} }} }},
-                        by_pinned_relation_list {{ document {{ fields {{ it_works }} }} }},
+                        by_relation_list {{ documents {{ fields {{ it_works }} }} }},
+                        by_pinned_relation_list {{ documents {{ fields {{ it_works }} }} }},
                     }}
                 }}
             }}"#,
@@ -187,24 +188,24 @@ fn relation_fields() {
                             "it_works": true
                         }
                     },
-                    "by_relation_list": [{
-                        "document" : {
+                    "by_relation_list": {
+                        "documents": [{
                             "fields": {
                                 "it_works": true
                             }
-                        }
-                    }],
-                    "by_pinned_relation_list": [{
-                        "document" : {
+                        }]
+                    },
+                    "by_pinned_relation_list": {
+                        "documents": [{
                             "fields": {
                                 "it_works": true
                             }
-                        }
-                    }]
+                        }]
+                    }
                 }
             }
         });
 
         assert_eq!(response.data, expected_data,);
     });
-} */
+}
diff --git a/aquadoggo/src/test_utils/mod.rs b/aquadoggo/src/test_utils/mod.rs
index afab515d8..40a6c915f 100644
--- a/aquadoggo/src/test_utils/mod.rs
+++ b/aquadoggo/src/test_utils/mod.rs
@@ -12,6 +12,7 @@ pub use config::{TestConfiguration, TEST_CONFIG};
 pub use db::{drop_database, initialize_db, initialize_db_with_url};
 pub use helpers::{build_document, doggo_fields, doggo_schema, schema_from_fields};
 pub use node::{
-    add_document, add_schema, populate_and_materialize, populate_store_config, TestNode,
+    add_document, add_schema, add_schema_and_documents, populate_and_materialize,
+    populate_store_config, TestNode,
 };
 pub use runner::test_runner;
diff --git a/aquadoggo/src/test_utils/node.rs b/aquadoggo/src/test_utils/node.rs
index 09594e376..abd050c23 100644
--- a/aquadoggo/src/test_utils/node.rs
+++ b/aquadoggo/src/test_utils/node.rs
@@ -220,3 +220,46 @@ pub async fn add_schema(
         .await
         .expect("Failed adding schema to provider.")
 }
+
+/// Create a schema in the test database and multiple documents using it.
+pub async fn add_schema_and_documents(
+    node: &mut TestNode,
+    schema_name: &str,
+    documents: Vec<Vec<(&str, OperationValue, Option<SchemaId>)>>,
+    key_pair: &KeyPair,
+) -> (Schema, Vec<DocumentViewId>) {
+    assert!(documents.len() > 0);
+
+    // Look at first document to automatically derive schema
+    let schema_fields = documents[0]
+        .iter()
+        .map(|(field_name, field_value, schema_id)| {
+            // Get field type from operation value
+            let field_type = match field_value.field_type() {
+                "relation" => FieldType::Relation(schema_id.clone().unwrap()),
+                "pinned_relation" => FieldType::PinnedRelation(schema_id.clone().unwrap()),
+                "relation_list" => FieldType::RelationList(schema_id.clone().unwrap()),
+                "pinned_relation_list" => FieldType::PinnedRelationList(schema_id.clone().unwrap()),
+                _ => field_value.field_type().parse().unwrap(),
+            };
+
+            (*field_name, field_type)
+        })
+        .collect();
+
+    // Create schema
+    let schema = add_schema(node, schema_name, schema_fields, key_pair).await;
+
+    // Add all documents and return created view ids
+    let mut view_ids = Vec::new();
+    for document in documents {
+        let fields = document
+            .iter()
+            .map(|field| (field.0, field.1.clone()))
+            .collect();
+        let view_id = add_document(node, schema.id(), fields, key_pair).await;
+        view_ids.push(view_id);
+    }
+
+    (schema, view_ids)
+}