Repository: graphql-rust/juniper (language: rust)

Issue:
Fields on interface fragment spreads don't get resolved
**Describe the bug**

When resolving fields defined on an interface, if the field is defined within a fragment spread, then it is omitted from the output.

I'm happy to work on a fix for this, but will need some guidance on where to look (and whatever other tips/hints you could give me).

**To Reproduce**

Using the schema defined in `juniper/src/tests/fixtures/starwars/` (I ran the `juniper_rocket_async` example to reproduce):

### Working

A simple query returns the expected result (`id` and `name` fields are populated).

```graphql
query {
  hero {
    id
    name
  }
}
```

```json
{
  "data": {
    "hero": {
      "id": "2001",
      "name": "R2-D2"
    }
  }
}
```

### Broken

But this query, using a fragment spread on the `Character` interface, is broken (`id` and `name` fields are omitted in the response):

```graphql
{
  hero {
    ... on Character {
      id
      name
    }
  }
}
```

```json
{
  "data": {
    "hero": {}
  }
}
```


**Expected behavior**

The second query above should return the exact same output as the first query.


**Additional context**

I encountered this problem using Relay in my UI, as parts of the query being generated by Relay use this pattern. Which leads me to believe that these queries should definitely be valid.



Discussion / hints:
This is clearly a regression from `0.15.3`. I downgraded `juniper` and all related crates from `0.15.4` to `0.15.3` and it helped.

~~Also this bug can be reproduced with unions.~~ It was an interface.
@ArsileLuci I just tried downgrading to 0.15.3 and am still seeing the issue. If this is a regression in 0.15.4 though, I'd be willing to bet it's related to this PR: https://github.com/graphql-rust/juniper/pull/907
@LucasPickering Found the issue. As You've pointed out the problem comes partially from #907 

Bug was in typename matching, at this [two rows](https://github.com/graphql-rust/juniper/pull/907/files#diff-2aa4c3fe54fa1e05c4fd649aa1d252e3ba8fd5baab1ea5a8cf2170876df4d52aR308-R309).

`fragment.type_condition.item` is the name of interface, and it was compared with `instance.concrete_type_name(sub_exec.context(), info)` which is actually exact name of the type that implements interface.

I have a fix for this, and now preparing tests to eliminate all possibilities of this reoccurring
@ArsileLuci nice find! thank you so much for finding+fixing that, much appreciated

Fix patch:
diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md
index 273a0087a..f71fce95b 100644
--- a/juniper/CHANGELOG.md
+++ b/juniper/CHANGELOG.md
@@ -1,6 +1,6 @@
 # master
 
-- No changes yet
+- Fix fields on interfaces not being resolved when used with fragments ([#923](https://github.com/graphql-rust/juniper/pull/923))
 
 # [[0.15.4] 2021-04-03](https://github.com/graphql-rust/juniper/releases/tag/juniper-0.15.4)
 
diff --git a/juniper/src/types/async_await.rs b/juniper/src/types/async_await.rs
index e1f6e6e1c..4fd16aad7 100644
--- a/juniper/src/types/async_await.rs
+++ b/juniper/src/types/async_await.rs
@@ -306,7 +306,10 @@ where
                 );
 
                 let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
-                if fragment.type_condition.item == concrete_type_name {
+                let type_name = instance.type_name(info);
+                if fragment.type_condition.item == concrete_type_name
+                    || Some(fragment.type_condition.item) == type_name
+                {
                     let sub_result = instance
                         .resolve_into_type_async(
                             info,
diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs
index 61d32ca84..014af5de5 100644
--- a/juniper/src/types/base.rs
+++ b/juniper/src/types/base.rs
@@ -515,7 +515,10 @@ where
                 );
 
                 let concrete_type_name = instance.concrete_type_name(sub_exec.context(), info);
-                if fragment.type_condition.item == concrete_type_name {
+                let type_name = instance.type_name(info);
+                if fragment.type_condition.item == concrete_type_name
+                    || Some(fragment.type_condition.item) == type_name
+                {
                     let sub_result = instance.resolve_into_type(
                         info,
                         fragment.type_condition.item,


Test patch:
diff --git a/integration_tests/juniper_tests/src/issue_922.rs b/integration_tests/juniper_tests/src/issue_922.rs
new file mode 100644
index 000000000..35de87faf
--- /dev/null
+++ b/integration_tests/juniper_tests/src/issue_922.rs
@@ -0,0 +1,128 @@
+use juniper::*;
+
+struct Query;
+
+#[juniper::graphql_object]
+impl Query {
+    fn characters() -> Vec<CharacterValue> {
+        vec![
+            Into::into(Human {
+                id: 0,
+                name: "human-32".to_owned(),
+            }),
+            Into::into(Droid {
+                id: 1,
+                name: "R2-D2".to_owned(),
+            }),
+        ]
+    }
+}
+
+#[juniper::graphql_interface(for = [Human, Droid])]
+trait Character {
+    fn id(&self) -> i32;
+
+    fn name(&self) -> String;
+}
+
+#[derive(juniper::GraphQLObject)]
+#[graphql(impl = CharacterValue)]
+struct Human {
+    pub id: i32,
+    pub name: String,
+}
+
+#[juniper::graphql_interface]
+impl Character for Human {
+    fn id(&self) -> i32 {
+        self.id
+    }
+
+    fn name(&self) -> String {
+        self.name.clone()
+    }
+}
+
+#[derive(juniper::GraphQLObject)]
+#[graphql(impl = CharacterValue)]
+struct Droid {
+    pub id: i32,
+    pub name: String,
+}
+
+#[juniper::graphql_interface]
+impl Character for Droid {
+    fn id(&self) -> i32 {
+        self.id
+    }
+
+    fn name(&self) -> String {
+        self.name.clone()
+    }
+}
+
+type Schema = juniper::RootNode<'static, Query, EmptyMutation<()>, EmptySubscription<()>>;
+
+#[tokio::test]
+async fn test_fragment_on_interface() {
+    let query = r#"
+        query Query {
+            characters {
+                ...CharacterFragment
+            }
+        }
+
+        fragment CharacterFragment on Character {
+            __typename
+            ... on Human {
+                id
+                name
+            }
+            ... on Droid {
+                id
+                name
+            }
+        }
+    "#;
+
+    let (res, errors) = juniper::execute(
+        query,
+        None,
+        &Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()),
+        &Variables::new(),
+        &(),
+    )
+    .await
+    .unwrap();
+
+    assert_eq!(errors.len(), 0);
+    assert_eq!(
+        res,
+        graphql_value!({
+            "characters": [
+                {"__typename": "Human", "id": 0, "name": "human-32"},
+                {"__typename": "Droid", "id": 1, "name": "R2-D2"},
+            ],
+        }),
+    );
+
+    let (res, errors) = juniper::execute_sync(
+        query,
+        None,
+        &Schema::new(Query, EmptyMutation::new(), EmptySubscription::new()),
+        &Variables::new(),
+        &(),
+    )
+    .unwrap();
+
+    assert_eq!(errors.len(), 0);
+    assert_eq!(
+        res,
+        graphql_value!({
+            "characters": [
+                {"__typename": "Human", "id": 0, "name": "human-32"},
+                {"__typename": "Droid", "id": 1, "name": "R2-D2"},
+            ],
+        }),
+    );
+}
diff --git a/integration_tests/juniper_tests/src/lib.rs b/integration_tests/juniper_tests/src/lib.rs
index ce6123d32..a4a9c97fe 100644
--- a/integration_tests/juniper_tests/src/lib.rs
+++ b/integration_tests/juniper_tests/src/lib.rs
@@ -21,4 +21,6 @@ mod issue_500;
 #[cfg(test)]
 mod issue_914;
 #[cfg(test)]
+mod issue_922;
+#[cfg(test)]
 mod pre_parse;