Skip to content

Commit

Permalink
Removing a used enum value is a breaking change (#5667)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilkisiela authored Oct 14, 2024
1 parent 2104901 commit be5d39c
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .changeset/sour-horses-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@graphql-hive/core': patch
'@graphql-hive/apollo': patch
'@graphql-hive/envelop': patch
'@graphql-hive/yoga': patch
---

Report enum values when an enum is used as an output type
93 changes: 93 additions & 0 deletions integration-tests/tests/api/target/usage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,99 @@ describe('changes with usage data', () => {
fields: 'auto-collect',
},
});

testChangesWithUsageData({
title: 'removing a used enum value is a breaking change',
publishSdl: /* GraphQL */ `
type Query {
feed: Post
}
enum Media {
Image
Video
}
type Post {
id: ID!
title: String!
type: Media
}
`,
checkSdl: /* GraphQL */ `
type Query {
feed: Post
}
enum Media {
Image
}
type Post {
id: ID!
title: String!
type: Media
}
`,
expectedSchemaCheckTypename: {
// Should be breaking,
// because it will cause existing queries
// that use this enum value to error
beforeReportedOperation: 'SchemaCheckError',
afterReportedOperation: 'SchemaCheckError',
},
reportOperation: {
operation: 'query feed { feed { id type } }',
operationName: 'feed',
fields: 'auto-collect',
},
});

testChangesWithUsageData({
title: 'adding a new value to a used enum value is NOT a breaking change',
publishSdl: /* GraphQL */ `
type Query {
feed: Post
}
enum Media {
Image
Video
}
type Post {
id: ID!
title: String!
type: Media
}
`,
checkSdl: /* GraphQL */ `
type Query {
feed: Post
}
enum Media {
Image
Video
Audio
}
type Post {
id: ID!
title: String!
type: Media
}
`,
expectedSchemaCheckTypename: {
beforeReportedOperation: 'SchemaCheckSuccess',
afterReportedOperation: 'SchemaCheckSuccess',
},
reportOperation: {
operation: 'query feed { feed { id type } }',
operationName: 'feed',
fields: 'auto-collect',
},
});
});

test.concurrent('number of produced and collected operations should match', async ({ expect }) => {
Expand Down
10 changes: 10 additions & 0 deletions packages/libraries/core/src/client/collect-schema-coordinates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ASTNode,
DocumentNode,
getNamedType,
GraphQLEnumType,
GraphQLInputType,
GraphQLInterfaceType,
GraphQLNamedType,
Expand Down Expand Up @@ -170,6 +171,15 @@ export function collectSchemaCoordinates(args: {
}

markAsUsed(makeId(parent.name, field.name));

// Collect the entire type if it's an enum.
// Deleting an enum value that is used,
// should be a breaking change
// as it changes the output of the field.
const fieldType = getNamedType(field.type);
if (fieldType instanceof GraphQLEnumType) {
markEntireTypeAsUsed(fieldType);
}
},
VariableDefinition(node) {
const inputType = args.typeInfo.getInputType();
Expand Down
27 changes: 27 additions & 0 deletions packages/libraries/core/tests/collect-schema-coordinates.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,33 @@ describe('collectSchemaCoordinates', () => {
});
expect(Array.from(result)).toEqual(['Query.hello', 'Query.hello.message', 'String']);
});

test('leaf field (enum)', () => {
const schema = buildSchema(/* GraphQL */ `
type Query {
hello: Option
}
enum Option {
World
You
}
`);
const result = collectSchemaCoordinates({
documentNode: parse(/* GraphQL */ `
query {
hello
}
`),
schema,
processVariables: false,
variables: null,
typeInfo: new TypeInfo(schema),
});

expect(Array.from(result)).toEqual(['Query.hello', 'Option.World', 'Option.You']);
});

test('collected fields of interface selection set does not contain exact resolutions (User.id, Animal.id)', () => {
const schema = buildSchema(/* GraphQL */ `
type Query {
Expand Down
8 changes: 8 additions & 0 deletions packages/libraries/core/tests/usage-collector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ test('collect fields', async () => {
Project.cleanId,
Project.name,
Project.type,
ProjectType.FEDERATION,
ProjectType.STITCHING,
ProjectType.SINGLE,
ProjectType.CUSTOM,
ProjectSelectorInput.organization,
ID,
ProjectSelectorInput.project,
Expand Down Expand Up @@ -133,6 +137,10 @@ test('collect input object types', async () => {
Project.cleanId,
Project.name,
Project.type,
ProjectType.FEDERATION,
ProjectType.STITCHING,
ProjectType.SINGLE,
ProjectType.CUSTOM,
ProjectSelectorInput.organization,
ID,
ProjectSelectorInput.project,
Expand Down
12 changes: 12 additions & 0 deletions packages/libraries/core/tests/usage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ test('should send data to Hive', async () => {
Project.cleanId,
Project.name,
Project.type,
ProjectType.FEDERATION,
ProjectType.STITCHING,
ProjectType.SINGLE,
ProjectType.CUSTOM,
ProjectSelectorInput.organization,
ID,
ProjectSelectorInput.project,
Expand Down Expand Up @@ -301,6 +305,10 @@ test('should send data to Hive (deprecated endpoint)', async () => {
Project.cleanId,
Project.name,
Project.type,
ProjectType.FEDERATION,
ProjectType.STITCHING,
ProjectType.SINGLE,
ProjectType.CUSTOM,
ProjectSelectorInput.organization,
ID,
ProjectSelectorInput.project,
Expand Down Expand Up @@ -678,6 +686,10 @@ test('should not send excluded operation name data to Hive', async () => {
Project.cleanId,
Project.name,
Project.type,
ProjectType.FEDERATION,
ProjectType.STITCHING,
ProjectType.SINGLE,
ProjectType.CUSTOM,
ProjectSelectorInput.organization,
ID,
ProjectSelectorInput.project,
Expand Down

0 comments on commit be5d39c

Please sign in to comment.