From 34d68ddc4448e003ba0acc3b05c0195ddb873b84 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Mon, 20 May 2019 18:14:14 -0500 Subject: [PATCH 01/13] started implementing returning changes on findRemovedTypes --- src/utilities/__tests__/findBreakingChanges-test.js | 6 ++++++ src/utilities/findBreakingChanges.js | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index f9dad88584..de950c5c06 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -41,6 +41,12 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED, description: 'Type1 was removed.', + oldLoc: { + startLine: 2, + startColumn: 7, + endLine: 4, + endColumn: 7, + }, }, ]); expect(findBreakingChanges(oldSchema, oldSchema)).to.deep.equal([]); diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index 42e705b1b4..980154d31e 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -64,9 +64,18 @@ export const DangerousChangeType = Object.freeze({ ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE', }); +export type ChangeLocation = { + startLine: number, + startColumn: number, + endLine: number, + endColumn: number, +}; + export type BreakingChange = { type: $Keys, description: string, + oldLoc?: ChangeLocation, + newLoc?: ChangeLocation, }; export type DangerousChange = { From 52c0bec31f9dd32d5241c3608fa36de14194becb Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Tue, 21 May 2019 11:10:01 -0500 Subject: [PATCH 02/13] adapted the tests for TYPE_REMOVED with location --- src/utilities/__tests__/findBreakingChanges-test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index de950c5c06..678d5d4321 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -676,10 +676,17 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED, description: 'Int was removed.', + oldLoc: undefined, }, { type: BreakingChangeType.TYPE_REMOVED, description: 'TypeThatGetsRemoved was removed.', + oldLoc: { + startLine: 42, + startColumn: 7, + endLine: 44, + endColumn: 7, + }, }, { type: BreakingChangeType.ARG_CHANGED_KIND, From d61e59dd0f8416b0bdc9d9540f26114d594fd086 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Tue, 21 May 2019 16:22:02 -0500 Subject: [PATCH 03/13] adapted test to include real endColumn --- src/utilities/__tests__/findBreakingChanges-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 678d5d4321..6a3ba7894d 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -45,7 +45,7 @@ describe('findBreakingChanges', () => { startLine: 2, startColumn: 7, endLine: 4, - endColumn: 7, + endColumn: 8, }, }, ]); @@ -685,7 +685,7 @@ describe('findBreakingChanges', () => { startLine: 42, startColumn: 7, endLine: 44, - endColumn: 7, + endColumn: 8, }, }, { From 6d86136d3d86a0de511f8c931104bb392b512777 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Wed, 22 May 2019 09:56:20 -0500 Subject: [PATCH 04/13] replaced by ASTNode --- src/utilities/findBreakingChanges.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index 980154d31e..feefd718f3 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -64,18 +64,11 @@ export const DangerousChangeType = Object.freeze({ ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE', }); -export type ChangeLocation = { - startLine: number, - startColumn: number, - endLine: number, - endColumn: number, -}; - export type BreakingChange = { type: $Keys, description: string, - oldLoc?: ChangeLocation, - newLoc?: ChangeLocation, + oldLoc?: ASTNode, + newLoc?: ASTNode, }; export type DangerousChange = { From 04b36f4f6e2d1ba0eb255fe05c1033cfef9f4701 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Wed, 22 May 2019 11:42:58 -0500 Subject: [PATCH 05/13] went to returning the full ASTNode and adapted the tests --- .../__tests__/findBreakingChanges-test.js | 20 ++++++++----------- src/utilities/findBreakingChanges.js | 4 ++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 6a3ba7894d..36195f7cc9 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -37,18 +37,14 @@ describe('findBreakingChanges', () => { const newSchema = buildSchema(` type Type2 `); - expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ - { - type: BreakingChangeType.TYPE_REMOVED, - description: 'Type1 was removed.', - oldLoc: { - startLine: 2, - startColumn: 7, - endLine: 4, - endColumn: 8, - }, - }, - ]); + expect(findBreakingChanges(oldSchema, newSchema)[0]).to.deep.include({ + type: BreakingChangeType.TYPE_REMOVED, + description: 'Type1 was removed.', + }); + // flow ensures that oldNode is of type ASTNode, checking its presence should be enough + expect(findBreakingChanges(oldSchema, newSchema)[0]).to.have.property( + 'oldNode', + ); expect(findBreakingChanges(oldSchema, oldSchema)).to.deep.equal([]); }); diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index feefd718f3..e23b89d0d3 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -67,8 +67,8 @@ export const DangerousChangeType = Object.freeze({ export type BreakingChange = { type: $Keys, description: string, - oldLoc?: ASTNode, - newLoc?: ASTNode, + oldNode?: ASTNode, + newNode?: ASTNode, }; export type DangerousChange = { From 8ee9b94e10ce269d7d36028ef0b407d93e315f2b Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Wed, 22 May 2019 16:10:41 -0500 Subject: [PATCH 06/13] added TYPE_CHANGED_KIND and ARG_CHANGED_KIND --- src/utilities/findBreakingChanges.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index e23b89d0d3..c3e8f1651e 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -201,6 +201,8 @@ function findTypeChanges( description: `${oldType.name} changed from ` + `${typeKindName(oldType)} to ${typeKindName(newType)}.`, + oldNode: oldType.astNode ? oldType.astNode : undefined, + newNode: newType.astNode ? newType.astNode : undefined, }); } } From 23c29c5c8544640f1c7b7af96acce47a37bfc4ce Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Wed, 22 May 2019 18:13:13 -0500 Subject: [PATCH 07/13] added FIELD_REMOVED --- .../__tests__/findBreakingChanges-test.js | 109 +++++++++--------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 36195f7cc9..6b2fb6352a 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -131,60 +131,61 @@ describe('findBreakingChanges', () => { `); const changes = findBreakingChanges(oldSchema, newSchema); - expect(changes).to.deep.equal([ - { - type: BreakingChangeType.FIELD_REMOVED, - description: 'Type1.field2 was removed.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field3 changed type from String to Boolean.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field4 changed type from TypeA to TypeB.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field6 changed type from String to [String].', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field7 changed type from [String] to String.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field9 changed type from Int! to Int.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field10 changed type from [Int]! to [Int].', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field11 changed type from Int to [Int]!.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field13 changed type from [Int!] to [Int].', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field14 changed type from [Int] to [[Int]].', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field15 changed type from [[Int]] to [Int].', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field16 changed type from Int! to [Int]!.', - }, - { - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field18 changed type from [[Int!]!] to [[Int!]].', - }, - ]); + expect(changes[0]).to.deep.include({ + type: BreakingChangeType.FIELD_REMOVED, + description: 'Type1.field2 was removed.', + }); + // $FlowFixMe + expect(changes[0].oldNode.name.value).to.equal('field2'); + expect(changes[0]).not.to.have.property('newNode'); + expect(changes[1]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field3 changed type from String to Boolean.', + }); + expect(changes[2]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field4 changed type from TypeA to TypeB.', + }); + expect(changes[3]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field6 changed type from String to [String].', + }); + expect(changes[4]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field7 changed type from [String] to String.', + }); + expect(changes[5]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field9 changed type from Int! to Int.', + }); + expect(changes[6]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field10 changed type from [Int]! to [Int].', + }); + expect(changes[7]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field11 changed type from Int to [Int]!.', + }); + expect(changes[8]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field13 changed type from [Int!] to [Int].', + }); + expect(changes[9]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field14 changed type from [Int] to [[Int]].', + }); + expect(changes[10]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field15 changed type from [[Int]] to [Int].', + }); + expect(changes[11]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field16 changed type from Int! to [Int]!.', + }); + expect(changes[12]).to.deep.include({ + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field18 changed type from [[Int!]!] to [[Int!]].', + }); }); it('should detect if fields on input types changed kind or were removed', () => { From e02cf5a2efb95453190de2b4e4b46d28d149ca56 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Thu, 23 May 2019 18:05:02 -0500 Subject: [PATCH 08/13] FIELD_CHANGED_KIND was updated in both implem and test --- .../__tests__/findBreakingChanges-test.js | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 6b2fb6352a..4d13c0f51c 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -142,50 +142,98 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field3 changed type from String to Boolean.', }); + // $FlowFixMe + expect(changes[1].oldNode.type.name.value).to.equal('String'); + // $FlowFixMe + expect(changes[1].newNode.type.name.value).to.equal('Boolean'); expect(changes[2]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field4 changed type from TypeA to TypeB.', }); + // $FlowFixMe + expect(changes[2].oldNode.type.name.value).to.equal('TypeA'); + // $FlowFixMe + expect(changes[2].newNode.type.name.value).to.equal('TypeB'); expect(changes[3]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field6 changed type from String to [String].', }); + // $FlowFixMe + expect(changes[3].oldNode.type.name.value).to.equal('String'); + // $FlowFixMe + expect(changes[3].newNode.type.kind).to.equal('ListType'); expect(changes[4]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field7 changed type from [String] to String.', }); + // $FlowFixMe + expect(changes[4].oldNode.type.kind).to.equal('ListType'); + // $FlowFixMe + expect(changes[4].newNode.type.name.value).to.equal('String'); expect(changes[5]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field9 changed type from Int! to Int.', }); + // $FlowFixMe + expect(changes[5].oldNode.type.kind).to.equal('NonNullType'); + // $FlowFixMe + expect(changes[5].newNode.type.name.value).to.equal('Int'); expect(changes[6]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field10 changed type from [Int]! to [Int].', }); + // $FlowFixMe + expect(changes[6].oldNode.type.kind).to.equal('NonNullType'); + // $FlowFixMe + expect(changes[6].newNode.type.kind).to.equal('ListType'); expect(changes[7]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field11 changed type from Int to [Int]!.', }); + // $FlowFixMe + expect(changes[7].oldNode.type.name.value).to.equal('Int'); + // $FlowFixMe + expect(changes[7].newNode.type.kind).to.equal('NonNullType'); expect(changes[8]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field13 changed type from [Int!] to [Int].', }); + // $FlowFixMe + expect(changes[8].oldNode.type.type.kind).to.equal('NonNullType'); + // $FlowFixMe + expect(changes[8].newNode.type.kind).to.equal('ListType'); expect(changes[9]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field14 changed type from [Int] to [[Int]].', }); + // $FlowFixMe + expect(changes[9].oldNode.type.type.name.value).to.equal('Int'); + // $FlowFixMe + expect(changes[9].newNode.type.type.kind).to.equal('ListType'); expect(changes[10]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field15 changed type from [[Int]] to [Int].', }); + // $FlowFixMe + expect(changes[10].oldNode.type.type.kind).to.equal('ListType'); + // $FlowFixMe + expect(changes[10].newNode.type.type.name.value).to.equal('Int'); expect(changes[11]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field16 changed type from Int! to [Int]!.', }); + // $FlowFixMe + expect(changes[11].oldNode.type.type.name.value).to.equal('Int'); + // $FlowFixMe + expect(changes[11].newNode.type.type.kind).to.equal('ListType'); expect(changes[12]).to.deep.include({ type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field18 changed type from [[Int!]!] to [[Int!]].', }); + // $FlowFixMe + expect(changes[12].oldNode.type.type.kind).to.equal('NonNullType'); + // $FlowFixMe + expect(changes[12].newNode.type.type.kind).to.equal('ListType'); }); it('should detect if fields on input types changed kind or were removed', () => { From 78ee3d4048c856e409c1f5ffc49529fbe7f376f5 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Tue, 28 May 2019 18:14:02 -0500 Subject: [PATCH 09/13] refactored tests (not everything running) --- .../__tests__/findBreakingChanges-test.js | 385 ++++++++++++------ 1 file changed, 262 insertions(+), 123 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 4d13c0f51c..12cfb041b5 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -37,14 +37,13 @@ describe('findBreakingChanges', () => { const newSchema = buildSchema(` type Type2 `); - expect(findBreakingChanges(oldSchema, newSchema)[0]).to.deep.include({ - type: BreakingChangeType.TYPE_REMOVED, - description: 'Type1 was removed.', - }); - // flow ensures that oldNode is of type ASTNode, checking its presence should be enough - expect(findBreakingChanges(oldSchema, newSchema)[0]).to.have.property( - 'oldNode', - ); + expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ + { + type: BreakingChangeType.TYPE_REMOVED, + description: 'Type1 was removed.', + oldNode: oldSchema.getType('Type1').astNode, + }, + ]); expect(findBreakingChanges(oldSchema, oldSchema)).to.deep.equal([]); }); @@ -65,16 +64,22 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeWasScalarBecomesEnum changed from a Scalar type to an Enum type.', + oldNode: oldSchema.getType('TypeWasScalarBecomesEnum').astNode, + newNode: newSchema.getType('TypeWasScalarBecomesEnum').astNode, }, { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeWasInterfaceBecomesUnion changed from an Interface type to a Union type.', + oldNode: oldSchema.getType('TypeWasInterfaceBecomesUnion').astNode, + newNode: newSchema.getType('TypeWasInterfaceBecomesUnion').astNode, }, { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeWasObjectBecomesInputObject changed from an Object type to an Input type.', + oldNode: oldSchema.getType('TypeWasObjectBecomesInputObject').astNode, + newNode: newSchema.getType('TypeWasObjectBecomesInputObject').astNode, }, ]); }); @@ -131,109 +136,85 @@ describe('findBreakingChanges', () => { `); const changes = findBreakingChanges(oldSchema, newSchema); - expect(changes[0]).to.deep.include({ - type: BreakingChangeType.FIELD_REMOVED, - description: 'Type1.field2 was removed.', - }); - // $FlowFixMe - expect(changes[0].oldNode.name.value).to.equal('field2'); - expect(changes[0]).not.to.have.property('newNode'); - expect(changes[1]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field3 changed type from String to Boolean.', - }); - // $FlowFixMe - expect(changes[1].oldNode.type.name.value).to.equal('String'); - // $FlowFixMe - expect(changes[1].newNode.type.name.value).to.equal('Boolean'); - expect(changes[2]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field4 changed type from TypeA to TypeB.', - }); - // $FlowFixMe - expect(changes[2].oldNode.type.name.value).to.equal('TypeA'); - // $FlowFixMe - expect(changes[2].newNode.type.name.value).to.equal('TypeB'); - expect(changes[3]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field6 changed type from String to [String].', - }); - // $FlowFixMe - expect(changes[3].oldNode.type.name.value).to.equal('String'); - // $FlowFixMe - expect(changes[3].newNode.type.kind).to.equal('ListType'); - expect(changes[4]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field7 changed type from [String] to String.', - }); - // $FlowFixMe - expect(changes[4].oldNode.type.kind).to.equal('ListType'); - // $FlowFixMe - expect(changes[4].newNode.type.name.value).to.equal('String'); - expect(changes[5]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field9 changed type from Int! to Int.', - }); - // $FlowFixMe - expect(changes[5].oldNode.type.kind).to.equal('NonNullType'); - // $FlowFixMe - expect(changes[5].newNode.type.name.value).to.equal('Int'); - expect(changes[6]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field10 changed type from [Int]! to [Int].', - }); - // $FlowFixMe - expect(changes[6].oldNode.type.kind).to.equal('NonNullType'); - // $FlowFixMe - expect(changes[6].newNode.type.kind).to.equal('ListType'); - expect(changes[7]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field11 changed type from Int to [Int]!.', - }); - // $FlowFixMe - expect(changes[7].oldNode.type.name.value).to.equal('Int'); - // $FlowFixMe - expect(changes[7].newNode.type.kind).to.equal('NonNullType'); - expect(changes[8]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field13 changed type from [Int!] to [Int].', - }); - // $FlowFixMe - expect(changes[8].oldNode.type.type.kind).to.equal('NonNullType'); - // $FlowFixMe - expect(changes[8].newNode.type.kind).to.equal('ListType'); - expect(changes[9]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field14 changed type from [Int] to [[Int]].', - }); - // $FlowFixMe - expect(changes[9].oldNode.type.type.name.value).to.equal('Int'); - // $FlowFixMe - expect(changes[9].newNode.type.type.kind).to.equal('ListType'); - expect(changes[10]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field15 changed type from [[Int]] to [Int].', - }); - // $FlowFixMe - expect(changes[10].oldNode.type.type.kind).to.equal('ListType'); - // $FlowFixMe - expect(changes[10].newNode.type.type.name.value).to.equal('Int'); - expect(changes[11]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field16 changed type from Int! to [Int]!.', - }); - // $FlowFixMe - expect(changes[11].oldNode.type.type.name.value).to.equal('Int'); - // $FlowFixMe - expect(changes[11].newNode.type.type.kind).to.equal('ListType'); - expect(changes[12]).to.deep.include({ - type: BreakingChangeType.FIELD_CHANGED_KIND, - description: 'Type1.field18 changed type from [[Int!]!] to [[Int!]].', - }); - // $FlowFixMe - expect(changes[12].oldNode.type.type.kind).to.equal('NonNullType'); - // $FlowFixMe - expect(changes[12].newNode.type.type.kind).to.equal('ListType'); + expect(changes).to.deep.equal([ + { + type: BreakingChangeType.FIELD_REMOVED, + description: 'Type1.field2 was removed.', + oldNode: oldSchema.getType('Type1').getFields()['field2'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field3 changed type from String to Boolean.', + oldNode: oldSchema.getType('Type1').getFields()['field3'].astNode, + newNode: newSchema.getType('Type1').getFields()['field3'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field4 changed type from TypeA to TypeB.', + oldNode: oldSchema.getType('Type1').getFields()['field4'].astNode, + newNode: newSchema.getType('Type1').getFields()['field4'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field6 changed type from String to [String].', + oldNode: oldSchema.getType('Type1').getFields()['field6'].astNode, + newNode: newSchema.getType('Type1').getFields()['field6'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field7 changed type from [String] to String.', + oldNode: oldSchema.getType('Type1').getFields()['field7'].astNode, + newNode: newSchema.getType('Type1').getFields()['field7'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field9 changed type from Int! to Int.', + oldNode: oldSchema.getType('Type1').getFields()['field9'].astNode, + newNode: newSchema.getType('Type1').getFields()['field9'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field10 changed type from [Int]! to [Int].', + oldNode: oldSchema.getType('Type1').getFields()['field10'].astNode, + newNode: newSchema.getType('Type1').getFields()['field10'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field11 changed type from Int to [Int]!.', + oldNode: oldSchema.getType('Type1').getFields()['field11'].astNode, + newNode: newSchema.getType('Type1').getFields()['field11'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field13 changed type from [Int!] to [Int].', + oldNode: oldSchema.getType('Type1').getFields()['field13'].astNode, + newNode: newSchema.getType('Type1').getFields()['field13'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field14 changed type from [Int] to [[Int]].', + oldNode: oldSchema.getType('Type1').getFields()['field14'].astNode, + newNode: newSchema.getType('Type1').getFields()['field14'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field15 changed type from [[Int]] to [Int].', + oldNode: oldSchema.getType('Type1').getFields()['field15'].astNode, + newNode: newSchema.getType('Type1').getFields()['field15'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field16 changed type from Int! to [Int]!.', + oldNode: oldSchema.getType('Type1').getFields()['field16'].astNode, + newNode: newSchema.getType('Type1').getFields()['field16'].astNode, + }, + { + type: BreakingChangeType.FIELD_CHANGED_KIND, + description: 'Type1.field18 changed type from [[Int!]!] to [[Int!]].', + oldNode: oldSchema.getType('Type1').getFields()['field18'].astNode, + newNode: newSchema.getType('Type1').getFields()['field18'].astNode, + }, + ]); }); it('should detect if fields on input types changed kind or were removed', () => { @@ -277,50 +258,92 @@ describe('findBreakingChanges', () => { `); expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ - { - type: BreakingChangeType.FIELD_REMOVED, - description: 'InputType1.field2 was removed.', - }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field1 changed type from String to Int.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field1'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field1'] + .astNode, + }, + { + type: BreakingChangeType.FIELD_REMOVED, + description: 'InputType1.field2 was removed.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field2'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field3 changed type from [String] to String.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field3'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field3'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field5 changed type from String to String!.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field5'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field5'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field6 changed type from [Int] to [Int]!.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field6'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field6'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field8 changed type from Int to [Int]!.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field8'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field8'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field9 changed type from [Int] to [Int!].', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field9'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field9'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field11 changed type from [Int] to [[Int]].', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field11'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field11'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field12 changed type from [[Int]] to [Int].', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field12'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field12'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field13 changed type from Int! to [Int]!.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field13'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field13'] + .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field15 changed type from [[Int]!] to [[Int!]!].', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field15'] + .astNode, + newNode: newSchema.getTypeMap()['InputType1'].getFields()['field15'] + .astNode, }, ]); }); @@ -346,6 +369,8 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, description: 'A required field requiredField on input type InputType1 was added.', + newNode: newSchema.getType('InputType1').getFields()['requiredField'] + .astNode, }, ]); }); @@ -370,10 +395,12 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED_FROM_UNION, description: 'Type2 was removed from union type UnionType1.', + oldNode: oldSchema.getTypeMap()['UnionType1'].astNode, }, ]); }); + // TODO: complete test it('should detect if a value was removed from an enum type', () => { const oldSchema = buildSchema(` enum EnumType1 { @@ -424,14 +451,26 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.ARG_REMOVED, description: 'Interface1.field1 arg arg1 was removed.', + oldNode: oldSchema + .getType('Interface1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg1').astNode, }, { type: BreakingChangeType.ARG_REMOVED, description: 'Interface1.field1 arg objectArg was removed.', + oldNode: oldSchema + .getType('Interface1') + .getFields() + ['field1'].args.find(arg => arg.name === 'objectArg').astNode, }, { type: BreakingChangeType.ARG_REMOVED, description: 'Type1.field1 arg name was removed.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'name').astNode, }, ]); }); @@ -486,61 +525,157 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg1 has changed type from String to Int.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg1').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg1').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg2 has changed type from String to [String].', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg2').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg2').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg3 has changed type from [String] to String.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg3').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg3').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg4 has changed type from String to String!.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg4').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg4').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg5 has changed type from String! to Int.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg5').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg5').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg6 has changed type from String! to Int!.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg6').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg6').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg8 has changed type from Int to [Int]!.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg8').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg8').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg9 has changed type from [Int] to [Int!].', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg9').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg9').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg11 has changed type from [Int] to [[Int]].', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg11').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg11').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg12 has changed type from [[Int]] to [Int].', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg12').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg12').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg13 has changed type from Int! to [Int]!.', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg13').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg13').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg15 has changed type from [[Int]!] to [[Int!]!].', + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg15').astNode, + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg15').astNode, }, ]); }); @@ -567,6 +702,10 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.REQUIRED_ARG_ADDED, description: 'A required arg newRequiredArg on Type1.field1 was added.', + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'newRequiredArg').astNode, }, ]); }); @@ -611,6 +750,7 @@ describe('findBreakingChanges', () => { expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([]); }); + // TODO: implement test changes it('should detect interfaces removed from types', () => { const oldSchema = buildSchema(` interface Interface1 @@ -650,7 +790,8 @@ describe('findBreakingChanges', () => { expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([]); }); - it('should detect all breaking changes', () => { + // TODO: unskip and complete implem + it.skip('should detect all breaking changes', () => { const oldSchema = buildSchema(` directive @DirectiveThatIsRemoved on FIELD_DEFINITION @@ -721,17 +862,10 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED, description: 'Int was removed.', - oldLoc: undefined, }, { type: BreakingChangeType.TYPE_REMOVED, description: 'TypeThatGetsRemoved was removed.', - oldLoc: { - startLine: 42, - startColumn: 7, - endLine: 44, - endColumn: 8, - }, }, { type: BreakingChangeType.ARG_CHANGED_KIND, @@ -787,6 +921,7 @@ describe('findBreakingChanges', () => { ]); }); + // TODO: implement DIRECTIVE changes it('should detect if a directive was explicitly removed', () => { const oldSchema = buildSchema(` directive @DirectiveThatIsRemoved on FIELD_DEFINITION @@ -805,6 +940,7 @@ describe('findBreakingChanges', () => { ]); }); + // TODO: implement DIRECTIVE changes it('should detect if a directive was implicitly removed', () => { const oldSchema = new GraphQLSchema({}); @@ -820,6 +956,7 @@ describe('findBreakingChanges', () => { ]); }); + // TODO: implement DIRECTIVE changes it('should detect if a directive argument was removed', () => { const oldSchema = buildSchema(` directive @DirectiveWithArg(arg1: String) on FIELD_DEFINITION @@ -850,6 +987,7 @@ describe('findBreakingChanges', () => { ) on FIELD_DEFINITION `); + // TODO: implement DIRECTIVE changes expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ { type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, @@ -859,6 +997,7 @@ describe('findBreakingChanges', () => { ]); }); + // TODO: implement DIRECTIVE changes it('should detect locations removed from a directive', () => { const oldSchema = buildSchema(` directive @DirectiveName on FIELD_DEFINITION | QUERY From c1b1681be7b644eaa4106d42cf58d2b2019f7e8a Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Tue, 28 May 2019 19:15:34 -0500 Subject: [PATCH 10/13] issue on pulling --- src/utilities/__tests__/findBreakingChanges-test.js | 6 ++++++ src/utilities/findBreakingChanges.js | 1 + 2 files changed, 7 insertions(+) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 12cfb041b5..835a349327 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -258,6 +258,12 @@ describe('findBreakingChanges', () => { `); expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ + { + type: BreakingChangeType.FIELD_REMOVED, + description: 'InputType1.field2 was removed.', + oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field2'] + .astNode, + }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field1 changed type from String to Int.', diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index c3e8f1651e..0a7335f33e 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -181,6 +181,7 @@ function findTypeChanges( schemaChanges.push({ type: BreakingChangeType.TYPE_REMOVED, description: `${oldType.name} was removed.`, + oldNode: oldType.astNode ? oldType.astNode : undefined, }); } From 3808296d23144533e14c5d2c35476bd3812fe54c Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Fri, 31 May 2019 12:23:08 -0500 Subject: [PATCH 11/13] BreakingChanges almost done, one test skipped to complete --- .../__tests__/findBreakingChanges-test.js | 118 ++++++++++++++++-- src/utilities/findBreakingChanges.js | 20 +++ 2 files changed, 125 insertions(+), 13 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index 835a349327..cf11c034af 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -41,6 +41,7 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED, description: 'Type1 was removed.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').astNode, }, ]); @@ -64,21 +65,27 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeWasScalarBecomesEnum changed from a Scalar type to an Enum type.', + // $FlowFixMe oldNode: oldSchema.getType('TypeWasScalarBecomesEnum').astNode, + // $FlowFixMe newNode: newSchema.getType('TypeWasScalarBecomesEnum').astNode, }, { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeWasInterfaceBecomesUnion changed from an Interface type to a Union type.', + // $FlowFixMe oldNode: oldSchema.getType('TypeWasInterfaceBecomesUnion').astNode, + // $FlowFixMe newNode: newSchema.getType('TypeWasInterfaceBecomesUnion').astNode, }, { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeWasObjectBecomesInputObject changed from an Object type to an Input type.', + // $FlowFixMe oldNode: oldSchema.getType('TypeWasObjectBecomesInputObject').astNode, + // $FlowFixMe newNode: newSchema.getType('TypeWasObjectBecomesInputObject').astNode, }, ]); @@ -140,78 +147,103 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.FIELD_REMOVED, description: 'Type1.field2 was removed.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field2'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field3 changed type from String to Boolean.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field3'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field3'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field4 changed type from TypeA to TypeB.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field4'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field4'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field6 changed type from String to [String].', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field6'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field6'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field7 changed type from [String] to String.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field7'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field7'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field9 changed type from Int! to Int.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field9'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field9'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field10 changed type from [Int]! to [Int].', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field10'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field10'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field11 changed type from Int to [Int]!.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field11'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field11'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field13 changed type from [Int!] to [Int].', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field13'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field13'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field14 changed type from [Int] to [[Int]].', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field14'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field14'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field15 changed type from [[Int]] to [Int].', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field15'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field15'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field16 changed type from Int! to [Int]!.', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field16'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field16'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'Type1.field18 changed type from [[Int!]!] to [[Int!]].', + // $FlowFixMe oldNode: oldSchema.getType('Type1').getFields()['field18'].astNode, + // $FlowFixMe newNode: newSchema.getType('Type1').getFields()['field18'].astNode, }, ]); @@ -261,84 +293,97 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.FIELD_REMOVED, description: 'InputType1.field2 was removed.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field2'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field1 changed type from String to Int.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field1'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field1'] .astNode, }, - { - type: BreakingChangeType.FIELD_REMOVED, - description: 'InputType1.field2 was removed.', - oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field2'] - .astNode, - }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field3 changed type from [String] to String.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field3'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field3'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field5 changed type from String to String!.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field5'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field5'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field6 changed type from [Int] to [Int]!.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field6'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field6'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field8 changed type from Int to [Int]!.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field8'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field8'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field9 changed type from [Int] to [Int!].', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field9'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field9'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field11 changed type from [Int] to [[Int]].', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field11'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field11'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field12 changed type from [[Int]] to [Int].', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field12'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field12'] .astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field13 changed type from Int! to [Int]!.', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field13'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field13'] .astNode, }, @@ -346,8 +391,10 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'InputType1.field15 changed type from [[Int]!] to [[Int!]!].', + // $FlowFixMe oldNode: oldSchema.getTypeMap()['InputType1'].getFields()['field15'] .astNode, + // $FlowFixMe newNode: newSchema.getTypeMap()['InputType1'].getFields()['field15'] .astNode, }, @@ -375,6 +422,7 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, description: 'A required field requiredField on input type InputType1 was added.', + // $FlowFixMe newNode: newSchema.getType('InputType1').getFields()['requiredField'] .astNode, }, @@ -401,7 +449,11 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED_FROM_UNION, description: 'Type2 was removed from union type UnionType1.', - oldNode: oldSchema.getTypeMap()['UnionType1'].astNode, + // $FlowFixMe + oldNode: oldSchema + .getTypeMap() + ['UnionType1'].getTypes() + .find(type => type.name === 'Type2').astNode, }, ]); }); @@ -428,6 +480,8 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.VALUE_REMOVED_FROM_ENUM, description: 'VALUE1 was removed from enum type EnumType1.', + // $FlowFixMe + oldNode: oldSchema.getType('EnumType1').getValue('VALUE1').astNode, }, ]); }); @@ -457,6 +511,7 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.ARG_REMOVED, description: 'Interface1.field1 arg arg1 was removed.', + // $FlowFixMe oldNode: oldSchema .getType('Interface1') .getFields() @@ -465,6 +520,7 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.ARG_REMOVED, description: 'Interface1.field1 arg objectArg was removed.', + // $FlowFixMe oldNode: oldSchema .getType('Interface1') .getFields() @@ -473,6 +529,7 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.ARG_REMOVED, description: 'Type1.field1 arg name was removed.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() @@ -531,10 +588,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg1 has changed type from String to Int.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg1').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -544,10 +603,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg2 has changed type from String to [String].', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg2').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -557,10 +618,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg3 has changed type from [String] to String.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg3').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -570,10 +633,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg4 has changed type from String to String!.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg4').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -583,10 +648,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg5 has changed type from String! to Int.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg5').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -596,10 +663,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg6 has changed type from String! to Int!.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg6').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -609,10 +678,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg8 has changed type from Int to [Int]!.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg8').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -622,10 +693,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg9 has changed type from [Int] to [Int!].', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg9').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -635,10 +708,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg11 has changed type from [Int] to [[Int]].', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg11').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -648,10 +723,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg12 has changed type from [[Int]] to [Int].', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg12').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -661,10 +738,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg13 has changed type from Int! to [Int]!.', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg13').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -674,10 +753,12 @@ describe('findBreakingChanges', () => { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'Type1.field1 arg arg15 has changed type from [[Int]!] to [[Int!]!].', + // $FlowFixMe oldNode: oldSchema .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'arg15').astNode, + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -708,6 +789,7 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.REQUIRED_ARG_ADDED, description: 'A required arg newRequiredArg on Type1.field1 was added.', + // $FlowFixMe newNode: newSchema .getType('Type1') .getFields() @@ -774,6 +856,8 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, description: 'Type1 no longer implements interface Interface1.', + // $FlowFixMe + oldNode: oldSchema.getType('Type1').astNode, }, ]); }); @@ -927,7 +1011,6 @@ describe('findBreakingChanges', () => { ]); }); - // TODO: implement DIRECTIVE changes it('should detect if a directive was explicitly removed', () => { const oldSchema = buildSchema(` directive @DirectiveThatIsRemoved on FIELD_DEFINITION @@ -942,11 +1025,12 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.DIRECTIVE_REMOVED, description: 'DirectiveThatIsRemoved was removed.', + // $FlowFixMe + oldNode: oldSchema.getDirective('DirectiveThatIsRemoved').astNode, }, ]); }); - // TODO: implement DIRECTIVE changes it('should detect if a directive was implicitly removed', () => { const oldSchema = new GraphQLSchema({}); @@ -958,11 +1042,11 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.DIRECTIVE_REMOVED, description: `${GraphQLDeprecatedDirective.name} was removed.`, + oldNode: undefined, }, ]); }); - // TODO: implement DIRECTIVE changes it('should detect if a directive argument was removed', () => { const oldSchema = buildSchema(` directive @DirectiveWithArg(arg1: String) on FIELD_DEFINITION @@ -976,11 +1060,15 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.DIRECTIVE_ARG_REMOVED, description: 'arg1 was removed from DirectiveWithArg.', + // $FlowFixMe + oldNode: oldSchema + .getDirective('DirectiveWithArg') + .args.find(arg => arg.name === 'arg1').astNode, }, ]); }); - it('should detect if an optional directive argument was added', () => { + it('should detect if an required directive argument was added', () => { const oldSchema = buildSchema(` directive @DirectiveName on FIELD_DEFINITION `); @@ -993,17 +1081,19 @@ describe('findBreakingChanges', () => { ) on FIELD_DEFINITION `); - // TODO: implement DIRECTIVE changes expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([ { type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, description: 'A required arg newRequiredArg on directive DirectiveName was added.', + // $FlowFixMe + newNode: newSchema + .getDirective('DirectiveName') + .args.find(arg => arg.name === 'newRequiredArg').astNode, }, ]); }); - // TODO: implement DIRECTIVE changes it('should detect locations removed from a directive', () => { const oldSchema = buildSchema(` directive @DirectiveName on FIELD_DEFINITION | QUERY @@ -1017,6 +1107,8 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, description: 'QUERY was removed from DirectiveName.', + // $FlowFixMe + oldNode: oldSchema.getDirective('DirectiveName').astNode, }, ]); }); diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index 0a7335f33e..ce2db594e4 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -36,6 +36,7 @@ import { } from '../type/definition'; import { type GraphQLSchema } from '../type/schema'; import { astFromValue } from './astFromValue'; +import { type ASTNode } from './../language/ast'; export const BreakingChangeType = Object.freeze({ TYPE_REMOVED: 'TYPE_REMOVED', @@ -129,6 +130,7 @@ function findDirectiveChanges( schemaChanges.push({ type: BreakingChangeType.DIRECTIVE_REMOVED, description: `${oldDirective.name} was removed.`, + oldNode: oldDirective.astNode ? oldDirective.astNode : undefined, }); } @@ -142,6 +144,7 @@ function findDirectiveChanges( description: `A required arg ${newArg.name} on directive ` + `${oldDirective.name} was added.`, + newNode: newArg.astNode ? newArg.astNode : undefined, }); } } @@ -150,6 +153,7 @@ function findDirectiveChanges( schemaChanges.push({ type: BreakingChangeType.DIRECTIVE_ARG_REMOVED, description: `${oldArg.name} was removed from ${oldDirective.name}.`, + oldNode: oldArg.astNode ? oldArg.astNode : undefined, }); } @@ -158,6 +162,8 @@ function findDirectiveChanges( schemaChanges.push({ type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, description: `${location} was removed from ${oldDirective.name}.`, + // locations are not a node, so the full directive is returned + oldNode: oldDirective.astNode ? oldDirective.astNode : undefined, }); } } @@ -228,6 +234,7 @@ function findInputObjectTypeChanges( description: `A required field ${newField.name} on ` + `input type ${oldType.name} was added.`, + newNode: newField.astNode ? newField.astNode : undefined, }); } else { schemaChanges.push({ @@ -243,6 +250,7 @@ function findInputObjectTypeChanges( schemaChanges.push({ type: BreakingChangeType.FIELD_REMOVED, description: `${oldType.name}.${oldField.name} was removed.`, + oldNode: oldField.astNode ? oldField.astNode : undefined, }); } @@ -257,6 +265,8 @@ function findInputObjectTypeChanges( description: `${oldType.name}.${oldField.name} changed type from ` + `${String(oldField.type)} to ${String(newField.type)}.`, + oldNode: oldField.astNode ? oldField.astNode : undefined, + newNode: newField.astNode ? newField.astNode : undefined, }); } } @@ -286,6 +296,7 @@ function findUnionTypeChanges( description: `${oldPossibleType.name} was removed from ` + `union type ${oldType.name}.`, + oldNode: oldPossibleType.astNode ? oldPossibleType.astNode : undefined, }); } @@ -312,6 +323,7 @@ function findEnumTypeChanges( description: `${oldValue.name} was removed from enum type ${ oldType.name }.`, + oldNode: oldValue.astNode ? oldValue.astNode : undefined, }); } @@ -340,6 +352,7 @@ function findObjectTypeChanges( description: `${oldType.name} no longer implements interface ` + `${oldInterface.name}.`, + oldNode: oldType.astNode ? oldType.astNode : undefined, }); } @@ -360,6 +373,7 @@ function findFieldChanges( schemaChanges.push({ type: BreakingChangeType.FIELD_REMOVED, description: `${oldType.name}.${oldField.name} was removed.`, + oldNode: oldField.astNode ? oldField.astNode : undefined, }); } @@ -376,6 +390,8 @@ function findFieldChanges( description: `${oldType.name}.${oldField.name} changed type from ` + `${String(oldField.type)} to ${String(newField.type)}.`, + oldNode: oldField.astNode ? oldField.astNode : undefined, + newNode: newField.astNode ? newField.astNode : undefined, }); } } @@ -397,6 +413,7 @@ function findArgChanges( description: `${oldType.name}.${oldField.name} arg ${ oldArg.name } was removed.`, + oldNode: oldArg.astNode ? oldArg.astNode : undefined, }); } @@ -412,6 +429,8 @@ function findArgChanges( `${oldType.name}.${oldField.name} arg ` + `${oldArg.name} has changed type from ` + `${String(oldArg.type)} to ${String(newArg.type)}.`, + oldNode: oldArg.astNode ? oldArg.astNode : undefined, + newNode: newArg.astNode ? newArg.astNode : undefined, }); } else if (oldArg.defaultValue !== undefined) { if (newArg.defaultValue === undefined) { @@ -445,6 +464,7 @@ function findArgChanges( description: `A required arg ${newArg.name} on ` + `${oldType.name}.${oldField.name} was added.`, + newNode: newArg.astNode ? newArg.astNode : undefined, }); } else { schemaChanges.push({ From c2d507666faf86daf9ecc1f047ce9cf2d83a00b6 Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Fri, 31 May 2019 14:36:33 -0500 Subject: [PATCH 12/13] finished breaking changes, started dangerous changes --- .../__tests__/findBreakingChanges-test.js | 104 +++++++++++++++++- src/utilities/findBreakingChanges.js | 4 + 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index cf11c034af..a47780279b 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -880,8 +880,7 @@ describe('findBreakingChanges', () => { expect(findBreakingChanges(oldSchema, newSchema)).to.deep.equal([]); }); - // TODO: unskip and complete implem - it.skip('should detect all breaking changes', () => { + it('should detect all breaking changes', () => { const oldSchema = buildSchema(` directive @DirectiveThatIsRemoved on FIELD_DEFINITION @@ -952,61 +951,113 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED, description: 'Int was removed.', + // $FlowFixMe + oldNode: oldSchema.getType('Int').astNode, }, { type: BreakingChangeType.TYPE_REMOVED, description: 'TypeThatGetsRemoved was removed.', + // $FlowFixMe + oldNode: oldSchema.getType('TypeThatGetsRemoved').astNode, }, { type: BreakingChangeType.ARG_CHANGED_KIND, description: 'ArgThatChanges.field1 arg id has changed type from Int to String.', + // $FlowFixMe + oldNode: oldSchema + .getType('ArgThatChanges') + .getFields() + ['field1'].args.find(arg => arg.name === 'id').astNode, + // $FlowFixMe + newNode: newSchema + .getType('ArgThatChanges') + .getFields() + ['field1'].args.find(arg => arg.name === 'id').astNode, }, { type: BreakingChangeType.VALUE_REMOVED_FROM_ENUM, description: 'VALUE0 was removed from enum type EnumTypeThatLosesAValue.', + // $FlowFixMe + oldNode: oldSchema.getType('EnumTypeThatLosesAValue').getValue('VALUE0') + .astNode, }, { type: BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, description: 'TypeThatLooseInterface1 no longer implements interface Interface1.', + // $FlowFixMe + oldNode: oldSchema.getType('TypeThatLooseInterface1').astNode, }, { type: BreakingChangeType.TYPE_REMOVED_FROM_UNION, description: 'TypeInUnion2 was removed from union type UnionTypeThatLosesAType.', + // $FlowFixMe + oldNode: oldSchema + .getTypeMap() + ['UnionTypeThatLosesAType'].getTypes() + .find(type => type.name === 'TypeInUnion2').astNode, }, { type: BreakingChangeType.TYPE_CHANGED_KIND, description: 'TypeThatChangesType changed from an Object type to an Interface type.', + // $FlowFixMe + oldNode: oldSchema.getType('TypeThatChangesType').astNode, + // $FlowFixMe + newNode: newSchema.getType('TypeThatChangesType').astNode, }, { type: BreakingChangeType.FIELD_REMOVED, description: 'TypeThatHasBreakingFieldChanges.field1 was removed.', + // $FlowFixMe + oldNode: oldSchema + .getType('TypeThatHasBreakingFieldChanges') + .getFields()['field1'].astNode, }, { type: BreakingChangeType.FIELD_CHANGED_KIND, description: 'TypeThatHasBreakingFieldChanges.field2 changed type from String to Boolean.', + // $FlowFixMe + oldNode: oldSchema + .getType('TypeThatHasBreakingFieldChanges') + .getFields()['field2'].astNode, + // $FlowFixMe + newNode: newSchema + .getType('TypeThatHasBreakingFieldChanges') + .getFields()['field2'].astNode, }, { type: BreakingChangeType.DIRECTIVE_REMOVED, description: 'DirectiveThatIsRemoved was removed.', + // $FlowFixMe + oldNode: oldSchema.getDirective('DirectiveThatIsRemoved').astNode, }, { type: BreakingChangeType.DIRECTIVE_ARG_REMOVED, description: 'arg1 was removed from DirectiveThatRemovesArg.', + // $FlowFixMe + oldNode: oldSchema + .getDirective('DirectiveThatRemovesArg') + .args.find(arg => arg.name === 'arg1').astNode, }, { type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, description: 'A required arg arg1 on directive NonNullDirectiveAdded was added.', + // $FlowFixMe + newNode: newSchema + .getDirective('NonNullDirectiveAdded') + .args.find(arg => arg.name === 'arg1').astNode, }, { type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, description: 'QUERY was removed from DirectiveName.', + // $FlowFixMe + oldNode: oldSchema.getDirective('DirectiveName').astNode, }, ]); }); @@ -1169,26 +1220,73 @@ describe('findDangerousChanges', () => { type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, description: 'Type1.field1 arg withDefaultValue defaultValue was removed.', + // $FlowFixMe + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'withDefaultValue').astNode, + // $FlowFixMe + newNode: undefined, }, { type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, description: 'Type1.field1 arg stringArg has changed defaultValue from "test" to "Test".', + // $FlowFixMe + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'stringArg').astNode, + // $FlowFixMe + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'stringArg').astNode, }, { type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, description: 'Type1.field1 arg emptyArray has changed defaultValue from [] to [7].', + // $FlowFixMe + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'emptyArray').astNode, + // $FlowFixMe + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'emptyArray').astNode, }, { type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, description: 'Type1.field1 arg valueArray has changed defaultValue from [["a", "b"], ["c"]] to [["b", "a"], ["d"]].', + // $FlowFixMe + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'valueArray').astNode, + // $FlowFixMe + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'valueArray').astNode, }, { type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, description: 'Type1.field1 arg complexObject has changed defaultValue from {innerInputArray: [{arrayField: [1, 2, 3]}]} to {innerInputArray: [{arrayField: [3, 2, 1]}]}.', + // $FlowFixMe + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'complexObject').astNode, + // $FlowFixMe + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'complexObject').astNode, }, ]); }); @@ -1318,7 +1416,7 @@ describe('findDangerousChanges', () => { ]); }); - it('should find all dangerous changes', () => { + it.skip('should find all dangerous changes', () => { const oldSchema = buildSchema(` enum EnumType1 { VALUE0 diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index ce2db594e4..401d15e667 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -439,6 +439,8 @@ function findArgChanges( description: `${oldType.name}.${oldField.name} arg ` + `${oldArg.name} defaultValue was removed.`, + oldNode: oldArg.astNode ? oldArg.astNode : undefined, + newNode: undefined, }); } else { const oldValueStr = stringifyValue(oldArg.defaultValue, oldArg.type); @@ -451,6 +453,8 @@ function findArgChanges( `${oldType.name}.${oldField.name} arg ` + `${oldArg.name} has changed defaultValue ` + `from ${oldValueStr} to ${newValueStr}.`, + oldNode: oldArg.astNode ? oldArg.astNode : undefined, + newNode: newArg.astNode ? newArg.astNode : undefined, }); } } From 688d55fc233eb4ea0c058ccd9b1657872e2f495b Mon Sep 17 00:00:00 2001 From: Maxime Burlat Date: Fri, 31 May 2019 15:24:06 -0500 Subject: [PATCH 13/13] fully implemented without extension nodes --- .../__tests__/findBreakingChanges-test.js | 61 +++++++++++++++---- src/utilities/findBreakingChanges.js | 11 +++- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/src/utilities/__tests__/findBreakingChanges-test.js b/src/utilities/__tests__/findBreakingChanges-test.js index a47780279b..3b2666b9c8 100644 --- a/src/utilities/__tests__/findBreakingChanges-test.js +++ b/src/utilities/__tests__/findBreakingChanges-test.js @@ -449,16 +449,12 @@ describe('findBreakingChanges', () => { { type: BreakingChangeType.TYPE_REMOVED_FROM_UNION, description: 'Type2 was removed from union type UnionType1.', - // $FlowFixMe - oldNode: oldSchema - .getTypeMap() - ['UnionType1'].getTypes() - .find(type => type.name === 'Type2').astNode, + oldNode: oldSchema.getTypeMap()['UnionType1'].astNode, + newNode: newSchema.getTypeMap()['UnionType1'].astNode, }, ]); }); - // TODO: complete test it('should detect if a value was removed from an enum type', () => { const oldSchema = buildSchema(` enum EnumType1 { @@ -858,6 +854,8 @@ describe('findBreakingChanges', () => { description: 'Type1 no longer implements interface Interface1.', // $FlowFixMe oldNode: oldSchema.getType('Type1').astNode, + // $FlowFixMe + newNode: newSchema.getType('Type1').astNode, }, ]); }); @@ -989,16 +987,15 @@ describe('findBreakingChanges', () => { 'TypeThatLooseInterface1 no longer implements interface Interface1.', // $FlowFixMe oldNode: oldSchema.getType('TypeThatLooseInterface1').astNode, + // $FlowFixMe + newNode: newSchema.getType('TypeThatLooseInterface1').astNode, }, { type: BreakingChangeType.TYPE_REMOVED_FROM_UNION, description: 'TypeInUnion2 was removed from union type UnionTypeThatLosesAType.', - // $FlowFixMe - oldNode: oldSchema - .getTypeMap() - ['UnionTypeThatLosesAType'].getTypes() - .find(type => type.name === 'TypeInUnion2').astNode, + oldNode: oldSchema.getTypeMap()['UnionTypeThatLosesAType'].astNode, + newNode: newSchema.getTypeMap()['UnionTypeThatLosesAType'].astNode, }, { type: BreakingChangeType.TYPE_CHANGED_KIND, @@ -1225,7 +1222,6 @@ describe('findDangerousChanges', () => { .getType('Type1') .getFields() ['field1'].args.find(arg => arg.name === 'withDefaultValue').astNode, - // $FlowFixMe newNode: undefined, }, { @@ -1343,6 +1339,8 @@ describe('findDangerousChanges', () => { { type: DangerousChangeType.VALUE_ADDED_TO_ENUM, description: 'VALUE2 was added to enum type EnumType1.', + // $FlowFixMe + newNode: newSchema.getType('EnumType1').getValue('VALUE2').astNode, }, ]); }); @@ -1366,6 +1364,10 @@ describe('findDangerousChanges', () => { { type: DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, description: 'NewInterface added to interfaces implemented by Type1.', + // $FlowFixMe + oldNode: oldSchema.getType('Type1').astNode, + // $FlowFixMe + newNode: newSchema.getType('Type1').astNode, }, ]); }); @@ -1389,6 +1391,10 @@ describe('findDangerousChanges', () => { { type: DangerousChangeType.TYPE_ADDED_TO_UNION, description: 'Type2 was added to union type UnionType1.', + // $FlowFixMe + oldNode: oldSchema.getType('UnionType1').astNode, + // $FlowFixMe + newNode: newSchema.getType('UnionType1').astNode, }, ]); }); @@ -1412,11 +1418,13 @@ describe('findDangerousChanges', () => { type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, description: 'An optional field field2 on input type InputType1 was added.', + // $FlowFixMe + newNode: newSchema.getType('InputType1').getFields()['field2'].astNode, }, ]); }); - it.skip('should find all dangerous changes', () => { + it('should find all dangerous changes', () => { const oldSchema = buildSchema(` enum EnumType1 { VALUE0 @@ -1457,21 +1465,43 @@ describe('findDangerousChanges', () => { { type: DangerousChangeType.VALUE_ADDED_TO_ENUM, description: 'VALUE2 was added to enum type EnumType1.', + // $FlowFixMe + newNode: newSchema.getType('EnumType1').getValue('VALUE2').astNode, }, { type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, description: 'Type1.field1 arg argThatChangesDefaultValue has changed defaultValue from "test" to "Test".', + // $FlowFixMe + oldNode: oldSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'argThatChangesDefaultValue') + .astNode, + // $FlowFixMe + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'argThatChangesDefaultValue') + .astNode, }, { type: DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, description: 'Interface1 added to interfaces implemented by TypeThatGainsInterface1.', + // $FlowFixMe + oldNode: oldSchema.getType('TypeThatGainsInterface1').astNode, + // $FlowFixMe + newNode: newSchema.getType('TypeThatGainsInterface1').astNode, }, { type: DangerousChangeType.TYPE_ADDED_TO_UNION, description: 'TypeInUnion2 was added to union type UnionTypeThatGainsAType.', + // $FlowFixMe + oldNode: oldSchema.getType('UnionTypeThatGainsAType').astNode, + // $FlowFixMe + newNode: newSchema.getType('UnionTypeThatGainsAType').astNode, }, ]); }); @@ -1493,6 +1523,11 @@ describe('findDangerousChanges', () => { { type: DangerousChangeType.OPTIONAL_ARG_ADDED, description: 'An optional arg arg2 on Type1.field1 was added.', + // $FlowFixMe + newNode: newSchema + .getType('Type1') + .getFields() + ['field1'].args.find(arg => arg.name === 'arg2').astNode, }, ]); }); diff --git a/src/utilities/findBreakingChanges.js b/src/utilities/findBreakingChanges.js index 401d15e667..f4e79bb0e1 100644 --- a/src/utilities/findBreakingChanges.js +++ b/src/utilities/findBreakingChanges.js @@ -242,6 +242,7 @@ function findInputObjectTypeChanges( description: `An optional field ${newField.name} on ` + `input type ${oldType.name} was added.`, + newNode: newField.astNode ? newField.astNode : undefined, }); } } @@ -287,6 +288,8 @@ function findUnionTypeChanges( description: `${newPossibleType.name} was added to union type ${ oldType.name }.`, + oldNode: oldType.astNode ? oldType.astNode : undefined, + newNode: newType.astNode ? newType.astNode : undefined, }); } @@ -296,7 +299,8 @@ function findUnionTypeChanges( description: `${oldPossibleType.name} was removed from ` + `union type ${oldType.name}.`, - oldNode: oldPossibleType.astNode ? oldPossibleType.astNode : undefined, + oldNode: oldType.astNode ? oldType.astNode : undefined, + newNode: newType.astNode ? newType.astNode : undefined, }); } @@ -314,6 +318,7 @@ function findEnumTypeChanges( schemaChanges.push({ type: DangerousChangeType.VALUE_ADDED_TO_ENUM, description: `${newValue.name} was added to enum type ${oldType.name}.`, + newNode: newValue.astNode ? newValue.astNode : undefined, }); } @@ -343,6 +348,8 @@ function findObjectTypeChanges( description: `${newInterface.name} added to interfaces implemented ` + `by ${oldType.name}.`, + oldNode: oldType.astNode ? oldType.astNode : undefined, + newNode: newType.astNode ? newType.astNode : undefined, }); } @@ -353,6 +360,7 @@ function findObjectTypeChanges( `${oldType.name} no longer implements interface ` + `${oldInterface.name}.`, oldNode: oldType.astNode ? oldType.astNode : undefined, + newNode: newType.astNode ? newType.astNode : undefined, }); } @@ -476,6 +484,7 @@ function findArgChanges( description: `An optional arg ${newArg.name} on ` + `${oldType.name}.${oldField.name} was added.`, + newNode: newArg.astNode ? newArg.astNode : undefined, }); } }