When I make real calls, my tests are passing fine; however, when I "nock" my requests, they fail with error message "Network Error." Here is the full error object I'm catching:
{ Error: Network Error
at createError (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/axios/lib/core/createError.js:15:15)
at XMLHttpRequest.handleError [as onerror] (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/axios/lib/adapters/xhr.js:85:14)
at XMLHttpRequest.callback.(anonymous function) (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:251:32)
at invokeEventListeners (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:210:27)
at invokeInlineListeners (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:168:7)
at EventTargetImpl._dispatch (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:7)
at EventTargetImpl.dispatchEvent (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:91:17)
at XMLHttpRequest.dispatchEvent (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:71:35)
at dispatchError (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:915:9)
at Request.client.on.err (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:623:11)
at emitOne (events.js:101:20)
at Request.emit (events.js:188:7)
at Request.onRequestError (/Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/request/request.js:813:8)
at emitOne (events.js:96:13)
at OverriddenClientRequest.emit (events.js:188:7)
at /Users/pauljaworski/Projects/OverEasy/over-easy-ui/node_modules/nock/lib/request_overrider.js:206:11
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
config:
{ transformRequest: { '0': [Function: transformRequest] },
transformResponse: { '0': [Function: transformResponse] },
headers:
{ Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8' },
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
method: 'post',
url: '{my url stripped for security}',
data: '{"petitionerId":"abc123","createdAt":"2016-09-26T16:29:28.612Z","updatedAt":null}' },
response: undefined }
I got the same error
@itsovereasy could you post how you use nock and how you make the request please?
Here's a test using nock that gives a "network error":
it('should dispatch the proper actions on fail', () => {
const error = 'Failed to create assets';
nock('https://<my-api-url>.amazonaws.com:443', { encodedQueryParams: true })
.post('/dev/assets/create', { petitionerId: 'abc123', createdAt: '2016-09-26T16:19:56.911Z', updatedAt: null })
.replyWithError({ message: error });
const store = mockStore(initialState);
const data = {
petitionerId: 'abc123'
};
const expected = [
{ type: constants.REQUEST_ASSETS_CREATE, data },
{ type: constants.ASSETS_CREATE_FAIL, data, error },
];
return store.dispatch(actions.createAssets(data))
.then(() => {
expect(store.getActions()).toEqual(expected);
});
});
I have another "success" test as well, where I am even including the response headers suggested, that also fails:
it('should dispatch the proper actions on success', () => {
nock('https://<my-api-url>.us-west-2.amazonaws.com:443', { encodedQueryParams: true })
.post('/dev/assets/create', { petitionerId: 'abc123', createdAt: '2016-09-26T16:19:56.911Z', updatedAt: null })
.reply(200, {}, { 'content-type': 'application/json',
'content-length': '2',
connection: 'keep-alive',
date: 'Mon, 26 Sep 2016 16:19:57 GMT',
'access-control-allow-origin': '*',
'x-amzn-requestid': '<my-requestid>',
'x-cache': 'Miss from cloudfront',
via: '1.1 <my-cloudfront>.cloudfront.net (CloudFront)',
'x-amz-cf-id': '<my-cf-id>' });
const store = mockStore(initialState);
const data = {
petitionerId: 'abc123'
};
const expected = [
{ type: constants.REQUEST_ASSETS_CREATE, data },
{ type: constants.ASSETS_CREATE_SUCCESS, data, response: {} },
];
return store.dispatch(actions.createAssets(data))
.then(() => {
expect(store.getActions()).toEqual(expected);
});
});
Thanks for the test examples. I don't see anything obviously wrong with them.
How do you make the actual requests? Which library are you using?
Im having a similar problem testing a service using axios. Im testing on phatomjs, does this library also Intercept the browser requests?
I see the issue #409 related to fetch, is the problem related just to that lib or it happens also in other libs like axios.
@vrinek I'm using axios. That seems to be the issue.
@ndelvalle It seems that nock and axios don't play well together, and I believe it's related to the OPTIONS request axios sends before the actual request. I ended up using this method for stubbing my axios requests, and it's working for me now.
Hopefully nock will work with axios in the future, though, because the syntax is much nicer.
Yeah I would really like to use nock instead of stubbing with sinon. But I think I'll do that for now. Thanks @paulwithap.
Thanks for all the feedback. Next step would be to write some failing tests for axios integration with nock. Would someone like to pick that up?
My solution by using moxios:
```
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import * as actions from './index'
import * as types from './actionTypes'
import axios from 'axios'
import moxios from 'moxios'
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
const API_END_POINT = process.env.REACT_APP_API_ENDPOINT || 'https://web-api.com/api/v1/';
describe('async actions', () => {
beforeEach(function () {
moxios.install()
});
afterEach(function () {
moxios.uninstall()
});
it('creates returns data in RECV_DATA when axios contacts request has been done', () => {
moxios.stubRequest(API_END_POINT + 'contacts', {
status: 200,
response: { data: { contacts: [{id: 1, firstName: 'FirstName', displayName: 'FirstName'}] }}
});
const expectedActions = [
{ type: types.REQ_DATA },
{ type: types.RECV_DATA, data: { contacts: [{id: 1, firstName: 'FirstName', displayName: 'FirstName'}] } }
];
const store = mockStore({ contacts: [] });
return store.dispatch(actions.getData('contacts'))
.then(() => {
expect(store.getActions()).toEqual(expectedActions)
})
})
});
````
Is there any progress being made on this? Really would love to use nock instead of any other methods of HTTP mocking.
Edit: I would love to contribute but I'm quite new to testing and don't really know where to start so if anyone can give me pointers that would be awesome. 👍
I finally resolved the issue by this thread: https://github.com/mzabriskie/axios/issues/305
Below code from @dyakimenko-p works for me:
import {expect} from 'chai'
import axios from 'axios' // v0.15.3
import httpAdapter from 'axios/lib/adapters/http'
import nock from 'nock' // v9.0.2
const host = 'http://localhost';
axios.defaults.host = host;
axios.defaults.adapter = httpAdapter;
describe('suite', () => {
it('test', done => {
nock(host)
.get('/test')
.reply(200, 'test data');
axios.get('/test').then(response => {
expect(response.data).to.be.equal('test data');
done();
});
});
});
I am having a similar issue. The curious part is that nock works with the first request made to my /authenticate route, but fails to intercept the second route.
I have fully tried to use moxios as well but I do not have access to the axios instance directly.
Any help or direction would be greatly appreciated.
Here is the output of my test (using Jest)
yarn test v0.19.1
$ jest --no-cache
FAIL actions/__tests__/model/model.spec.js
● models › fetches all the models
AssertionError: Mocks not yet satisfied:
GET https://domain.example.com:443/model_type
at Scope.done (../node_modules/nock/lib/scope.js:158:10)
at actions/__tests__/model/model.spec.js:70:19
at run (../node_modules/core-js/modules/es6.promise.js:87:22)
at ../node_modules/core-js/modules/es6.promise.js:100:28
at flush (../node_modules/core-js/modules/_microtask.js:18:9)
at _combinedTickCallback (../internal/process/next_tick.js:67:7)
at process._tickCallback (../internal/process/next_tick.js:98:9)
models
✕ fetches all the models (30ms)
○ fetches a signle model instance
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 skipped, 2 total
Snapshots: 0 total
Time: 3.126s
Ran all test suites.
console.log ../node_modules/nock/lib/interceptor.js:321
matching https://domain.example.com:443 to POST https://domain.example.com:443/authenticate: true
error Command failed with exit code 1.
Had to rename some variables as per company policy
here is the code:
import nock from 'nock';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import * as actions from 'actions/model';
import * as TYPES from '../../model/constants';
import { expect } from 'chai';
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
describe('models', () => {
const gmodel = {
id: 1,
name: 'Test',
number: 1,
created_at: 1482348266,
updated_at: 1482348266,
};
const BASE_URL = 'https://domain.exampe.com';
beforeEach(() => {
nock.disableNetConnect();
nock(BASE_URL)
.log(console.log)
.post('/authenticate')
.reply(200, { token: 1 });
});
afterEach(() => nock.cleanAll());
fit('fetches all the models', () => {
const model = 'model_type';
const data = [ gmodel ];
const store = mockStore({ model_type: {} });
const expectedActions = [
{
type: TYPES.MODEL_ALL,
model: { type: model },
data,
},
];
const scope = nock(BASE_URL)
.log(console.log)
.get('/model_type')
.reply(200, { data });
return store.dispatch(actions.getAllModels(model))
.then(() => {
scope.done();
expect(store.getActions()).to.equal(expectedActions);
});
});
Just in case it could help someone, I was getting Network Error on hosts other than http://localhost before I installed isomorphic-fetch for my react app.
I have a similar issue while using nock with axios (setup - jest + enzyme, react, redux) when I am testing an async action. When I try to dispatch an action ( store.dispatch(fetchData()).then() ), I get the error
TypeError: Cannot read property 'then' of undefined
Why is this happening? nock is unable to mock the http request, I have looked at a lot of sources, but could not solve it. Any help is appreciated
code -
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import nock from 'nock';
import { fetchData } from '../../actions/index';
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
const host = 'http://localhost';
describe('test actions', () => {
it('fetch data', () => {
const expectedData = {alpha: 1};
nock(host)
.get('/installation')
.reply(200, expectedData);
const expectedActions = [{
type: 'FETCH_DATA_FULFILLED',
payload: expectedData
}];
const store = mockStore({alpha: 0});
return store.dispatch(fetchData())
// error occurs at this point
.then(() => {
expect(store.getActions().toEqual(expectedActions));
})
.error(() => {
});
});
});
This also appears to be happening with prequest requests too.
@aditya1315 the problem is with fetchData, can you print it?
it should return a promise, does it?
also if u use axiox in fetchData, you should also need the adapter (define in the actions file after you import the axios)
axios.defaults.adapter = httpAdapter;
This problem is related to jsdom, somehow. I switched from using Jest to using Jasmine as my testing framework and axios works out of the box with nock without changing the adapter or anything like that.
When axios is initializing, it checks if it's running in browser or node (see here) and it uses the appropriate adapter (http for node, xhr for browser and jsdom).
This means that if you require/import axios after you already have a jsdom globally available, axios will use the xhr adapter and use jsdom's XMLHttpRequest object.
When axios is getting an error without any details from the browser, it returns a general "Network Error" exception (see here). To get more information about the error you're getting you can either use jsdom v10.x.x (has a default virtual console that sends everything to node's console), or if you're using v9.x.x or bellow, setup a virtual console by yourself:
var virtualConsole = jsdom.createVirtualConsole().sendTo(console);
require('jsdom-global')(..., { virtualConsole });
I'm assuming you're getting cross-origin errors, if that's the case, here's how you can solve it.
You can either use axios's http adapter, which means you don't go through jsdom's APIs so no cross origin problems.
For testing react components you probably want to axios to go through jsdom's APIs, and you want your document running under a domain, and you would like to get cross origin errors if you're making requests outside of that domain. To make it work, you just need to setup your mocks with nock to return cross origin headers (just like you would on a real browser).
To initialize a jsdom under a domain, just pass a url option, like that:
require('jsdom-global')(..., { url: 'http://some-url.com' });
Finally, return a cors header from nock mocks:
nock('http://some-url.com').get('/').reply(200, 'hello world', {'Access-Control-Allow-Origin': '*'})
I believe the ideal solution would be nock to transparently fallback to xhr-mock when appropriate?
as i suggested recently here: https://github.com/nock/nock/issues/1160 ?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. We try to do our best, but nock is maintained by volunteers and there is only so much we can do at a time. Thank you for your contributions.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue and add a reference to this one if it’s related. Thank you!
Most helpful comment
I finally resolved the issue by this thread: https://github.com/mzabriskie/axios/issues/305
Below code from @dyakimenko-p works for me: