Repository: kamilkisiela/graphql-inspector
Pull request #95 (2019-03-08 15:06:22)

Added diff support for arrays and objects
When diffing `defaultValue`, we sometimes get an object or array back. Added custom handling for such cases.


Co-authored-by: Andreas Hubel <andreas.hubel@br.de>

kamilkisiela: Thank you, I'll release it today :)

Patch:
diff --git a/.gitignore b/.gitignore
index 78549aa9..78f6a68b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ yarn-error.log
 **/*/yarn-error.log
 .env
 private-key.pem
+.DS_Store
\ No newline at end of file
diff --git a/packages/core/src/diff/argument.ts b/packages/core/src/diff/argument.ts
index 1f72ed3b..acfc8f73 100644
--- a/packages/core/src/diff/argument.ts
+++ b/packages/core/src/diff/argument.ts
@@ -11,6 +11,7 @@ import {
   fieldArgumentDefaultChanged,
   fieldArgumentTypeChanged,
 } from './changes/argument';
+import {diffArrays} from '../utils/arrays';
 
 export function changesInArgument(
   type: GraphQLObjectType | GraphQLInterfaceType,
@@ -25,7 +26,20 @@ export function changesInArgument(
   }
 
   if (oldArg.defaultValue !== newArg.defaultValue) {
-    changes.push(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
+    if (
+      Array.isArray(oldArg.defaultValue) &&
+      Array.isArray(newArg.defaultValue)
+    ) {
+      const diff = diffArrays(oldArg.defaultValue, newArg.defaultValue);
+      if (diff.length > 0) {
+        changes.push(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
+      }
+    } else if (
+      JSON.stringify(oldArg.defaultValue) !==
+      JSON.stringify(newArg.defaultValue)
+    ) {
+      changes.push(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
+    }
   }
 
   if (oldArg.type.toString() !== newArg.type.toString()) {
diff --git a/packages/core/src/diff/input.ts b/packages/core/src/diff/input.ts
index ed1aef1a..a921647d 100644
--- a/packages/core/src/diff/input.ts
+++ b/packages/core/src/diff/input.ts
@@ -48,7 +48,19 @@ function changesInInputField(
   }
 
   if (oldField.defaultValue !== newField.defaultValue) {
-    changes.push(inputFieldDefaultValueChanged(input, oldField, newField));
+    if (
+      Array.isArray(oldField.defaultValue) &&
+      Array.isArray(newField.defaultValue)
+    ) {
+      if (diffArrays(oldField.defaultValue, newField.defaultValue).length > 0) {
+        changes.push(inputFieldDefaultValueChanged(input, oldField, newField));
+      }
+    } else if (
+      JSON.stringify(oldField.defaultValue) !==
+      JSON.stringify(newField.defaultValue)
+    ) {
+      changes.push(inputFieldDefaultValueChanged(input, oldField, newField));
+    }
   }
 
   if (oldField.type.toString() !== newField.type.toString()) {


Test patch:
diff --git a/packages/core/__tests__/diff/schema.ts b/packages/core/__tests__/diff/schema.ts
index d5d694a1..e76cca6e 100644
--- a/packages/core/__tests__/diff/schema.ts
+++ b/packages/core/__tests__/diff/schema.ts
@@ -382,3 +382,145 @@ test('', () => {
     }
   });
 });
+
+test('array as default value in argument (same)', () => {
+  const schemaA = buildASTSchema(gql`
+    interface MyInterface {
+      a(b: [String] = ["Hello"]): String!
+    }
+  `);
+
+  const schemaB = buildASTSchema(gql`
+    interface MyInterface {
+      a(b: [String] = ["Hello"]): String!
+    }
+  `);
+
+  const changes = diff(schemaA, schemaB);
+
+  expect(changes.length).toEqual(0);
+});
+
+test('array as default value in argument (different)', () => {
+  const schemaA = buildASTSchema(gql`
+    interface MyInterface {
+      a(b: [String] = ["Hello"]): String!
+    }
+  `);
+
+  const schemaB = buildASTSchema(gql`
+    interface MyInterface {
+      a(b: [String] = ["Goodbye"]): String!
+    }
+  `);
+
+  const changes = diff(schemaA, schemaB);
+
+  expect(changes.length).toEqual(1);
+  expect(changes[0]).toBeDefined();
+  expect(changes[0].criticality.level).toEqual(CriticalityLevel.Dangerous);
+  expect(changes[0].message).toEqual(
+    `Default value for argument 'b' on field 'MyInterface.a' changed from 'Hello' to 'Goodbye'`,
+  );
+  expect(changes[0].path).toEqual(`MyInterface.a.b`);
+});
+
+test('input as default value (same)', () => {
+  const schemaA = buildASTSchema(gql`
+    enum SortOrder {
+      ASC
+    }
+
+    input CommentQuery {
+      limit: Int!
+      sortOrder: SortOrder!
+    }
+
+    type Comment {
+      replies(query: CommentQuery = {sortOrder: ASC, limit: 3}): String!
+    }
+  `);
+
+  const schemaB = buildASTSchema(gql`
+    enum SortOrder {
+      ASC
+    }
+
+    input CommentQuery {
+      limit: Int!
+      sortOrder: SortOrder!
+    }
+
+    type Comment {
+      replies(query: CommentQuery = {sortOrder: ASC, limit: 3}): String!
+    }
+  `);
+
+  const changes = diff(schemaA, schemaB);
+
+  expect(changes.length).toEqual(0);
+});
+
+test('array as default value in input (same)', () => {
+  const schemaA = buildASTSchema(gql`
+    enum SortOrder {
+      ASC
+    }
+
+    input CommentQuery {
+      limit: Int!
+      sortOrder: [SortOrder] = [ASC]
+    }
+  `);
+
+  const schemaB = buildASTSchema(gql`
+    enum SortOrder {
+      ASC
+    }
+
+    input CommentQuery {
+      limit: Int!
+      sortOrder: [SortOrder] = [ASC]
+    }
+  `);
+
+  const changes = diff(schemaA, schemaB);
+
+  expect(changes.length).toEqual(0);
+});
+
+test('array as default value in input (different)', () => {
+  const schemaA = buildASTSchema(gql`
+    enum SortOrder {
+      ASC
+      DEC
+    }
+
+    input CommentQuery {
+      limit: Int!
+      sortOrder: [SortOrder] = [ASC]
+    }
+  `);
+
+  const schemaB = buildASTSchema(gql`
+    enum SortOrder {
+      ASC
+      DEC
+    }
+
+    input CommentQuery {
+      limit: Int!
+      sortOrder: [SortOrder] = [DEC]
+    }
+  `);
+
+  const changes = diff(schemaA, schemaB);
+
+  expect(changes.length).toEqual(1);
+  expect(changes[0]).toBeDefined();
+  expect(changes[0].criticality.level).toEqual(CriticalityLevel.Dangerous);
+  expect(changes[0].message).toEqual(
+    `Input field 'CommentQuery.sortOrder' default value changed from 'ASC' to 'DEC'`,
+  );
+  expect(changes[0].path).toEqual(`CommentQuery.sortOrder`);
+});