import { expect } from 'chai' ; import { describe , it } from 'mocha' ; import { dedent } from '../../__testUtils__/dedent' ; import { invariant } from '../../jsutils/invariant' ; import { Kind } from '../../language/kinds' ; import { parse } from '../../language/parser' ; import { Source } from '../../language/source' ; import { formatError , GraphQLError , printError } from '../GraphQLError' ; const source = new Source ( dedent `
  {
    field
  }
` ) ; const ast = parse ( source ) ; const operationNode = ast . definitions [ 0 ] ; invariant ( operationNode . kind === Kind . OPERATION_DEFINITION ) ; const fieldNode = operationNode . selectionSet . selections [ 0 ] ; invariant ( fieldNode ) ; describe ( 'GraphQLError' , ( ) => { it ( 'is a class and is a subclass of Error' , ( ) => { expect ( new GraphQLError ( 'str' ) ) . to . be . instanceof ( Error ) ; expect ( new GraphQLError ( 'str' ) ) . to . be . instanceof ( GraphQLError ) ; } ) ; it ( 'has a name, message, extensions, and stack trace' , ( ) => { const e = new GraphQLError ( 'msg' ) ; expect ( e ) . to . deep . include ( { name : 'GraphQLError' , message : 'msg' , extensions : { } , } ) ; expect ( e . stack ) . to . be . a ( 'string' ) ; } ) ; it ( 'enumerate only properties prescribed by the spec' , ( ) => { const e = new GraphQLError ( 'msg' , [ fieldNode ] , source , [ 1 , 2 , 3 ] , [ 'a' , 'b' , 'c' ] , new Error ( 'test' ) , { foo : 'bar' } ) ; expect ( Object . keys ( e ) ) . to . deep . equal ( [ 'message' , 'path' , 'locations' , 'extensions' , ] ) ; } ) ; it ( 'uses the stack of an original error' , ( ) => { const original = new Error ( 'original' ) ; const e = new GraphQLError ( 'msg' , undefined , undefined , undefined , undefined , original ) ; expect ( e ) . to . include ( { name : 'GraphQLError' , message : 'msg' , stack : original . stack , originalError : original , } ) ; } ) ; it ( 'creates new stack if original error has no stack' , ( ) => { const original = new Error ( 'original' ) ; const e = new GraphQLError ( 'msg' , null , null , null , null , original ) ; expect ( e ) . to . include ( { name : 'GraphQLError' , message : 'msg' , originalError : original , } ) ; expect ( e . stack ) . to . be . a ( 'string' ) ; } ) ; it ( 'converts nodes to positions and locations' , ( ) => { const e = new GraphQLError ( 'msg' , [ fieldNode ] ) ; expect ( e ) . to . deep . include ( { source , nodes : [ fieldNode ] , positions : [ 4 ] , locations : [ { line : 2 , column : 3 } ] , } ) ; } ) ; it ( 'converts single node to positions and locations' , ( ) => { const e = new GraphQLError ( 'msg' , fieldNode ) ; expect ( e ) . to . deep . include ( { source , nodes : [ fieldNode ] , positions : [ 4 ] , locations : [ { line : 2 , column : 3 } ] , } ) ; } ) ; it ( 'converts node with loc.start === 0 to positions and locations' , ( ) => { const e = new GraphQLError ( 'msg' , operationNode ) ; expect ( e ) . to . deep . include ( { source , nodes : [ operationNode ] , positions : [ 0 ] , locations : [ { line : 1 , column : 1 } ] , } ) ; } ) ; it ( 'converts node without location to undefined source, positions and locations' , ( ) => { const fieldNodeNoLocation = { ... fieldNode , loc : undefined , } ; const e = new GraphQLError ( 'msg' , fieldNodeNoLocation ) ; expect ( e ) . to . deep . include ( { nodes : [ fieldNodeNoLocation ] , source : undefined , positions : undefined , locations : undefined , } ) ; } ) ; it ( 'converts source and positions to locations' , ( ) => { const e = new GraphQLError ( 'msg' , null , source , [ 6 ] ) ; expect ( e ) . to . deep . include ( { source , nodes : undefined , positions : [ 6 ] , locations : [ { line : 2 , column : 5 } ] , } ) ; } ) ; it ( 'defaults to original error extension only if extensions argument is not passed' , ( ) => { class ErrorWithExtensions extends Error { extensions : unknown ; constructor ( message ) { super ( message ) ; this . extensions = { original : 'extensions' } ; } } const original = new ErrorWithExtensions ( 'original' ) ; const inheritedExtensions = new GraphQLError ( 'InheritedExtensions' , undefined , undefined , undefined , undefined , original , undefined ) ; expect ( inheritedExtensions ) . to . deep . include ( { message : 'InheritedExtensions' , originalError : original , extensions : { original : 'extensions' } , } ) ; const ownExtensions = new GraphQLError ( 'OwnExtensions' , undefined , undefined , undefined , undefined , original , { own : 'extensions' } ) ; expect ( ownExtensions ) . to . deep . include ( { message : 'OwnExtensions' , originalError : original , extensions : { own : 'extensions' } , } ) ; const ownEmptyExtensions = new GraphQLError ( 'OwnEmptyExtensions' , undefined , undefined , undefined , undefined , original , { } ) ; expect ( ownEmptyExtensions ) . to . deep . include ( { message : 'OwnEmptyExtensions' , originalError : original , extensions : { } , } ) ; } ) ; it ( 'serializes to include all standard fields' , ( ) => { const eShort = new GraphQLError ( 'msg' ) ; expect ( JSON . stringify ( eShort , null , 2 ) ) . to . equal ( dedent `
      {
        "message": "msg"
      }
    ` ) ; const path = [ 'path' , 2 , 'field' ] ; const extensions = { foo : 'bar' } ; const eFull = new GraphQLError ( 'msg' , fieldNode , undefined , undefined , path , undefined , extensions ) ; expect ( JSON . stringify ( eFull , null , 2 ) ) . to . equal ( dedent `
      {
        "message": "msg",
        "locations": [
          {
            "line": 2,
            "column": 3
          }
        ],
        "path": [
          "path",
          2,
          "field"
        ],
        "extensions": {
          "foo": "bar"
        }
      }
    ` ) ; } ) ; } ) ; describe ( 'toString' , ( ) => { it ( 'Deprecated: prints an error using printError' , ( ) => { const error = new GraphQLError ( 'Error' ) ; expect ( printError ( error ) ) . to . equal ( 'Error' ) ; } ) ; it ( 'prints an error without location' , ( ) => { const error = new GraphQLError ( 'Error without location' ) ; expect ( error . toString ( ) ) . to . equal ( 'Error without location' ) ; } ) ; it ( 'prints an error using node without location' , ( ) => { const error = new GraphQLError ( 'Error attached to node without location' , parse ( '{ foo }' , { noLocation : true } ) ) ; expect ( error . toString ( ) ) . to . equal ( 'Error attached to node without location' ) ; } ) ; it ( 'prints an error with nodes from different sources' , ( ) => { const docA = parse ( new Source ( dedent `
          type Foo {
            field: String
          }
        ` , 'SourceA' ) ) ; const opA = docA . definitions [ 0 ] ; invariant ( opA . kind === Kind . OBJECT_TYPE_DEFINITION && opA . fields ) ; const fieldA = opA . fields [ 0 ] ; const docB = parse ( new Source ( dedent `
          type Foo {
            field: Int
          }
        ` , 'SourceB' ) ) ; const opB = docB . definitions [ 0 ] ; invariant ( opB . kind === Kind . OBJECT_TYPE_DEFINITION && opB . fields ) ; const fieldB = opB . fields [ 0 ] ; const error = new GraphQLError ( 'Example error with two nodes' , [ fieldA . type , fieldB . type , ] ) ; expect ( error . toString ( ) ) . to . equal ( dedent `
      Example error with two nodes

      SourceA:2:10
      1 | type Foo {
      2 |   field: String
        |          ^
      3 | }

      SourceB:2:10
      1 | type Foo {
      2 |   field: Int
        |          ^
      3 | }
    ` ) ; } ) ; } ) ; describe ( 'toJSON' , ( ) => { it ( 'Deprecated: format an error using formatError' , ( ) => { const error = new GraphQLError ( 'Example Error' ) ; expect ( formatError ( error ) ) . to . deep . equal ( { message : 'Example Error' , } ) ; } ) ; it ( 'includes path' , ( ) => { const error = new GraphQLError ( 'msg' , null , null , null , [ 'path' , 3 , 'to' , 'field' , ] ) ; expect ( error . toJSON ( ) ) . to . deep . equal ( { message : 'msg' , path : [ 'path' , 3 , 'to' , 'field' ] , } ) ; } ) ; it ( 'includes extension fields' , ( ) => { const error = new GraphQLError ( 'msg' , null , null , null , null , null , { foo : 'bar' , } ) ; expect ( error . toJSON ( ) ) . to . deep . equal ( { message : 'msg' , extensions : { foo : 'bar' } , } ) ; } ) ; } ) ;