@apollo/federation
Version:
Apollo Federation Utilities
286 lines (258 loc) • 7.9 kB
text/typescript
import { composeServices } from '../../../compose';
import { providesNotOnEntity as validateProvidesNotOnEntity } from '../';
import {
gql,
graphqlErrorSerializer,
} from 'apollo-federation-integration-testsuite';
expect.addSnapshotSerializer(graphqlErrorSerializer);
describe('providesNotOnEntity', () => {
it('does not warn when @provides used on an entity', () => {
const serviceA = {
typeDefs: gql`
type LineItem {
sku: String!
quantity: Int!
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
type Product {
lineItem: LineItem
lineItemNonNull: LineItem!
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toMatchInlineSnapshot(`Array []`);
});
it('does not warn when @provides used on a list of entity', () => {
const serviceA = {
typeDefs: gql`
type LineItem {
sku: String!
quantity: Int!
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
type Product {
lineItems: [LineItem]
lineItemsNonNull: [LineItem]!
nonNullLineItems: [LineItem!]
nonNullLineItemsNonNull: [LineItem!]!
deep: [[LineItem!]!]!
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toMatchInlineSnapshot(`Array []`);
});
it('does not warn when @provides used on an entity of a child type', () => {
const serviceA = {
typeDefs: gql`
type User {
id: ID!
username: String
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
type Review {
author: User
}
type User {
username: String
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toEqual([]);
});
it('warns when there is a @provides on a type that is not an entity', () => {
const serviceA = {
typeDefs: gql`
type Product {
sku: String!
upc: String!
id: ID!
}
type LineItem {
sku: String!
quantity: Int!
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
extend type Product {
sku: String!
lineItem: LineItem
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toMatchInlineSnapshot(`
Array [
Object {
"code": "PROVIDES_NOT_ON_ENTITY",
"locations": Array [
Object {
"column": 22,
"line": 4,
},
],
"message": "[serviceB] Product.lineItem -> uses the @provides directive but \`Product.lineItem\` does not return a type that has a @key. Try adding a @key to the \`LineItem\` type.",
},
]
`);
});
it('warns when there is a @provides on a type that is not a list of entity', () => {
const serviceA = {
typeDefs: gql`
type Product {
sku: String!
upc: String!
id: ID!
}
type LineItem {
sku: String!
quantity: Int!
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
extend type Product {
sku: String!
lineItems: [LineItem]
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toMatchInlineSnapshot(`
Array [
Object {
"code": "PROVIDES_NOT_ON_ENTITY",
"locations": Array [
Object {
"column": 25,
"line": 4,
},
],
"message": "[serviceB] Product.lineItems -> uses the @provides directive but \`Product.lineItems\` does not return a type that has a @key. Try adding a @key to the \`LineItem\` type.",
},
]
`);
});
it('warns when there is a @provides on a non-object type', () => {
const serviceA = {
typeDefs: gql`
type Product {
sku: String!
upc: String!
id: ID!
}
enum Category {
BOOK
MOVIE
SONG
ALBUM
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
extend type Product {
sku: String!
category: Category
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toMatchInlineSnapshot(`
Array [
Object {
"code": "PROVIDES_NOT_ON_ENTITY",
"locations": Array [
Object {
"column": 22,
"line": 4,
},
],
"message": "[serviceB] Product.category -> uses the @provides directive but \`Product.category\` returns \`Category\`, which is not an Object or List type. @provides can only be used on Object types with at least one @key, or Lists of such Objects.",
},
]
`);
});
it('warns when there is a @provides on a list of non-object type', () => {
const serviceA = {
typeDefs: gql`
type Product {
sku: String!
upc: String!
id: ID!
}
enum Category {
BOOK
MOVIE
SONG
ALBUM
}
`,
name: 'serviceA',
};
const serviceB = {
typeDefs: gql`
extend type Product {
sku: String!
categories: [Category]
}
`,
name: 'serviceB',
};
const serviceList = [serviceA, serviceB];
const { schema } = composeServices(serviceList);
const warnings = validateProvidesNotOnEntity({ schema, serviceList });
expect(warnings).toMatchInlineSnapshot(`
Array [
Object {
"code": "PROVIDES_NOT_ON_ENTITY",
"locations": Array [
Object {
"column": 26,
"line": 4,
},
],
"message": "[serviceB] Product.categories -> uses the @provides directive but \`Product.categories\` returns \`[Category]\`, which is not an Object or List type. @provides can only be used on Object types with at least one @key, or Lists of such Objects.",
},
]
`);
});
});