jameslnewell / xhr-mock

Utility for mocking XMLHttpRequest.
196 stars 48 forks source link

Throws 'A handler errored' to console after upgrading to 2.3.0 #57

Closed henri-hulski closed 6 years ago

henri-hulski commented 6 years ago

After upgrading to version 2.3.0 I get some of the following errors when running my tests:

   console.error node_modules/xhr-mock/lib/MockXMLHttpRequest.js:673
      xhr-mock: A handler errored:
       Error: xhr-mock: No handler returned a response.
          at /home/pacha/web/cerebral/auth-boilerplate/node_modules/xhr-mock/lib/handle.js:31:19
          at <anonymous>

But the tests are still passing. One example test which throws to console:

import mock from 'xhr-mock'
import { CerebralTest } from 'cerebral/test'

import app from '.'

beforeEach(() => {
  mock.setup()
  localStorage.removeItem('jwtHeader')
})

test('should refresh token when expired token and refresh allowed', async () => {
  expect.assertions(2)

  localStorage.setItem(
    'jwtHeader',
    JSON.stringify(authHeader.expiredRefreshableJwt)
  )
  let cerebral = CerebralTest(app({ flash: null, flashType: null }))

  mock.get('/api/refresh', (req, res) => {
    return res
      .status(200)
      .header('Content-Type', 'application/json')
      .header('Authorization', authHeader.validJwt)
  })

  await cerebral
    .runSignal('appMounted')
    .then(({ state }) => [
      expect(state.user.authenticated).toBe(true),
      expect(state.user.nickname).toBe('Tester'),
    ])
})

I do not really understand why it throws this error.

jameslnewell commented 6 years ago

Hi @henri-hulski. Thanks for reaching out. The error isn't being thrown, its being logged. Prior to v2.3 there was no reporting of errors that occurred in handlers or due to a lack of matching handlers for the requested URL. This made it very difficult to debug whether the error event emitted by the xhr was real, was due to xhr-mock or was due to a handler. This behaviour masked real problems within tests.

v2.3 changes this behaviour by logging the errors by default. If you wish, you can change how errors are logged by setting mock.error(({req, err}) => {/* log the error, or don't log the error as you please */}). However, with the default behaviour, the only times you should actually see errors logged is when your handler looks like this (req, res) => Promise.reject(res). All other errors logged will uncover real problems with your tests. For example, in the reported example you'll want to look into why your mock.get() isn't being matched.

henri-hulski commented 6 years ago

@jameslnewell thanks for your answer. I actually found out that the error mean that a url which was called was not covered by a mock. Really great for debugging the tests.

Is there an option to print out the url which is not covered? Normally it's not a problem, but in the above case I was not able yet to find out, which url is called.

jameslnewell commented 6 years ago

Yep sure. You have access to the request in the error callback.

eg:

mock.error(({req, err}) => console.log(req.url(), err)

I'll look at including the request details in the message by default.

henri-hulski commented 6 years ago

@jameslnewell Hmm It's quite strange. When adding

mock.error(({req, err}) => console.log(req, err))

I get

PASS  client/app/app.test.js (5.261s)
  ● Console

    console.log client/app/app.test.js:11
      MockRequest {
        _method: 'GET',
        _url: MockURLImplementation { path: '/api/refresh', query: {} },
        _headers:
         { 'content-type': 'application/json; charset=UTF-8',
           accept: 'application/json',
           authorization: '' },
        _body: null } Error: xhr-mock: No handler returned a response.
          at /home/pacha/web/cerebral/auth-boilerplate/node_modules/xhr-mock/lib/handle.js:31:19
          at <anonymous>

Which is not expected as I actually have a handler for this case as you can see above. When removing the handler I get 2 times the same message and the test is failing.

henri-hulski commented 6 years ago

Ok I have solved it. My bad! Had just to move mock.get before CerebralTest().

henri-hulski commented 6 years ago

Really much better for debugging now. Found some important issues!

jameslnewell commented 6 years ago

🕺

jameslnewell commented 6 years ago

In v2.3.1 I've updated the default error logging to look like this:

      xhr-mock: No handler returned a response for the request.

        GET / HTTP/1.1
      xhr-mock: A handler returned an error for the request.

        GET / HTTP/1.1

        Error: 😵
            at /Users/jnewell/code/xhr-mock/packages/xhr-mock/test/acceptance.test.ts:277:41
            at /Users/jnewell/code/xhr-mock/packages/xhr-mock/src/createMockFunction.ts:55:16
            at /Users/jnewell/code/xhr-mock/packages/xhr-mock/src/handle.ts:42:20
            at <anonymous>

Feel free to suggest better messages/formatting. Ty.

henri-hulski commented 6 years ago

Cool! I think it would make sense to include some request info at least in the first case. Really helps debugging.

henri-hulski commented 6 years ago

XHR-mock v.2.3.1 fixed also another problem. In another app I suddenly had a handful of failing tests after upgrading to 2.3.0. Seems that xhr-mocks has overridden the HttpProviderError which is thrown by @cerebral/http but which is actually part of the workflow. With 2.3.1 this is fixed.

jameslnewell commented 6 years ago

I've never used cerebral but the other fix in v2.3.1 was #58.