Reputation: 709
I am getting loading state only and data as undefined in testing. I don't know why I am following everything in the given example. Please help.
Testing file. When i am waiting thsi line toexecute await wait(() => getByTestId('edit-category'));
. It is giving response data of query as undefined.
Error: TypeError: Cannot read property 'getCategory' of undefined
Line 34 on editConatinerCategory.tsx
=> category={data!.getCategory!}
import React from 'react';
import gql from 'graphql-tag';
import { cleanup, wait } from 'react-testing-library';
import { customRender } from '../../../test-utils/customRender';
import { EditCategoryContainer } from './Container';
afterEach(() => {
cleanup();
console.error;
});
console.error = jest.fn();
const getCategoryMock = {
request: {
query: gql`
query getCategory($id: Int!) {
getCategory(id: $id) {
id
name
active
position
}
}
`,
variables: {
id: 1
}
},
result: {
data: {
getCategory: {
id: 1,
name: 'category',
active: true,
position: 1
}
}
}
};
describe('create edit category module', () => {
test('Rendering correct', async () => {
const { container, debug, getByTestId } = customRender(<EditCategoryContainer />, [
getCategoryMock
]);
await wait(() => getByTestId('edit-category'));
await wait(() => expect(container).toMatchSnapshot());
//Getting this TypeError: Cannot read property 'getCategory' of undefined. Because i am data as undefined from my query response
});
});
CustomRender.tsx
import React from 'react';
import { render } from 'react-testing-library';
import { MockedProvider, MockedResponse } from 'react-apollo/test-utils';
import { Router, Switch } from 'react-router-dom';
import { createMemoryHistory } from 'history';
export const customRender = (
node: JSX.Element | null,
mocks?: MockedResponse[],
{
route = '/',
history = createMemoryHistory({ initialEntries: [route] })
} = {}
) => {
return {
history,
...render(
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={history}>
<Switch>{node}</Switch>
</Router>
</MockedProvider>
)
};
};
EditCategoryContainer.tsx
import React from 'react';
import { withRouter } from 'react-router';
import { Spin } from 'antd';
import {
AddCategoryComponent,
GetCategoryComponent
} from '../../../generated/graphql';
import { EditCategory } from './Edit';
import { LoadingComponent } from '../../../components/LoadingComponent';
export const EditCategoryContainer = withRouter(({ history, match }) => {
const id: number = parseInt(match.params.id, 10);
return (
<GetCategoryComponent
variables={{
id
}}
>
{({ data, loading: getCategoryLoading }) => {
console.log(getCategoryLoading, 'getCategoryLoading');
if (getCategoryLoading) {
return <LoadingComponent />;
}
if (data && !data.getCategory) {
return <div>Category not found!</div>;
}
console.log(data);
return (
<AddCategoryComponent>
{(addCategory, { loading, error }) => {
return (
<EditCategory
data-testid="edit-category"
category={data!.getCategory!}
loading={loading || getCategoryLoading}
onSubmit={values => {
addCategory({ variables: values }).then(() => {
history.push('/dashboard/categories');
});
}}
/>
);
}}
</AddCategoryComponent>
);
}}
</GetCategoryComponent>
);
});
Edit: I tried @mikaelrs solution which is passed match. But it is not working. I also tried to pass id:1 as fixed. But it is still giving error.
<GetCategoryComponent
variables={{
id:1
}}
>
...rest of code.
</GetCategoryComponent>
This is not working. My query without veriable is working fine. Mutation is also working fine. I am having only problem with this. When i have to pass like varible like this.
Upvotes: 3
Views: 9114
Reputation: 1901
I faced a similar issue. Here is how I resolved my issue.
First, wait for the query to resolve, as recommended by @mikaelrs and the docs:
await new Promise(resolve => setTimeout(resolve, 0));
After doing that, the loading
property was false
, but data
was still undefined
. I discovered that my mock result object was missing a property. Once I added that missing property to the mock result, the data
was populated as expected.
Upvotes: 4
Reputation: 335
What I do to wait for the loading state of the MockedProvider
to pass is to use the wait
function from waait
. This is actually what Apollo
recommends as well.
So in your test you would do:
import React from 'react';
import gql from 'graphql-tag';
import { cleanup } from 'react-testing-library';
import wait from 'waait'
import { customRender } from '../../../test-utils/customRender';
import { EditCategoryContainer } from './Container';
afterEach(() => {
cleanup();
});
const getCategoryMock = {
request: {
query: gql`
query getCategory($id: Int!) {
getCategory(id: $id) {
id
name
active
position
}
}
`,
variables: {
id: 1
}
},
result: {
data: {
getCategory: {
id: 1,
name: 'category',
active: true,
position: 1
}
}
}
};
describe('create edit category module', () => {
test('Rendering correct', async () => {
const { container, debug } = customRender(<EditCategoryContainer />, [
getCategoryMock
]);
await wait(0);
// Your loading state should be false after this, and your component should
// get it's data from apollo for you to do any assertion you would like to
// after this point. To see that the component is rendered with data invoke
// the debug function from react-testing-library after this point
debug();
expect(container).toMatchSnapshot()
});
});
Another solution is to use react-testing-library
s wait
function to wait for an element that would be present after the loading state switches to true.
For instance
describe('create edit category module', () => {
test('Rendering correct', async () => {
const { container, debug, queryByText } = customRender(<EditCategoryContainer />, [
getCategoryMock
]);
await wait(()=> queryByText("Some Data"));
// Your loading state should be false after this, and your component should
// get it's data from apollo for you to do any assertion you would like to
// after this point
expect(container).toMatchSnapshot()
});
});
Upvotes: 6