mirror of
https://github.com/graphql-hive/console
synced 2026-05-01 11:27:17 +00:00
339 lines
9.2 KiB
TypeScript
339 lines
9.2 KiB
TypeScript
import stripAnsi from 'strip-ansi';
|
||
import { ProjectType, RuleInstanceSeverityLevel, SchemaPolicyInput } from 'testkit/gql/graphql';
|
||
import { prepareProject } from 'testkit/registry-models';
|
||
import { createCLI } from '../../../testkit/cli';
|
||
|
||
export const createPolicy = (level: RuleInstanceSeverityLevel): SchemaPolicyInput => ({
|
||
rules: [
|
||
{
|
||
ruleId: 'require-description',
|
||
severity: level,
|
||
configuration: {
|
||
types: true,
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
describe('Schema policy checks', () => {
|
||
describe('model: composite', () => {
|
||
it('Federation project with policy with only warnings, should check only the part that was changed', async () => {
|
||
const { tokens, policy } = await prepareProject(ProjectType.Federation);
|
||
await policy.setOrganizationSchemaPolicy(
|
||
createPolicy(RuleInstanceSeverityLevel.Warning),
|
||
true,
|
||
);
|
||
const cli = createCLI(tokens.registry);
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type Product @key(fields: "id") {
|
||
id: ID!
|
||
title: String
|
||
url: String
|
||
}
|
||
|
||
extend type Query {
|
||
product(id: ID!): Product
|
||
}
|
||
`,
|
||
serviceName: 'products',
|
||
serviceUrl: 'https://api.com/products',
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type User @key(fields: "id") {
|
||
id: ID!
|
||
name: String!
|
||
}
|
||
|
||
extend type Query {
|
||
user(id: ID!): User
|
||
}
|
||
`,
|
||
serviceName: 'users',
|
||
serviceUrl: 'https://api.com/users',
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
const rawMessage = await cli.check({
|
||
sdl: /* GraphQL */ `
|
||
type User @key(fields: "id") {
|
||
id: ID!
|
||
name: String!
|
||
}
|
||
|
||
extend type Query {
|
||
user(id: ID!): User
|
||
field: String!
|
||
}
|
||
`,
|
||
serviceName: 'users',
|
||
expect: 'approved',
|
||
});
|
||
const message = stripAnsi(rawMessage);
|
||
|
||
expect(message.split('\n')).toEqual([
|
||
'ℹ Detected 1 change',
|
||
'',
|
||
' Safe changes:',
|
||
' - Field field was added to object type Query',
|
||
'',
|
||
'',
|
||
'⚠ Detected 1 warning',
|
||
'',
|
||
' - Description is required for type User (source: policy-require-description)',
|
||
'',
|
||
'View full report:',
|
||
expect.any(String),
|
||
]);
|
||
});
|
||
|
||
it('Federation project with policy with , should check only the part that was changed', async () => {
|
||
const { tokens, policy } = await prepareProject(ProjectType.Federation);
|
||
await policy.setOrganizationSchemaPolicy(createPolicy(RuleInstanceSeverityLevel.Error), true);
|
||
const cli = createCLI(tokens.registry);
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type Product @key(fields: "id") {
|
||
id: ID!
|
||
title: String
|
||
url: String
|
||
}
|
||
|
||
extend type Query {
|
||
product(id: ID!): Product
|
||
}
|
||
`,
|
||
serviceName: 'products',
|
||
serviceUrl: 'https://api.com/products',
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type User @key(fields: "id") {
|
||
id: ID!
|
||
name: String!
|
||
}
|
||
|
||
extend type Query {
|
||
user(id: ID!): User
|
||
}
|
||
`,
|
||
serviceName: 'users',
|
||
serviceUrl: 'https://api.com/users',
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
const rawMessage = await cli.check({
|
||
sdl: /* GraphQL */ `
|
||
type User @key(fields: "id") {
|
||
id: ID!
|
||
name: String!
|
||
}
|
||
|
||
extend type Query {
|
||
user(id: ID!): User
|
||
field: String!
|
||
}
|
||
`,
|
||
serviceName: 'users',
|
||
expect: 'rejected',
|
||
});
|
||
const message = stripAnsi(rawMessage);
|
||
|
||
expect(message).toContain(`Detected 1 error`);
|
||
expect(message.split('\n').slice(1)).toEqual([
|
||
'✖ Detected 1 error',
|
||
'',
|
||
' - Description is required for type User (source: policy-require-description)',
|
||
'',
|
||
'ℹ Detected 1 change',
|
||
'',
|
||
' Safe changes:',
|
||
' - Field field was added to object type Query',
|
||
'',
|
||
'View full report:',
|
||
expect.any(String),
|
||
'',
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('model: single', () => {
|
||
test('Single with policy with only warnings', async () => {
|
||
const { tokens, policy } = await prepareProject(ProjectType.Single);
|
||
await policy.setOrganizationSchemaPolicy(
|
||
createPolicy(RuleInstanceSeverityLevel.Warning),
|
||
true,
|
||
);
|
||
const cli = await createCLI(tokens.registry);
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type Query {
|
||
foo: String!
|
||
}
|
||
`,
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
const rawMessage = await cli.check({
|
||
sdl: /* GraphQL */ `
|
||
type Query {
|
||
foo: String!
|
||
user: User!
|
||
}
|
||
|
||
type User {
|
||
name: String!
|
||
}
|
||
`,
|
||
expect: 'approved',
|
||
});
|
||
const message = stripAnsi(rawMessage);
|
||
|
||
expect(message).toContain(`Detected 2 warnings`);
|
||
expect(message.split('\n')).toEqual([
|
||
'ℹ Detected 2 changes',
|
||
'',
|
||
' Safe changes:',
|
||
' - Type User was added',
|
||
' - Field user was added to object type Query',
|
||
'',
|
||
'',
|
||
'⚠ Detected 2 warnings',
|
||
'',
|
||
' - Description is required for type Query (source: policy-require-description)',
|
||
' - Description is required for type User (source: policy-require-description)',
|
||
'',
|
||
'View full report:',
|
||
expect.any(String),
|
||
]);
|
||
});
|
||
|
||
test('Single with policy with only errors', async () => {
|
||
const { tokens, policy } = await prepareProject(ProjectType.Single);
|
||
await policy.setOrganizationSchemaPolicy(createPolicy(RuleInstanceSeverityLevel.Error), true);
|
||
const cli = await createCLI(tokens.registry);
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type Query {
|
||
foo: String!
|
||
}
|
||
`,
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
const rawMessage = await cli.check({
|
||
sdl: /* GraphQL */ `
|
||
type Query {
|
||
foo: String!
|
||
user: User!
|
||
}
|
||
|
||
type User {
|
||
name: String!
|
||
}
|
||
`,
|
||
expect: 'rejected',
|
||
});
|
||
const message = stripAnsi(rawMessage);
|
||
|
||
expect(message).toContain(`Detected 2 errors`);
|
||
expect(message.split('\n').slice(1)).toEqual([
|
||
'✖ Detected 2 errors',
|
||
'',
|
||
' - Description is required for type Query (source: policy-require-description)',
|
||
' - Description is required for type User (source: policy-require-description)',
|
||
'',
|
||
'ℹ Detected 2 changes',
|
||
'',
|
||
' Safe changes:',
|
||
' - Type User was added',
|
||
' - Field user was added to object type Query',
|
||
'',
|
||
'View full report:',
|
||
expect.any(String),
|
||
'',
|
||
]);
|
||
});
|
||
|
||
test('Single with policy with both errors and warning', async () => {
|
||
const { tokens, policy } = await prepareProject(ProjectType.Single);
|
||
await policy.setOrganizationSchemaPolicy(
|
||
{
|
||
rules: [
|
||
{
|
||
ruleId: 'require-description',
|
||
severity: RuleInstanceSeverityLevel.Error,
|
||
configuration: {
|
||
types: true,
|
||
},
|
||
},
|
||
{
|
||
ruleId: 'require-deprecation-reason',
|
||
severity: RuleInstanceSeverityLevel.Warning,
|
||
},
|
||
],
|
||
},
|
||
true,
|
||
);
|
||
const cli = await createCLI(tokens.registry);
|
||
|
||
await cli.publish({
|
||
sdl: /* GraphQL */ `
|
||
type Query {
|
||
foo: String!
|
||
}
|
||
`,
|
||
expect: 'latest-composable',
|
||
});
|
||
|
||
const rawMessage = await cli.check({
|
||
sdl: /* GraphQL */ `
|
||
type Query {
|
||
foo: String! @deprecated(reason: "")
|
||
user: User!
|
||
}
|
||
|
||
type User {
|
||
name: String!
|
||
}
|
||
`,
|
||
expect: 'rejected',
|
||
});
|
||
const message = stripAnsi(rawMessage);
|
||
|
||
expect(message).toContain(`Detected 2 errors`);
|
||
expect(message).toContain(`Detected 1 warning`);
|
||
expect(message.split('\n').slice(1)).toEqual([
|
||
'✖ Detected 2 errors',
|
||
'',
|
||
' - Description is required for type Query (source: policy-require-description)',
|
||
' - Description is required for type User (source: policy-require-description)',
|
||
'',
|
||
'',
|
||
'⚠ Detected 1 warning',
|
||
'',
|
||
' - Deprecation reason is required for field foo in type Query. (source: policy-require-deprecation-reason)',
|
||
'',
|
||
'ℹ Detected 3 changes',
|
||
'',
|
||
' Safe changes:',
|
||
' - Type User was added',
|
||
' - Field user was added to object type Query',
|
||
' - Field Query.foo is deprecated',
|
||
'',
|
||
'View full report:',
|
||
expect.any(String),
|
||
'',
|
||
]);
|
||
});
|
||
});
|
||
});
|