Skip to content

Commit

Permalink
Marking breaking types as dangerous with the deprecated fields rule (#…
Browse files Browse the repository at this point in the history
…2240)

* Marking breaking types as dangerous with the deprecated fields rule enabled

* Adding example

* Adding changeset

* Adding unit tests for suppressRemovalOfDeprecatedFields rule
  • Loading branch information
Tohaker authored Jan 23, 2023
1 parent 7eb5e8d commit ca29cdd
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/eighty-starfishes-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-inspector/core': minor
---

suppressRemovalOfDeprecatedField rule will now mark removed types as dangerous
3 changes: 3 additions & 0 deletions integration_tests/2239/newSchema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type Query {
newQuery: Int!
}
8 changes: 8 additions & 0 deletions integration_tests/2239/oldSchema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type Query {
oldQuery: OldType @deprecated(reason: "use newQuery")
newQuery: Int!
}

type OldType {
field: String!
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { buildSchema } from 'graphql';
import { suppressRemovalOfDeprecatedField } from '../../../src/diff/rules';
import { CriticalityLevel, diff } from '../../../src/index';
import { findFirstChangeByPath } from '../../../utils/testing';

describe('suppressRemovalOfDeprecatedFields rule', () => {
test('removed field on object', async () => {
const a = buildSchema(/* GraphQL */ `
type Foo {
a: String! @deprecated(reason: "use b")
b: String!
}
`);
const b = buildSchema(/* GraphQL */ `
type Foo {
b: String!
}
`);

const changes = await diff(a, b, [suppressRemovalOfDeprecatedField]);

const removed = findFirstChangeByPath(changes, 'Foo.a');

expect(removed.criticality.level).toBe(CriticalityLevel.Dangerous);
});

test('removed field on interface', async () => {
const a = buildSchema(/* GraphQL */ `
interface Foo {
a: String! @deprecated(reason: "use b")
b: String!
}
`);
const b = buildSchema(/* GraphQL */ `
interface Foo {
b: String!
}
`);

const changes = await diff(a, b, [suppressRemovalOfDeprecatedField]);

const removed = findFirstChangeByPath(changes, 'Foo.a');

expect(removed.criticality.level).toBe(CriticalityLevel.Dangerous);
});

test('removed enum', async () => {
const a = buildSchema(/* GraphQL */ `
enum Foo {
a @deprecated(reason: "use b")
b
}
`);
const b = buildSchema(/* GraphQL */ `
enum Foo {
b
}
`);

const changes = await diff(a, b, [suppressRemovalOfDeprecatedField]);

const removed = findFirstChangeByPath(changes, 'Foo.a');

expect(removed.criticality.level).toBe(CriticalityLevel.Dangerous);
});

test('removed input field', async () => {
const a = buildSchema(/* GraphQL */ `
input Foo {
a: String! @deprecated(reason: "use b")
b: String!
}
`);
const b = buildSchema(/* GraphQL */ `
input Foo {
b: String!
}
`);

const changes = await diff(a, b, [suppressRemovalOfDeprecatedField]);

const removed = findFirstChangeByPath(changes, 'Foo.a');

expect(removed.criticality.level).toBe(CriticalityLevel.Dangerous);
});

test('removed field with custom types', async () => {
const a = buildSchema(/* GraphQL */ `
type Foo {
a: CustomType! @deprecated(reason: "use b")
b: String!
}
type CustomType {
c: String!
d: String!
}
`);
const b = buildSchema(/* GraphQL */ `
type Foo {
b: String!
}
`);

const changes = await diff(a, b, [suppressRemovalOfDeprecatedField]);

const removedField = findFirstChangeByPath(changes, 'Foo.a');
const removedType = findFirstChangeByPath(changes, 'CustomType');

expect(removedField.criticality.level).toBe(CriticalityLevel.Dangerous);
expect(removedType.criticality.level).toBe(CriticalityLevel.Dangerous);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { parsePath } from '../../utils/path';
import { ChangeType, CriticalityLevel } from './../changes/change';
import { Rule } from './types';

export const suppressRemovalOfDeprecatedField: Rule = ({ changes, oldSchema }) => {
export const suppressRemovalOfDeprecatedField: Rule = ({ changes, oldSchema, newSchema }) => {
return changes.map(change => {
if (
change.type === ChangeType.FieldRemoved &&
Expand Down Expand Up @@ -75,6 +75,25 @@ export const suppressRemovalOfDeprecatedField: Rule = ({ changes, oldSchema }) =
}
}

if (
change.type === ChangeType.TypeRemoved &&
change.criticality.level === CriticalityLevel.Breaking &&
change.path
) {
const [typeName] = parsePath(change.path);
const type = newSchema.getType(typeName);

if (!type) {
return {
...change,
criticality: {
...change.criticality,
level: CriticalityLevel.Dangerous,
},
};
}
}

return change;
});
};

0 comments on commit ca29cdd

Please sign in to comment.