издеваюсь над крюком Аполлона
jest.mock("@apollo/client", () => ({
...jest.requireActual("@apollo/client"),
useApolloClient: () => ({
query: jest.fn().mockResolvedValueOnce({
data: { myReturnValue: { some: "data" } },
loading: false,
errors: undefined,
}),
}),
}))
моя функция
const myFunction = (input) => {
console.info("called this?") // this 100% gets called in the test
const data = { ...defaultData, ...input }
return client
.query({
query: Query,
fetchPolicy: "network-only",
variables: {},
})
.then(({ data, errors }) => {
if (!data?) {
alert(errors)
} else {
console.info("in else block") // this 100% gets called in the test
runFunction()
}
})
}
в моем тесте регистрируется: «в блоке else»
и в моем тесте у меня есть:
fireEvent.click(screen.getByText("My Button Text"))
await waitFor(() => expect(useApolloClient().query).toBeCalledTimes(1))
В тестовом выводе я получаю
Expected number of calls: 1
Received number of calls: 0
почему это? Он определенно звонил client.query
, как это было в журналах
@jonrsharpe спасибо за хорошее объяснение. Есть ли способ достичь того, чего я пытаюсь, или это выходит за рамки модульного теста?
Не издевайтесь так. Используйте настоящий экземпляр клиента Apollo.
Самое простое решение — не создавать каждый раз новый объект, например. useApolloClient: () => ({
-> useApolloClient: jest.fn().mockReturnValue({
или просто извлеките значение и получите useApolloClient: () => fakeClient
. Но, вероятно, существуют и другие подходы, которые помогут вам приблизиться к тестированию реального поведения.
Как сказал @phry, не издевайтесь над модулем @apollo/client
. Вместо этого следуйте руководству Тестирование компонентов React.
Тестирование компонента с точки зрения пользователя, что эквивалентно тесту черного ящика. Не тестируйте конкретную реализацию (например, expect(someMethod).toBeCalled()
). Вместо этого мы должны утверждать, что отображает компонент. После того, как пользователь взаимодействует с компонентом, изменения в содержимом рендеринга будут
например
index.tsx
:
import React, { useState } from 'react';
import { gql, useApolloClient } from '@apollo/client';
export const GET_DOG_QUERY = gql`
query GetDog($name: String) {
dog(name: $name) {
id
name
breed
}
}
`;
export function SomeComponent() {
const client = useApolloClient();
const [data, setData] = useState();
console.info("🚀 ~ SomeComponent ~ data:", data)
const onClick = () => {
client
.query({
query: GET_DOG_QUERY,
fetchPolicy: 'network-only',
variables: {
name: 'Buck',
},
})
.then(({ data, errors }) => {
setData(data);
});
};
return (
<div>
<button onClick = {onClick}>My Button Text</button>
{data && <span>{data.dog.breed}</span>}
</div>
);
}
index.test.tsx
:
import React from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { GET_DOG_QUERY, SomeComponent } from '.';
import { fireEvent, render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
describe('78333569', () => {
test('should pass', async () => {
const mocks = [
{
request: {
query: GET_DOG_QUERY,
variables: {
name: 'Buck',
},
},
result: {
data: {
dog: { id: '1', name: 'Buck', breed: 'bulldog' },
},
},
},
];
render(
<MockedProvider mocks = {mocks} addTypename = {false}>
<SomeComponent />
</MockedProvider>,
);
fireEvent.click(screen.getByText('My Button Text'));
expect(await screen.findByText('bulldog')).toBeInTheDocument();
});
});
Результат испытаний:
console.info
🚀 ~ SomeComponent ~ data: undefined
at log (stackoverflow/78333569/index.tsx:18:11)
console.info
🚀 ~ SomeComponent ~ data: { dog: { id: '1', name: 'Buck', breed: 'bulldog' } }
at log (stackoverflow/78333569/index.tsx:18:11)
PASS stackoverflow/78333569/index.test.tsx
78333569
√ should pass (78 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.332 s, estimated 3 s
Ran all test suites related to changed files.
версии пакета:
"@apollo/client": "^3.9.11"
Каждый раз, когда вы вызываете
useApolloClient
, вы получаете новый объект с новым свойством запроса и новым значением фиктивной функции.expect(useApolloClient().query).toBeCalledTimes(1)
никогда не сможет добиться успеха, даже если вы проведете опрос, потому что единственная существующая ссылка на макет находится в ожидании.