Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore coverage to 100% #2372

Merged
merged 1 commit into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/execution/__tests__/variables-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,18 @@ describe('Execute: Handles inputs', () => {
};
}

it('return all errors by default', () => {
const result = getVariableValues(schema, variableDefinitions, inputValue);

expect(result).to.deep.equal({
errors: [
invalidValueError(0, 0),
invalidValueError(1, 1),
invalidValueError(2, 2),
],
});
});

it('when maxErrors is equal to number of errors', () => {
const result = getVariableValues(
schema,
Expand Down
2 changes: 1 addition & 1 deletion src/execution/values.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export function getVariableValues(
inputs: { +[variable: string]: mixed, ... },
options?: {| maxErrors?: number |},
): CoercedVariableValues {
const maxErrors = options?.maxErrors;
const errors = [];
const maxErrors = options?.maxErrors;
try {
const coerced = coerceVariableValues(schema, varDefNodes, inputs, error => {
if (maxErrors != null && errors.length >= maxErrors) {
Expand Down
8 changes: 5 additions & 3 deletions src/subscription/__tests__/mapAsyncIterator-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,9 @@ describe('mapAsyncIterator', () => {
} catch (e) {
caughtError = e;
}
expect(caughtError?.message).to.equal('Goodbye');

invariant(caughtError != null);
expect(caughtError.message).to.equal('Goodbye');
});

it('maps over thrown errors if second callback provided', async () => {
Expand All @@ -294,8 +296,8 @@ describe('mapAsyncIterator', () => {
});

const result = await doubles.next();
expect(result.value).to.be.instanceof(Error);
expect(result.value?.message).to.equal('Goodbye');
invariant(result.value instanceof Error);
expect(result.value.message).to.equal('Goodbye');
expect(result.done).to.equal(false);

expect(await doubles.next()).to.deep.equal({
Expand Down
5 changes: 4 additions & 1 deletion src/subscription/__tests__/subscribe-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import EventEmitter from 'events';
import { expect } from 'chai';
import { describe, it } from 'mocha';

import invariant from '../../jsutils/invariant';

import { parse } from '../../language/parser';

import { GraphQLError } from '../../error/GraphQLError';
Expand Down Expand Up @@ -142,7 +144,8 @@ async function expectPromiseToThrow(promise, message) {
/* istanbul ignore next */
expect.fail('promise should have thrown but did not');
} catch (error) {
expect(error?.message).to.equal(message);
invariant(error instanceof Error);
expect(error.message).to.equal(message);
}
}

Expand Down
142 changes: 85 additions & 57 deletions src/type/__tests__/validation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,88 +13,92 @@ import { buildSchema } from '../../utilities/buildASTSchema';

import { GraphQLSchema } from '../schema';
import { GraphQLString } from '../scalars';
import { GraphQLDirective } from '../directives';
import { validateSchema, assertValidSchema } from '../validate';
import { GraphQLDirective, assertDirective } from '../directives';
import {
type GraphQLNamedType,
type GraphQLInputType,
type GraphQLOutputType,
GraphQLList,
GraphQLNonNull,
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
assertScalarType,
assertInterfaceType,
assertObjectType,
assertUnionType,
assertEnumType,
assertInputObjectType,
} from '../definition';

const SomeScalarType = new GraphQLScalarType({ name: 'SomeScalar' });
const SomeSchema = buildSchema(`
scalar SomeScalar
const SomeInterfaceType = new GraphQLInterfaceType({
name: 'SomeInterface',
fields: () => ({ f: { type: SomeObjectType } }),
});
interface SomeInterface { f: SomeObject }
const SomeObjectType = new GraphQLObjectType({
name: 'SomeObject',
fields: () => ({ f: { type: SomeObjectType } }),
interfaces: [SomeInterfaceType],
});
type SomeObject implements SomeInterface { f: SomeObject }
const SomeUnionType = new GraphQLUnionType({
name: 'SomeUnion',
types: [SomeObjectType],
});
union SomeUnion = SomeObject
const SomeEnumType = new GraphQLEnumType({
name: 'SomeEnum',
values: {
ONLY: {},
},
});
enum SomeEnum { ONLY }
const SomeInputObjectType = new GraphQLInputObjectType({
name: 'SomeInputObject',
fields: {
val: { type: GraphQLString, defaultValue: 'hello' },
},
});
input SomeInputObject { val: String = "hello" }
directive @SomeDirective on QUERY
`);

const SomeScalarType = assertScalarType(SomeSchema.getType('SomeScalar'));
const SomeInterfaceType = assertInterfaceType(
SomeSchema.getType('SomeInterface'),
);
const SomeObjectType = assertObjectType(SomeSchema.getType('SomeObject'));
const SomeUnionType = assertUnionType(SomeSchema.getType('SomeUnion'));
const SomeEnumType = assertEnumType(SomeSchema.getType('SomeEnum'));
const SomeInputObjectType = assertInputObjectType(
SomeSchema.getType('SomeInputObject'),
);

const SomeDirective = assertDirective(SomeSchema.getDirective('SomeDirective'));

function withModifiers<T: GraphQLNamedType>(
types: Array<T>,
type: T,
): Array<T | GraphQLList<T> | GraphQLNonNull<T | GraphQLList<T>>> {
return [
...types,
...types.map(type => GraphQLList(type)),
...types.map(type => GraphQLNonNull(type)),
...types.map(type => GraphQLNonNull(GraphQLList(type))),
type,
GraphQLList(type),
GraphQLNonNull(type),
GraphQLNonNull(GraphQLList(type)),
];
}

const outputTypes = withModifiers([
GraphQLString,
SomeScalarType,
SomeEnumType,
SomeObjectType,
SomeUnionType,
SomeInterfaceType,
]);

const notOutputTypes = withModifiers([SomeInputObjectType]);

const inputTypes = withModifiers([
GraphQLString,
SomeScalarType,
SomeEnumType,
SomeInputObjectType,
]);

const notInputTypes = withModifiers([
SomeObjectType,
SomeUnionType,
SomeInterfaceType,
]);
const outputTypes: Array<GraphQLOutputType> = [
...withModifiers(GraphQLString),
...withModifiers(SomeScalarType),
...withModifiers(SomeEnumType),
...withModifiers(SomeObjectType),
...withModifiers(SomeUnionType),
...withModifiers(SomeInterfaceType),
];

const notOutputTypes: Array<GraphQLInputType> = [
...withModifiers(SomeInputObjectType),
];

const inputTypes: Array<GraphQLInputType> = [
...withModifiers(GraphQLString),
...withModifiers(SomeScalarType),
...withModifiers(SomeEnumType),
...withModifiers(SomeInputObjectType),
];

const notInputTypes: Array<GraphQLOutputType> = [
...withModifiers(SomeObjectType),
...withModifiers(SomeUnionType),
...withModifiers(SomeInterfaceType),
];

function schemaWithFieldType(type) {
return new GraphQLSchema({
Expand Down Expand Up @@ -380,16 +384,40 @@ describe('Type System: A Schema must have Object root types', () => {
]);
});

it('rejects a Schema whose types are incorrectly typed', () => {
const schema = new GraphQLSchema({
query: SomeObjectType,
// $DisableFlowOnNegativeTest
types: [{ name: 'SomeType' }, SomeDirective],
});
expect(validateSchema(schema)).to.deep.equal([
{
message: 'Expected GraphQL named type but got: { name: "SomeType" }.',
},
{
message: 'Expected GraphQL named type but got: @SomeDirective.',
locations: [{ line: 14, column: 3 }],
},
]);
});

it('rejects a Schema whose directives are incorrectly typed', () => {
const schema = new GraphQLSchema({
query: SomeObjectType,
// $DisableFlowOnNegativeTest
directives: ['SomeDirective'],
directives: [null, 'SomeDirective', SomeScalarType],
});
expect(validateSchema(schema)).to.deep.equal([
{
message: 'Expected directive but got: null.',
},
{
message: 'Expected directive but got: "SomeDirective".',
},
{
message: 'Expected directive but got: SomeScalar.',
locations: [{ line: 2, column: 3 }],
},
]);
});
});
Expand Down
6 changes: 3 additions & 3 deletions src/type/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ function validateTypes(context: SchemaValidationContext): void {
if (!isNamedType(type)) {
context.reportError(
`Expected GraphQL named type but got: ${inspect(type)}.`,
type?.astNode,
type.astNode,
);
continue;
}
Expand Down Expand Up @@ -354,7 +354,7 @@ function validateTypeImplementsInterface(
`Interface field ${iface.name}.${fieldName} expects type ` +
`${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` +
`is type ${inspect(typeField.type)}.`,
[ifaceField.astNode?.type, typeField.astNode?.type],
[ifaceField.astNode.type, typeField.astNode.type],
);
}

Expand All @@ -381,7 +381,7 @@ function validateTypeImplementsInterface(
`expects type ${inspect(ifaceArg.type)} but ` +
`${type.name}.${fieldName}(${argName}:) is type ` +
`${inspect(typeArg.type)}.`,
[ifaceArg.astNode?.type, typeArg.astNode?.type],
[ifaceArg.astNode.type, typeArg.astNode.type],
);
}

Expand Down
14 changes: 14 additions & 0 deletions src/utilities/__tests__/findDeprecatedUsages-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ describe('findDeprecatedUsages', () => {
expect(errors.length).to.equal(0);
});

it('should ignore unknown stuff', () => {
const errors = findDeprecatedUsages(
schema,
parse(`
{
unknownField(unknownArg: UNKNOWN_VALUE)
normalField(enumArg: UNKNOWN_VALUE)
}
`),
);

expect(errors.length).to.equal(0);
});

it('should report usage of deprecated fields', () => {
const errors = findDeprecatedUsages(
schema,
Expand Down
14 changes: 10 additions & 4 deletions src/utilities/__tests__/getOperationAST-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,37 @@ describe('getOperationAST', () => {
const doc = parse(`
{ field }
mutation Test { field }
subscription TestSub { field }`);
subscription TestSub { field }
`);
expect(getOperationAST(doc)).to.equal(null);
});

it('Does not get ambiguous named operation', () => {
const doc = parse(`
query TestQ { field }
mutation TestM { field }
subscription TestS { field }`);
subscription TestS { field }
`);
expect(getOperationAST(doc)).to.equal(null);
});

it('Does not get misnamed operation', () => {
const doc = parse(`
{ field }
query TestQ { field }
mutation TestM { field }
subscription TestS { field }`);
subscription TestS { field }
`);
expect(getOperationAST(doc, 'Unknown')).to.equal(null);
});

it('Gets named operation', () => {
const doc = parse(`
query TestQ { field }
mutation TestM { field }
subscription TestS { field }`);
subscription TestS { field }
`);
expect(getOperationAST(doc, 'TestQ')).to.equal(doc.definitions[0]);
expect(getOperationAST(doc, 'TestM')).to.equal(doc.definitions[1]);
expect(getOperationAST(doc, 'TestS')).to.equal(doc.definitions[2]);
Expand Down