import errToJSON from '../index'
import regExpEscape from 'escape-string-regexp'

describe('error to json', function () {
  it('should convert an error w/ non-enumerable props to json', function () {
    const err = new TypeError('boom')
    const nonEnumerableProps = ['code', 'errno', 'syscall']
    nonEnumerableProps.forEach(function (prop) {
      Object.defineProperty(err, prop, {
        // val is just prop
        value: prop,
      })
    })
    // @ts-ignore
    err.json = {
      toJSON() {
        return {
          some: 'json',
        }
      },
    }
    const json = errToJSON(err)
    // @ts-ignore
    json.stack = cleanStack(json.stack)
    expect(json).toMatchInlineSnapshot(`
      Object {
        "code": "code",
        "errno": "errno",
        "json": Object {
          "some": "json",
        },
        "message": "boom",
        "name": "TypeError",
        "stack": "TypeError: boom
          at Object.<anonymous> (/src/__tests__/errorToJSON.test.ts:6:17)
          at Object.asyncJestTest (/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
          at /node_modules/jest-jasmine2/build/queueRunner.js:47:12
          at new Promise (<anonymous>)
          at mapper (/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
          at /node_modules/jest-jasmine2/build/queueRunner.js:77:41",
        "syscall": "syscall",
      }
    `)
  })

  it('should convert an error w/ enumerable props to json', function () {
    var err = new TypeError('boom')
    var extended = {
      data: {
        someModel: {
          foo: 10,
          bar: 20,
          qux: function () {},
          toJSON: function () {
            return { foo: 10, bar: 20 }
          },
        },
        someData: {
          a: 1,
          b: 2,
          c: 3,
        },
        err: Object.assign(new Error('boom2'), {
          data: {
            someDeepData: 1,
            err: new Error('boom3'),
          },
        }),
      },
      statusCode: 400,
    }
    Object.assign(err, extended)
    var json = errToJSON(err)
    // @ts-ignore
    json.stack = cleanStack(json.stack)
    // @ts-ignore
    json.data.err.stack = cleanStack(json.data.err.stack)
    // @ts-ignore
    json.data.err.data.err.stack = cleanStack(json.data.err.data.err.stack)
    expect(json).toMatchInlineSnapshot(`
      Object {
        "data": Object {
          "err": Object {
            "data": Object {
              "err": Object {
                "message": "boom3",
                "name": "Error",
                "stack": "Error: boom3
          at Object.<anonymous> (/src/__tests__/errorToJSON.test.ts:66:18)
          at Object.asyncJestTest (/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
          at /node_modules/jest-jasmine2/build/queueRunner.js:47:12
          at new Promise (<anonymous>)
          at mapper (/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
          at /node_modules/jest-jasmine2/build/queueRunner.js:77:41",
              },
              "someDeepData": 1,
            },
            "message": "boom2",
            "name": "Error",
            "stack": "Error: boom2
          at Object.<anonymous> (/src/__tests__/errorToJSON.test.ts:63:28)
          at Object.asyncJestTest (/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
          at /node_modules/jest-jasmine2/build/queueRunner.js:47:12
          at new Promise (<anonymous>)
          at mapper (/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
          at /node_modules/jest-jasmine2/build/queueRunner.js:77:41",
          },
          "someData": Object {
            "a": 1,
            "b": 2,
            "c": 3,
          },
          "someModel": Object {
            "bar": 20,
            "foo": 10,
          },
        },
        "message": "boom",
        "name": "TypeError",
        "stack": "TypeError: boom
          at Object.<anonymous> (/src/__tests__/errorToJSON.test.ts:47:15)
          at Object.asyncJestTest (/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
          at /node_modules/jest-jasmine2/build/queueRunner.js:47:12
          at new Promise (<anonymous>)
          at mapper (/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
          at /node_modules/jest-jasmine2/build/queueRunner.js:77:41",
        "statusCode": 400,
      }
    `)
  })

  it('should invoke toJSON if error already has toJSON', () => {
    const err = new Error()
    const json = {}
    // @ts-ignore
    err.toJSON = () => json
    expect(errToJSON(err)).toBe(json)
  })
})

function cleanStack(stack: string) {
  return stack
    .replace(new RegExp(regExpEscape(process.cwd()), 'g'), '')
    .replace(/.*\/wallaby\/.*\n/g, '')
    .replace(/.* processTicksAndRejections .*(\n|$)/g, '')
    .replace(/queueRunner.js:77:41\n/g, 'queueRunner.js:77:41')
}
