use apollo_compiler::coord;
use insta::assert_snapshot;
use test_log::test;
use super::ServiceDefinition;
use super::compose_as_fed2_subgraphs;
use super::extract_subgraphs_from_supergraph_result;
#[test]
fn generates_a_valid_supergraph() {
let subgraph1 = ServiceDefinition {
name: "Subgraph1",
type_defs: r#"
type Query {
t: T
}
type T @key(fields: "k") {
k: ID
}
type S {
x: Int
}
union U = S | T
"#,
};
let subgraph2 = ServiceDefinition {
name: "Subgraph2",
type_defs: r#"
type T @key(fields: "k") {
k: ID
a: Int
b: String
}
enum E {
V1
V2
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph1, subgraph2]);
let supergraph = result.expect("Expected composition to succeed");
let api_schema = supergraph
.to_api_schema(Default::default())
.expect("Expected API schema generation to succeed");
assert_snapshot!(supergraph.schema().schema());
assert_snapshot!(api_schema.schema());
}
#[test]
fn implements_on_type_definition_not_extend_type() {
let subgraph_a = ServiceDefinition {
name: "Subgraph1",
type_defs: r#"
type Query {
t: T
}
interface I {
id: ID!
}
type T implements I @key(fields: "id") {
id: ID!
}
"#,
};
let subgraph_b = ServiceDefinition {
name: "Subgraph2",
type_defs: r#"
interface I {
id: ID!
}
extend type T implements I @key(fields: "id") {
id: ID!
note: String
}
"#,
};
let supergraph =
compose_as_fed2_subgraphs(&[subgraph_a, subgraph_b]).expect("composition should succeed");
assert_snapshot!(supergraph.schema().schema());
}
#[test]
fn preserves_descriptions() {
let subgraph1 = ServiceDefinition {
name: "Subgraph1",
type_defs: r#"
"The foo directive description"
directive @foo(url: String) on FIELD
"A cool schema"
schema {
query: Query
}
"""
Available queries
Not much yet
"""
type Query {
"Returns tea"
t(
"An argument that is very important"
x: String!
): String
}
"#,
};
let subgraph2 = ServiceDefinition {
name: "Subgraph2",
type_defs: r#"
"The foo directive description"
directive @foo(url: String) on FIELD
"An enum"
enum E {
"The A value"
A
"The B value"
B
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph1, subgraph2]);
let supergraph = result.expect("Expected composition to succeed");
let api_schema = supergraph
.to_api_schema(Default::default())
.expect("Expected API schema generation to succeed");
assert_snapshot!(api_schema.schema());
}
#[test]
fn no_hint_raised_when_merging_empty_description() {
let subgraph1 = ServiceDefinition {
name: "Subgraph1",
type_defs: r#"
schema {
query: Query
}
""
type T {
a: String @shareable
}
type Query {
"Returns tea"
t(
"An argument that is very important"
x: String!
): T
}
"#,
};
let subgraph2 = ServiceDefinition {
name: "Subgraph2",
type_defs: r#"
"Type T"
type T {
a: String @shareable
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph1, subgraph2]);
let supergraph = result.expect("Expected composition to succeed");
assert_eq!(
supergraph.hints().len(),
0,
"Expected no hints but got: {:?}",
supergraph.hints()
);
}
#[test]
fn include_types_from_different_subgraphs() {
let subgraph_a = ServiceDefinition {
name: "subgraphA",
type_defs: r#"
type Query {
products: [Product!]
}
type Product {
sku: String!
name: String!
}
"#,
};
let subgraph_b = ServiceDefinition {
name: "subgraphB",
type_defs: r#"
type User {
name: String
email: String!
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph_a, subgraph_b]);
let supergraph = result.expect("Expected composition to succeed");
let api_schema = supergraph
.to_api_schema(Default::default())
.expect("Expected API schema generation to succeed");
assert_snapshot!(api_schema.schema());
let extracted_subgraphs = extract_subgraphs_from_supergraph_result(&supergraph)
.expect("Expected subgraph extraction to succeed");
let subgraph_a_extracted = extracted_subgraphs
.get("subgraphA")
.expect("Expected subgraphA to be present in extracted subgraphs");
assert_snapshot!(subgraph_a_extracted.schema.schema());
let subgraph_b_extracted = extracted_subgraphs
.get("subgraphB")
.expect("Expected subgraphB to be present in extracted subgraphs");
assert_snapshot!(subgraph_b_extracted.schema.schema());
}
#[test]
fn doesnt_leave_federation_directives_in_the_final_schema() {
let subgraph_a = ServiceDefinition {
name: "subgraphA",
type_defs: r#"
type Query {
products: [Product!] @provides(fields: "name")
}
type Product @key(fields: "sku") {
sku: String!
name: String! @external
}
"#,
};
let subgraph_b = ServiceDefinition {
name: "subgraphB",
type_defs: r#"
type Product @key(fields: "sku") {
sku: String!
name: String! @shareable
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph_a, subgraph_b]);
let supergraph = result.expect("Expected composition to succeed");
let api_schema = supergraph
.to_api_schema(Default::default())
.expect("Expected API schema generation to succeed");
assert_snapshot!(api_schema.schema());
let extracted_subgraphs = extract_subgraphs_from_supergraph_result(&supergraph)
.expect("Expected subgraph extraction to succeed");
let subgraph_a_extracted = extracted_subgraphs
.get("subgraphA")
.expect("Expected subgraphA to be present in extracted subgraphs");
assert_snapshot!(subgraph_a_extracted.schema.schema());
let subgraph_b_extracted = extracted_subgraphs
.get("subgraphB")
.expect("Expected subgraphB to be present in extracted subgraphs");
assert_snapshot!(subgraph_b_extracted.schema.schema());
}
#[test]
fn merges_default_arguments_when_they_are_arrays() {
let subgraph_a = ServiceDefinition {
name: "subgraph-a",
type_defs: r#"
type Query {
a: A @shareable
}
type A @key(fields: "id") {
id: ID
get(ids: [ID] = []): [B] @external
req: Int @requires(fields: "get { __typename }")
}
type B @key(fields: "id", resolvable: false) {
id: ID
}
"#,
};
let subgraph_b = ServiceDefinition {
name: "subgraph-b",
type_defs: r#"
type Query {
a: A @shareable
}
type A @key(fields: "id") {
id: ID
get(ids: [ID] = []): [B]
}
type B @key(fields: "id") {
id: ID
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph_a, subgraph_b]);
let _supergraph = result.expect("Expected composition to succeed");
}
#[test]
fn removes_redundant_join_field_directives() {
let subgraph1 = ServiceDefinition {
name: "Subgraph1",
type_defs: r#"
type Query {
product(id: ID!): Product
}
type Product @key(fields: "id") {
id: ID!
name: String! @shareable
price: Float! @shareable
}
"#,
};
let subgraph2 = ServiceDefinition {
name: "Subgraph2",
type_defs: r#"
type Product @key(fields: "id") {
id: ID!
name: String! @shareable
price: Float! @shareable
description: String
}
"#,
};
let result = compose_as_fed2_subgraphs(&[subgraph1, subgraph2]);
let supergraph = result.expect("Expected composition to succeed");
let schema = supergraph.schema().schema();
for field_coord in [
coord!(Product.id),
coord!(Product.name),
coord!(Product.price),
] {
let field = field_coord.lookup_field(schema).expect("Field exists");
let has_join_field = field.directives.iter().any(|d| d.name == "join__field");
assert!(
!has_join_field,
"Field {} should not have @join__field directives",
field_coord
);
}
let description_field = coord!(Product.description)
.lookup_field(schema)
.expect("Field exists");
let has_join_field = description_field
.directives
.iter()
.any(|d| d.name == "join__field");
assert!(
has_join_field,
"Field Product.description should have @join__field directive"
);
}