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

TypeError: Cannot read property 'resolve' of undefined #3

Closed
dotnetCarpenter opened this Issue Jan 14, 2018 · 14 comments

Comments

Projects
None yet
7 participants
@dotnetCarpenter

dotnetCarpenter commented Jan 14, 2018

I need help to understand this error message. The stack trace is:

at e.value (node_modules/jest-mock-axios/dist/webpack:/lib/mock-axios.ts:66:20)
at Object.<anonymous> (tests/loader.test.js:17:27)

I've followed the README and created a __mock__/axios.js file in the root.

// ./__mock__/axios.js
import mockAxios from 'jest-mock-axios'
export default mockAxios

I then created a simple test case in tests/loader.test.js:

import mockAxios from 'jest-mock-axios'
import dummyTest from './tmp/dummy'

afterEach(() => {
  // cleaning up the mess left behind the previous test
  mockAxios.reset()
})

it('is just an implementation to check that we can mock axios', () => {
  const dummyF = jest.fn()
  const dummyCatch = jest.fn()

  dummyTest('hello')
    .then(dummyF)
    .catch(dummyCatch)

  mockAxios.mockResponse({ data: 'world'})

  expect(mockAxios.get).toHaveBeenCalledWith('/foobar/', 'hello')

  expect(dummyF).toHaveBeenCalledWith('world')

  expect(dummyCatch).not.toHaveBeenCalled()
})

In `tests/tmp/dummy.js' I have:

import axios from 'axios'

export default function dummyTest (msg) {
  const loader = axios.get('/foobar/', { data: msg })

  return loader.then(data => 'world')
}

The result is:

FAIL  tests/loader.test.js
  ● is just an implementation to check that we can mock axios

    TypeError: Cannot read property 'resolve' of undefined

      at e.value (node_modules/jest-mock-axios/dist/webpack:/lib/mock-axios.ts:66:20)
      at Object.<anonymous> (tests/loader.test.js:17:27)
@dotnetCarpenter

This comment has been minimized.

dotnetCarpenter commented Jan 14, 2018

I looked through my local jest-mock-axios package but since it's transpiled I didn't get much out of it. Looking at the source on github, it becomes much more clear. The error in the stack trace points to lib/mock-axios.ts#L66.

What is not clear is from where the response is suppose to come from. Since we are mocking an HTTP call, I expect that non existing end-points can be used for testing.

@dotnetCarpenter

This comment has been minimized.

dotnetCarpenter commented Jan 14, 2018

OK, I was too fast. Of couse the promise variable is the issue here. lib/mock-axios.ts#L54

@dotnetCarpenter

This comment has been minimized.

dotnetCarpenter commented Jan 14, 2018

Hmm.. The README says that mockAxios.mockResponse can be called with { data: 'server says hello!' } but that doesn't looks like the signature for public mockResponse(response?:HttpResponse, promise:SyncPromise=null):void {.

What am I missing?

@dotnetCarpenter

This comment has been minimized.

dotnetCarpenter commented Jan 14, 2018

I've never written typescript so I might be wrong but let's assume that the type HttpResponse does nothing, then { data: 'world' } will be mixed in the response object.

Node: v8.9.4
jest: 22.0.6

@dotnetCarpenter

This comment has been minimized.

dotnetCarpenter commented Jan 14, 2018

Jesus. I misspelled __mocks__(missing s)!

@danawoodman

This comment has been minimized.

Contributor

danawoodman commented Feb 23, 2018

I'm having this same issue but have the __mocks__ folder spelled correctly. Perhaps there is another reason for this?

Even though I'm passing in a promise this error throws, which is unexpected.

I am using TypeScript and this is a sample of the code I'm working with:

// currency.ts
import axios from 'axios'

const CURRENCY_API = '/v1/currency'

class Currency {
  static price() {
    return axios
      .get(CURRENCY_API)
      .then((resp: axios.Response) => Number(resp.data[0].price_usd))
      .catch((error: Error) => console.log(error))
  }
}

export default Currency
// currency.test.ts
import mockAxios from 'jest-mock-axios'
import Currency from './currency'

describe('server/models/currency', () => {
  afterEach(() => mockAxios.reset())

  describe('.price', () => {
    test('returns the correct currency valule', async () => {
      const resp = { data: [{ price_usd: '15000' }] }
      mockAxios.mockResponse(resp)
      const actual = await Currency.price()
      expect(mockAxios.get).toHaveBeenCalled()
      const expected = 15000
      expect(actual).toBe(expected)
    })
  })
})
@danawoodman

This comment has been minimized.

Contributor

danawoodman commented Feb 23, 2018

@knee-cola any chance you have some ideas on why this would be happening?

@DominicGebhart

This comment has been minimized.

DominicGebhart commented Feb 26, 2018

I ran into the same problem today.

@danawoodman

This comment has been minimized.

Contributor

danawoodman commented Feb 27, 2018

I ended up just using direct mocking using Jest that works pretty well:

import axios from 'axios'
import http from './http'

jest.mock('axios')

test('should return data', async () => {
  const url = '/foo'
  const resp = { data: 'bar' }
  axios.get.mockReturnValue(resp)
  const data = await http.get(url)
  expect(axios.get).toBeCalledWith(url)
  expect(data).toBe(resp.data)
})
@knee-cola

This comment has been minimized.

Owner

knee-cola commented Mar 1, 2018

I have managed to reproduce the original error reported by @dotnetCarpenter and can confirm he's findings . This problem can be caused by mispelling the "mocks" directory. The mocking file needs to ne placed inside the mocks directory - not the *mock dir.

@danawoodman have you configured Jest to transform TypeScript before running the tests?

Here's a sampe jest.config.js file (it's used in one of my projects, which contains Axios tests):

module.exports = {
    "verbose": true,
    "testRegex": "/test/.*\\.spec\\.(ts|tsx|js)$",
    "moduleFileExtensions": [
        "ts",
        "tsx",
        "js"
    ],
    "transform": {
        "\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
    }
};

Also here's the tsconfig.js:

{
    // docs: https://basarat.gitbooks.io/typescript/content/docs/project/tsconfig.html
    "compilerOptions": {
        "noImplicitAny": true,
        // module resolution strategy ('node','classic')
        "moduleResolution": "node",
        //  ECMAScript target version ('ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT')
        "target": "ESNEXT",
        // module code generation ('commonjs', 'amd', 'system', 'umd' or 'es2015')
        "module": "commonjs",
        // create declaration files in output folder
        "declaration": true,
        "declarationDir": "./"
    },
    // excluding folders from being included
    // while creating `declaration` files
    "exclude": [
        "test",
        "__mocks__"
    ]
}
@danawoodman

This comment has been minimized.

Contributor

danawoodman commented Mar 1, 2018

@knee-cola yes it is transforming TypeScript

@vnugent

This comment has been minimized.

vnugent commented Mar 7, 2018

I'm seeing the same error as described by OP. The dir is correctly spelled as mocks.

node: v7.10.0

  "dependencies": {
    "axios": "~0.17.1",
    "axios-mock-adapter": "~1.12.0",
    "react": "~16.2.0",
    "react-dom": "~16.2.0",
    "react-router-dom": "^4.2.2",
    "react-scripts-ts": "2.13.0"
@timthompson

This comment has been minimized.

timthompson commented Apr 4, 2018

I ran across this same issue and thought I would comment for anyone else that may come across this issue.

If the problem isn't the spelling/placement of the __mocks__ directory, another potential cause of this issue that isn't really spelled out in the docs but makes sense after looking at the source is the mockAxios.mockResponse() or mockAxios.mockError() call should come after your axios call is triggered in your test code.

If it comes before the axios call is triggered then you will get this error.

So trigger the call, then tell mockAxios how you want it to respond.

@shortstevenn

This comment has been minimized.

shortstevenn commented Apr 26, 2018

@timthompson nice catch, that was pretty non-obvious :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment