问题描述
我有一个使用 useFragment 钩子的组件,我试图弄清楚如何传入数据并使用@testing-library/react 对其进行测试:
// @flow
import { graphql,useFragment } from 'react-relay/hooks';
import Field from '../../common/fields/Field.react';
import type { MyComponent_user } from './__generated__/MyComponent_user.graphql';
type Props = {
user: MyComponent_user,};
export default ({ user: userFragment }: Props) => {
const user = useFragment(
graphql`
fragment MyComponent_user on UserType
{
id
fullName
userType
details {
user {
id
}
address
city
state
zipCode
country
phone
title
company
}
}
`,userFragment,);
const userDetails = user?.details;
const userHref = '/user?userId=';
return (
<div className="user-container">
{user?.fullName && <Field label="Full Name" value={user.fullName} />}
{user?.userType && (
<Field
label="User Type"
value={user.userType === '1' ? 'Employee' : 'User'}
/>
)}
{userDetails?.address && <Field label="Address" value={userDetails.address} />}
{userDetails?.city && <Field label="City" value={userDetails.city} />}
{userDetails?.state && <Field label="State" value={userDetails.state} />}
{userDetails?.zipCode && <Field label="Zipcode" value={userDetails.zipCode} />}
{userDetails?.country && <Field label="Country" value={userDetails.country} />}
{userDetails?.phone && <Field label="Phone" value={userDetails.phone} />}
{userDetails?.title && <Field label="Title" value={userDetails.title} />}
{userDetails?.company && <Field label="Company" value={userDetails.company} />}
</div>
);
};
我正在尝试编写测试:
import { render,screen } from '@testing-library/react';
import { RelayEnvironmentProvider } from 'react-relay/hooks';
import RelayEnvironment from '../../../../environment';
import MyComponent from '../MyComponent.react';
const props = {
user: {
id: 1,fullName: 'Meek Mill',userType: '0',details: {
address: '294 Oak Street',city: 'Philadelphia',state: 'PA',zipCode: '19019',country: 'US',phone: '555-555-5555',title: 'Owner',company: 'Dream Chasers Records',user: {
id: '237895024906790',},};
describe('when the user type is 0',() => {
it('displays User as the User Type',() => {
render(
<RelayEnvironmentProvider environment={RelayEnvironment}>
<MyComponent {...props} />
</RelayEnvironmentProvider>,);
screen.debug();
});
});
我收到此错误:
Invariant Violation: Relay: Expected to receive an object where `... MyComponent_user` was spread,but the fragment reference was not found`. This is most likely the result of:
- Forgetting to spread ` MyComponent_user` in `useFragment()`'s parent's fragment.
- Conditionally fetching ` MyComponent_user` but unconditionally passing a fragment reference prop to `useFragment()`. If the parent fragment only fetches the fragment conditionally - with e.g. `@include`,`@skip`,or inside a `... on SomeType { }` spread - then the fragment reference will not exist. In this case,pass `null` if the conditions for evaluating the fragment are not met (e.g. if the `@include(if)` value is false.)
12 | console.log('userFragment:',userFragment);
13 | console.log('props:',props);
> 14 | const user = useFragment(
| ^
15 | graphql`
16 | fragment MyComponent_user on UserType {
17 | id
如果在文档中添加一些测试示例就好了。
解决方法
在测试 Relay 框架时,您需要了解几件事。
- 我们需要在 Relay 测试中使用两个主要模块:
-
createMockEnvironment:它提供中继环境接口和模拟层,允许
resolving
、reject
和查询的模拟操作,突变和订阅。 - mockPayloadGenerator:允许您为需要测试的组件生成和维护一组模拟数据。
-
createMockEnvironment:它提供中继环境接口和模拟层,允许
- 根据您希望在测试中涵盖的测试用例数量,您需要提供一组不同的模拟数据并将其传递给
MockPayloadGenerator
。
import { render,cleanup } from '@testing-library/react';
import { MockPayloadGenerator } from 'relay-test-utils';
const DEFAULT_PROPS = {
user: {
id: 1,fullName: 'Meek Mill',userType: '0',details: {
address: '294 Oak Street',city: 'Philadelphia',state: 'PA',zipCode: '19019',country: 'US',phone: '555-555-5555',title: 'Owner',company: 'Dream Chasers Records',user: {
id: '237895024906790',},};
function TestRenderer(): React.Node {
const {node} = useLazyLoadQuery<MyTopLevelComponentTestQuery>(
graphql`
query MyTopLevelComponentTestQuery
@relay_test_operation {
node(id: "TEST_FAKE_USER_ID") {
...MyComponent_user
}
}
`,{},);
return user != null && <MyComponent user={node} />;
}
describe('MyComponent',() => {
let environment = createMockEnvironment();
function renderWithEnvironment(node: React.Node): React.Node {
return (
<RelayEnvironmentProvider environment={environment}>
<Suspense fallback={null}>{node}</Suspense>
</RelayEnvironmentProvider>,);
}
function mockNextOperation(props): void {
// if you use `resolveMostRecentOperation` you don't need to
// have MyTopLevelComponentTestQuery
// environment.mock.resolveMostRecentOperation(operation =>
environment.mock.queueOperationResolver(operation =>
MockPayloadGenerator.generate(operation,{
UserType() {
return {
node: {
...props,};
},}),);
}
beforeEach(() => {
environment = createMockEnvironment();
cleanup();
});
it('when the user type is 0',() => {
mockNextOperation(DEFAULT_PROPS);
const {getByText} = render(
renderWithEnvironment(<TestRenderer />),);
// whatever your logic is to test your component
expect(getByText('User Type: User')).toBeTruthy();
});
it('when the user type is 1',() => {
mockNextOperation(ANOTHER_TEST_PROPS);
const {getByText} = render(
renderWithEnvironment(<TestRenderer />),);
// whatever your logic is to test your component
expect(getByText('User Type: Employee')).toBeTruthy();
});
});