@apollo/federation
Version:
Apollo Federation Utilities
252 lines (236 loc) • 6.04 kB
text/typescript
import {
Kind,
DocumentNode,
GraphQLSchema,
specifiedDirectives,
} from 'graphql';
import { validateSDL } from 'graphql/validation/validate';
import { buildMapsFromServiceList } from '../../../compose';
import {
astSerializer,
typeSerializer,
selectionSetSerializer,
graphqlErrorSerializer,
gql,
} from 'apollo-federation-integration-testsuite';
import { knownSubgraphDirectives } from '@apollo/subgraph/dist/directives';
import { ServiceDefinition } from '../../../types';
import { MatchingEnums } from '../matchingEnums';
expect.addSnapshotSerializer(astSerializer);
expect.addSnapshotSerializer(typeSerializer);
expect.addSnapshotSerializer(selectionSetSerializer);
expect.addSnapshotSerializer(graphqlErrorSerializer);
// simulate the first half of the composition process
const createDefinitionsDocumentForServices = (
serviceList: ServiceDefinition[],
): DocumentNode => {
const { typeDefinitionsMap } = buildMapsFromServiceList(serviceList);
return {
kind: Kind.DOCUMENT,
definitions: Object.values(typeDefinitionsMap).flat(),
};
};
describe('matchingEnums', () => {
let schema: GraphQLSchema;
// create a blank schema for each test
beforeEach(() => {
schema = new GraphQLSchema({
query: undefined,
directives: [...specifiedDirectives, ...knownSubgraphDirectives],
});
});
it('does not error with matching enums across services', () => {
const serviceList = [
{
typeDefs: gql`
enum ProductCategory {
BED
BATH
}
`,
name: 'serviceA',
},
{
typeDefs: gql`
enum ProductCategory {
BED
BATH
}
`,
name: 'serviceB',
},
];
const definitionsDocument = createDefinitionsDocumentForServices(
serviceList,
);
const errors = validateSDL(definitionsDocument, schema, [MatchingEnums]);
expect(errors).toHaveLength(0);
});
it('errors when enums in separate services dont match', () => {
const serviceList = [
{
typeDefs: gql`
enum ProductCategory {
BED
BATH
}
`,
name: 'serviceA',
},
{
typeDefs: gql`
enum ProductCategory {
BEYOND
}
`,
name: 'serviceB',
},
];
const definitionsDocument = createDefinitionsDocumentForServices(
serviceList,
);
const errors = validateSDL(definitionsDocument, schema, [MatchingEnums]);
expect(errors).toMatchInlineSnapshot(`
Array [
Object {
"code": "ENUM_MISMATCH",
"locations": Array [
Object {
"column": 1,
"line": 2,
},
Object {
"column": 1,
"line": 2,
},
],
"message": "The \`ProductCategory\` enum does not have identical values in all services. Groups of services with identical values are: [serviceA], [serviceB]",
},
]
`);
});
it('errors when enums in separate services dont match', () => {
const serviceList = [
{
typeDefs: gql`
type Query {
products: [Product]!
}
type Product {
sku: String!
upc: String!
type: ProductType
}
enum ProductType {
BOOK
FURNITURE
}
`,
name: 'serviceA',
},
{
typeDefs: gql`
enum ProductType {
FURNITURE
BOOK
DIGITAL
}
`,
name: 'serviceB',
},
{
typeDefs: gql`
enum ProductType {
FURNITURE
BOOK
DIGITAL
}
`,
name: 'serviceC',
},
];
const definitionsDocument = createDefinitionsDocumentForServices(
serviceList,
);
const errors = validateSDL(definitionsDocument, schema, [MatchingEnums]);
expect(errors).toMatchInlineSnapshot(`
Array [
Object {
"code": "ENUM_MISMATCH",
"locations": Array [
Object {
"column": 1,
"line": 12,
},
Object {
"column": 1,
"line": 2,
},
Object {
"column": 1,
"line": 2,
},
],
"message": "The \`ProductType\` enum does not have identical values in all services. Groups of services with identical values are: [serviceA], [serviceB, serviceC]",
},
]
`);
});
it('errors when an enum name is defined as another type in a service', () => {
const serviceList = [
{
typeDefs: gql`
enum ProductType {
BOOK
FURNITURE
}
`,
name: 'serviceA',
},
{
typeDefs: gql`
type ProductType {
id: String
}
`,
name: 'serviceB',
},
{
typeDefs: gql`
enum ProductType {
FURNITURE
BOOK
DIGITAL
}
`,
name: 'serviceC',
},
];
const definitionsDocument = createDefinitionsDocumentForServices(
serviceList,
);
const errors = validateSDL(definitionsDocument, schema, [MatchingEnums]);
expect(errors).toMatchInlineSnapshot(`
Array [
Object {
"code": "ENUM_MISMATCH_TYPE",
"locations": Array [
Object {
"column": 1,
"line": 2,
},
Object {
"column": 1,
"line": 2,
},
Object {
"column": 1,
"line": 2,
},
],
"message": "[serviceA] ProductType -> ProductType is an enum in [serviceA, serviceC], but not in [serviceB]",
},
]
`);
});
});