React - Testing a wrapper for server request with Jest and mock throws: "Error: read ECONNRESE"
React - Testing a wrapper for server request with Jest and mock throws: "Error: read ECONNRESE"
TL;DR: 我如何测试用 React 包装 fetch 的函数?
我正在使用 TypeScript 构建一个 React 应用程序。为了使用 fetch api 我将这些库添加到我的 tsconfig:
"lib": ["es2017", "dom"],
现在我写了下面的函数:
import { Schema } from "normalizr";
import { camelizeAndNormalize } from "../../core";
export const getRequest = (fullUrlRoute: string, schema: Schema) =>
fetch(fullUrlRoute).then(response =>
response.json().then(json => {
if (!response.ok) {
return Promise.reject(json);
}
return Promise.resolve(camelizeAndNormalize(json, schema));
})
);
函数camelizeAndNormalize
字面意思就是按照它说的去做。 (我正在使用 normalizr 规范化 Redux 的状态)。
现在我想用下面的 Jest 测试来测试这个包装函数:
import fetch from "jest-fetch-mock";
import { schema } from "normalizr";
import { getRequest } from "./getRequests";
const response = {
author: {
id: "1",
name: "Paul"
},
comments: [
{
commenter: {
id: "2",
name: "Nicole"
},
id: "324"
}
],
id: "123",
title: "My awesome blog post"
};
const expected = {
entities: {
articles: {
"123": {
author: "1",
comments: ["324"],
id: "123",
title: "My awesome blog post"
}
},
comments: {
"324": { id: "324", commenter: "2" }
},
users: {
"1": { id: "1", name: "Paul" },
"2": { id: "2", name: "Nicole" }
}
},
result: "123"
};
const fullTestUrl = "https://google.com";
const user = new schema.Entity("users");
const comment = new schema.Entity("comments", {
commenter: user
});
const testSchema = new schema.Entity("articles", {
author: user,
comments: [comment]
});
describe("get request", () => {
beforeEach(() => {
fetch.resetMocks();
});
it("calls the given fullUrlRoute and returns data", () => {
fetch.mockResponseOnce(JSON.stringify(response));
expect.assertions(3);
return getRequest(fullTestUrl, testSchema).then(res => {
expect(res).toEqual(expected);
expect(fetch.mock.calls.length).toEqual(1);
expect(fetch.mock.calls[0][0]).toEqual(fullTestUrl);
});
});
it("recognizes when a response's status is not okay", () => {
fetch.mockResponseOnce(JSON.stringify({ ok: false }), { status: 403 });
expect.assertions(1);
return getRequest(fullTestUrl, testSchema).catch(err => {
expect(err.ok).toEqual(false);
});
});
it("recognizes a failed fetch request", () => {
fetch.mockReject(new Error("fake error message"));
expect.assertions(1);
return getRequest(fullTestUrl, testSchema).catch(err => {
expect(err).toEqual(Error("fake error message"));
});
});
});
在这个测试中,我使用 jest-fetch-mock 模拟了 fetch。虽然这个测试抛出错误:
FAIL src/services/utils/serverRequests/GET/getRequests.test.ts
● Console
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: connect ECONNREFUSED 68.178.213.61:443
at Object.dispatchError (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at Request.emit (events.js:165:20)
at Request.onRequestError (/Users/jan/Startup/pontemio/pontem/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:160:13)
at TLSSocket.socketErrorListener (_http_client.js:389:9)
at TLSSocket.emit (events.js:160:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:152:19) undefined
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: connect ECONNREFUSED 68.178.213.61:443
at Object.dispatchError (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at Request.emit (events.js:165:20)
at Request.onRequestError (/Users/jan/Startup/pontemio/pontem/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:160:13)
at TLSSocket.socketErrorListener (_http_client.js:389:9)
at TLSSocket.emit (events.js:160:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:152:19) undefined
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: connect ECONNREFUSED 68.178.213.61:443
at Object.dispatchError (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at Request.emit (events.js:165:20)
at Request.onRequestError (/Users/jan/Startup/pontemio/pontem/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:160:13)
at TLSSocket.socketErrorListener (_http_client.js:389:9)
at TLSSocket.emit (events.js:160:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:152:19) undefined
为什么模拟不起作用?我如何测试在 React with Jest 中使用 fetch 的函数?
发现我错过了什么。我需要将以下内容添加到我的 src/setupTests.ts
:
// react-testing-library renders your components to document.body,
// this will ensure they're removed after each test.
// this adds jest-dom's custom assertions
import "jest-dom/extend-expect";
import "react-testing-library/cleanup-after-each";
// setupJest.js or similar file
const globalAny: any = global;
// tslint:disable-next-line
globalAny.fetch = require("jest-fetch-mock");
TL;DR: 我如何测试用 React 包装 fetch 的函数?
我正在使用 TypeScript 构建一个 React 应用程序。为了使用 fetch api 我将这些库添加到我的 tsconfig:
"lib": ["es2017", "dom"],
现在我写了下面的函数:
import { Schema } from "normalizr";
import { camelizeAndNormalize } from "../../core";
export const getRequest = (fullUrlRoute: string, schema: Schema) =>
fetch(fullUrlRoute).then(response =>
response.json().then(json => {
if (!response.ok) {
return Promise.reject(json);
}
return Promise.resolve(camelizeAndNormalize(json, schema));
})
);
函数camelizeAndNormalize
字面意思就是按照它说的去做。 (我正在使用 normalizr 规范化 Redux 的状态)。
现在我想用下面的 Jest 测试来测试这个包装函数:
import fetch from "jest-fetch-mock";
import { schema } from "normalizr";
import { getRequest } from "./getRequests";
const response = {
author: {
id: "1",
name: "Paul"
},
comments: [
{
commenter: {
id: "2",
name: "Nicole"
},
id: "324"
}
],
id: "123",
title: "My awesome blog post"
};
const expected = {
entities: {
articles: {
"123": {
author: "1",
comments: ["324"],
id: "123",
title: "My awesome blog post"
}
},
comments: {
"324": { id: "324", commenter: "2" }
},
users: {
"1": { id: "1", name: "Paul" },
"2": { id: "2", name: "Nicole" }
}
},
result: "123"
};
const fullTestUrl = "https://google.com";
const user = new schema.Entity("users");
const comment = new schema.Entity("comments", {
commenter: user
});
const testSchema = new schema.Entity("articles", {
author: user,
comments: [comment]
});
describe("get request", () => {
beforeEach(() => {
fetch.resetMocks();
});
it("calls the given fullUrlRoute and returns data", () => {
fetch.mockResponseOnce(JSON.stringify(response));
expect.assertions(3);
return getRequest(fullTestUrl, testSchema).then(res => {
expect(res).toEqual(expected);
expect(fetch.mock.calls.length).toEqual(1);
expect(fetch.mock.calls[0][0]).toEqual(fullTestUrl);
});
});
it("recognizes when a response's status is not okay", () => {
fetch.mockResponseOnce(JSON.stringify({ ok: false }), { status: 403 });
expect.assertions(1);
return getRequest(fullTestUrl, testSchema).catch(err => {
expect(err.ok).toEqual(false);
});
});
it("recognizes a failed fetch request", () => {
fetch.mockReject(new Error("fake error message"));
expect.assertions(1);
return getRequest(fullTestUrl, testSchema).catch(err => {
expect(err).toEqual(Error("fake error message"));
});
});
});
在这个测试中,我使用 jest-fetch-mock 模拟了 fetch。虽然这个测试抛出错误:
FAIL src/services/utils/serverRequests/GET/getRequests.test.ts
● Console
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: connect ECONNREFUSED 68.178.213.61:443
at Object.dispatchError (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at Request.emit (events.js:165:20)
at Request.onRequestError (/Users/jan/Startup/pontemio/pontem/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:160:13)
at TLSSocket.socketErrorListener (_http_client.js:389:9)
at TLSSocket.emit (events.js:160:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:152:19) undefined
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: connect ECONNREFUSED 68.178.213.61:443
at Object.dispatchError (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at Request.emit (events.js:165:20)
at Request.onRequestError (/Users/jan/Startup/pontemio/pontem/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:160:13)
at TLSSocket.socketErrorListener (_http_client.js:389:9)
at TLSSocket.emit (events.js:160:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:152:19) undefined
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Error: connect ECONNREFUSED 68.178.213.61:443
at Object.dispatchError (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
at Request.client.on.err (/Users/jan/Startup/pontemio/pontem/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
at Request.emit (events.js:165:20)
at Request.onRequestError (/Users/jan/Startup/pontemio/pontem/node_modules/request/request.js:881:8)
at ClientRequest.emit (events.js:160:13)
at TLSSocket.socketErrorListener (_http_client.js:389:9)
at TLSSocket.emit (events.js:160:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:152:19) undefined
为什么模拟不起作用?我如何测试在 React with Jest 中使用 fetch 的函数?
发现我错过了什么。我需要将以下内容添加到我的 src/setupTests.ts
:
// react-testing-library renders your components to document.body,
// this will ensure they're removed after each test.
// this adds jest-dom's custom assertions
import "jest-dom/extend-expect";
import "react-testing-library/cleanup-after-each";
// setupJest.js or similar file
const globalAny: any = global;
// tslint:disable-next-line
globalAny.fetch = require("jest-fetch-mock");