Я создаю приложение React Native и пишу свои модульные тесты с помощью Jest.
(Как видно из этот вопрос,) Я пишу функцию, которая проверяет, есть ли сетевое соединение.
Вот функция (checkNetwork.ts):
import { NetInfo } from "react-native";
import { NO_NETWORK_CONNECTION } from "../../../../config/constants/errors";
const checkNetwork = (): Promise<boolean | string> =>
new Promise((resolve, reject) => {
NetInfo.isConnected
.fetch()
.then(isConnected => (isConnected ? resolve(true) : reject(NO_NETWORK_CONNECTION)))
.catch(() => reject(NO_NETWORK_CONNECTION));
});
export default checkNetwork;
Теперь я хочу поиздеваться над этой функцией при тестировании другой функции, которая выполняет вызовы API.
Я создал папку под названием __mocks__ рядом с checkNetwork.ts внутри checkNetwork/ (см. Структуру папок ниже). В нем я также создал еще один файл с именем checkNetwork.ts, который содержит макет и выглядит так:
const checkNetwork = () => new Promise(resolve => resolve(true));
export default checkNetwork;
Функция, которая использует эту функцию, делает простой запрос на выборку (postRequests.ts):
import checkNetwork from "../../core/checkNetwork/checkNetwork";
export const postRequestWithoutHeader = (fullUrlRoute: string, body: object) =>
checkNetwork().then(() =>
fetch(fullUrlRoute, {
method: "POST",
body: JSON.stringify(body),
headers: { "Content-Type": "application/json" }
}).then(response =>
response.json().then(json => {
if (!response.ok) {
return Promise.reject(json);
}
return json;
})
)
);
Структура папок выглядит так:
myreactnativeproject
├── app/
│ ├── services/
│ │ ├── utils/
│ │ │ └── core/
│ │ │ └── checkNetwork/
│ │ │ └── checkNetwork.ts
│ │ ├── serverRequests/
│ │ │ └── POST/
│ │ │ └── postRequests.ts
│ . .
│ . .
│ . .
.
.
.
Затем я создал другой файл под названием postRequests.test.ts в POST/ для написания модульных тестов для postRequests.test.ts. Теперь я ожидал, что Jest автоматически использует макет, который возвращает true. Но на самом деле происходит то, что тест не возвращает NO_NETWORK_CONNECTION. Как я могу заставить Jest использовать макет?






Вот решение, структура папок не имеет значения, для простоты структура папок выглядит следующим образом:
.
├── __mocks__
│ └── checkNetwork.ts
├── checkNetwork.ts
├── errors.ts
├── postRequests.test.ts
└── postRequests.ts
checkNetwork.ts:
import NetInfo from '@react-native-community/netinfo';
import { NO_NETWORK_CONNECTION } from './errors';
const checkNetwork = (): Promise<boolean | string> =>
new Promise((resolve, reject) => {
NetInfo.isConnected
.fetch()
.then(isConnected => (isConnected ? resolve(true) : reject(NO_NETWORK_CONNECTION)))
.catch(() => reject(NO_NETWORK_CONNECTION));
});
export default checkNetwork;
postRequests.ts:
import checkNetwork from './checkNetwork';
import fetch from 'node-fetch';
export const postRequestWithoutHeader = (fullUrlRoute: string, body: object) =>
checkNetwork().then(() =>
fetch(fullUrlRoute, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
}).then(response =>
response.json().then(json => {
if (!response.ok) {
return Promise.reject(json);
}
return json;
})
)
);
Модульный тест:
postRequests.test.ts:
import { postRequestWithoutHeader } from './postRequests';
import fetch from 'node-fetch';
const { Response } = jest.requireActual('node-fetch');
jest.mock('./checkNetwork.ts');
jest.mock('node-fetch');
describe('postRequestWithoutHeader', () => {
const mockedData = { data: 'mocked data' };
const mockedJSONData = JSON.stringify(mockedData);
const urlRoute = 'https://github.com/mrdulin';
const body = {};
it('should post request without header correctly', async () => {
(fetch as jest.MockedFunction<typeof fetch>).mockResolvedValueOnce(new Response(mockedJSONData));
const actualValue = await postRequestWithoutHeader(urlRoute, body);
expect(actualValue).toEqual(mockedData);
expect(fetch).toBeCalledWith(urlRoute, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
});
});
it('should post request error', async () => {
const mockedResponse = new Response(mockedJSONData, { status: 400 });
(fetch as jest.MockedFunction<typeof fetch>).mockResolvedValueOnce(mockedResponse);
await expect(postRequestWithoutHeader(urlRoute, body)).rejects.toEqual(mockedData);
expect(fetch).toBeCalledWith(urlRoute, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
});
});
});
Результат модульного тестирования со 100% покрытием:
PASS src/stackoverflow/52673113/postRequests.test.ts
postRequestWithoutHeader
✓ should post request without header correctly (7ms)
✓ should post request error (1ms)
-----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
postRequests.ts | 100 | 100 | 100 | 100 | |
-----------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.996s, estimated 5s
Вот завершенная демонстрация: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/52673113
Зависимости:
"@react-native-community/netinfo": "^4.2.1",
"react-native": "^0.60.5",
Я использую модуль react-native последней версии, поэтому модуль NetInfo устарел. https://facebook.github.io/react-native/docs/netinfo.html