mirror of
https://github.com/vale981/apollo-server
synced 2025-03-16 15:56:41 -04:00
174 lines
5.4 KiB
TypeScript
174 lines
5.4 KiB
TypeScript
/* tslint:disable:no-unused-expression */
|
|
import { expect } from 'chai';
|
|
import { stub, spy } from 'sinon';
|
|
import 'mocha';
|
|
|
|
import { GraphQLError } from 'graphql';
|
|
|
|
import {
|
|
ApolloError,
|
|
formatApolloErrors,
|
|
AuthenticationError,
|
|
ForbiddenError,
|
|
ValidationError,
|
|
SyntaxError,
|
|
} from './errors';
|
|
|
|
describe('Errors', () => {
|
|
describe('ApolloError', () => {
|
|
const message = 'message';
|
|
it('defaults code to INTERNAL_SERVER_ERROR', () => {
|
|
const error = new ApolloError(message);
|
|
expect(error.message).to.equal(message);
|
|
expect(error.extensions.code).not.to.exist;
|
|
});
|
|
it('allows code setting and additional properties', () => {
|
|
const code = 'CODE';
|
|
const key = 'key';
|
|
const error = new ApolloError(message, code, { key });
|
|
expect(error.message).to.equal(message);
|
|
expect(error.key).to.equal(key);
|
|
expect(error.extensions.code).to.equal(code);
|
|
});
|
|
});
|
|
|
|
describe('formatApolloErrors', () => {
|
|
type CreateFormatError =
|
|
| ((options: Record<string, any>, errors) => Record<string, any>[])
|
|
| ((options?: Record<string, any>) => Record<string, any>);
|
|
const message = 'message';
|
|
const code = 'CODE';
|
|
const key = 'key';
|
|
|
|
const createFromttedError: CreateFormatError = (
|
|
options,
|
|
errors?: Error[],
|
|
) => {
|
|
if (errors === undefined) {
|
|
const error = new ApolloError(message, code, { key });
|
|
return formatApolloErrors(
|
|
[
|
|
new GraphQLError(
|
|
error.message,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
error,
|
|
),
|
|
],
|
|
options,
|
|
)[0];
|
|
} else {
|
|
return formatApolloErrors(errors, options);
|
|
}
|
|
};
|
|
|
|
it('exposes a stacktrace in debug mode', () => {
|
|
const error = createFromttedError({ debug: true });
|
|
expect(error.message).to.equal(message);
|
|
expect(error.extensions.exception.key).to.equal(key);
|
|
expect(error.extensions.code).to.equal(code);
|
|
expect(
|
|
error.extensions.exception.stacktrace,
|
|
'stacktrace should exist under exception',
|
|
).to.exist;
|
|
});
|
|
it('hides stacktrace by default', () => {
|
|
const thrown = new Error(message);
|
|
(thrown as any).key = key;
|
|
const error = formatApolloErrors([
|
|
new GraphQLError(
|
|
thrown.message,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
undefined,
|
|
thrown,
|
|
),
|
|
])[0];
|
|
expect(error.message).to.equal(message);
|
|
expect(error.extensions.code).to.equal('INTERNAL_SERVER_ERROR');
|
|
expect(error.extensions.exception.key).to.equal(key);
|
|
expect(
|
|
error.extensions.exception.stacktrace,
|
|
'stacktrace should exist under exception',
|
|
).not.to.exist;
|
|
});
|
|
it('exposes fields on error under exception field and provides code', () => {
|
|
const error = createFromttedError();
|
|
expect(error.message).to.equal(message);
|
|
expect(error.extensions.exception.key).to.equal(key);
|
|
expect(error.extensions.code).to.equal(code);
|
|
expect(
|
|
error.extensions.exception.stacktrace,
|
|
'stacktrace should exist under exception',
|
|
).not.to.exist;
|
|
});
|
|
it('calls logFunction with each error', () => {
|
|
const error = new ApolloError(message, code, { key });
|
|
const logFunction = stub();
|
|
const formattedError = formatApolloErrors([error], {
|
|
logFunction,
|
|
debug: true,
|
|
});
|
|
expect(error.message).to.equal(message);
|
|
expect(error.key).to.equal(key);
|
|
expect(error.extensions.code).to.equal(code);
|
|
expect(error instanceof ApolloError).true;
|
|
expect(logFunction.calledOnce);
|
|
});
|
|
it('calls formatter after exposing the code and stacktrace', () => {
|
|
const error = new ApolloError(message, code, { key });
|
|
const formatter = stub();
|
|
const formattedError = formatApolloErrors([error], {
|
|
formatter,
|
|
debug: true,
|
|
});
|
|
expect(error.message).to.equal(message);
|
|
expect(error.key).to.equal(key);
|
|
expect(error.extensions.code).to.equal(code);
|
|
expect(error instanceof ApolloError).true;
|
|
expect(formatter.calledOnce);
|
|
});
|
|
});
|
|
describe('Named Errors', () => {
|
|
const message = 'message';
|
|
function verifyError(error, { code, errorClass, name }) {
|
|
expect(error.message).to.equal(message);
|
|
expect(error.extensions.code).to.equal(code);
|
|
expect(error.name).equals(name);
|
|
expect(error instanceof ApolloError).true;
|
|
expect(error instanceof errorClass).true;
|
|
}
|
|
|
|
it('provides an authentication error', () => {
|
|
verifyError(new AuthenticationError(message), {
|
|
code: 'UNAUTHENTICATED',
|
|
errorClass: AuthenticationError,
|
|
name: 'AuthenticationError',
|
|
});
|
|
});
|
|
it('provides a forbidden error', () => {
|
|
verifyError(new ForbiddenError(message), {
|
|
code: 'FORBIDDEN',
|
|
errorClass: ForbiddenError,
|
|
name: 'ForbiddenError',
|
|
});
|
|
});
|
|
it('provides a syntax error', () => {
|
|
verifyError(new SyntaxError(message), {
|
|
code: 'GRAPHQL_PARSE_FAILED',
|
|
errorClass: SyntaxError,
|
|
name: 'SyntaxError',
|
|
});
|
|
});
|
|
it('provides a validation error', () => {
|
|
verifyError(new ValidationError(message), {
|
|
code: 'GRAPHQL_VALIDATION_FAILED',
|
|
errorClass: ValidationError,
|
|
name: 'ValidationError',
|
|
});
|
|
});
|
|
});
|
|
});
|