当一个组件有多个 useQueries 时,Apollo MockedProvider 不起作用?
Apollo's MockedProvider doenst work when a component has multiple useQuery's?
我有一个简单的 Apollo 设置。在这个 CodeSandbox 示例中,我使用的是 MockedProvider
,但实时的也可以:
https://codesandbox.io/s/winter-glitter-o8ug5?file=/src/App.js:0-1164
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { gql, useQuery, ApolloProvider } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
const client = new ApolloClient({
uri: "https://48p1r2roz4.sse.codesandbox.io",
cache: new InMemoryCache()
});
const EXCHANGE_RATES_1 = gql`
query GetExchangeRates {
rates(currency: "USD") {
rate
}
}
`;
const mocks = [
{
request: {
query: EXCHANGE_RATES_1
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
}
}
];
const MyComponent = () => {
const { data: data1, loading: loading1 } = useQuery(EXCHANGE_RATES_1);
if (loading1) return <p>Loading...</p>;
return (
<div>
<h1>{data1?.rates[0].rate}</h1>
</div>
);
};
const AppMocked = () => {
return (
<MockedProvider addTypename={false} mocks={mocks}>
<MyComponent />
</MockedProvider>
);
};
const AppLive = () => {
return (
<ApolloProvider client={client}>
<MyComponent />
</ApolloProvider>
);
};
export default AppMocked;
我需要在 MyComponent
中添加一个 useQuery
。我知道这是一个奇怪的例子,因为它应该只是一个查询,但它说明了我 运行 遇到的问题。
https://codesandbox.io/s/magical-dewdney-j451d?file=/src/App.js:0-1630
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { gql, useQuery, ApolloProvider } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
const client = new ApolloClient({
uri: "https://48p1r2roz4.sse.codesandbox.io",
cache: new InMemoryCache()
});
const EXCHANGE_RATES_1 = gql`
query GetExchangeRates {
rates(currency: "USD") {
rate
}
}
`;
const EXCHANGE_RATES_2 = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
}
}
`;
const mocks = [
{
request: {
query: EXCHANGE_RATES_1
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
}
},
{
request: {
query: EXCHANGE_RATES_2
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
currency: "YOLO"
}
]
}
}
}
];
const MyComponent = () => {
const { data: data1, loading: loading1 } = useQuery(EXCHANGE_RATES_1);
const { data: data2, loading: loading2 } = useQuery(EXCHANGE_RATES_2);
if (loading1 || loading2) return <p>Loading...</p>;
return (
<div>
<h1>{data1?.rates[0].rate}</h1>
<h2>{data2?.rates[0].currency}</h2>
</div>
);
};
const AppMocked = () => {
return (
<MockedProvider addTypename={false} mocks={mocks}>
<MyComponent />
</MockedProvider>
);
};
const AppLive = () => {
return (
<ApolloProvider client={client}>
<MyComponent />
</ApolloProvider>
);
};
export default AppMocked;
现场版工作正常,但模拟版的 H1 为空。当我注销 data1
时,我可以看到它最初确实有数据,但在随后的渲染中变为 'undefined'
我在文档中看不到任何内容来解释为什么模拟不起作用:https://www.apollographql.com/docs/react/development-testing/testing/
出于某种原因,在您的设置中,查询被调用了不止一次。
这会导致在后台出现“查询不再有模拟响应”错误(请参阅 mockLink.ts),因为每个查询调用都会消耗一个模拟响应。
第一次调用查询时,它 returns 模拟数据,这就是您最初看到它的原因。下一次调用会抛出错误并将数据设置为 undefined
.
我找到了两种解决方法:
选项 1 通过将 fetch-policy
设置为 no-cache
:
禁用 MockedProvider 上的缓存
<MockedProvider
mocks={mocks}
defaultOptions={{
watchQuery: { fetchPolicy: 'no-cache' },
query: { fetchPolicy: 'no-cache' },
}}
>
<MyComponent />
</MockedProvider>
选项 2 通过提供 newData
函数允许多次使用模拟响应:
const mocks = [
{
request: {
query: EXCHANGE_RATES_1
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
},
newData: () => ({
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
})
},
{
request: {
query: EXCHANGE_RATES_2
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
currency: "YOLO"
}
]
}
},
newData: () => ({
data: {
rates: [
{
__typename: "ExchangeRate",
currency: "YOLO"
}
]
}
})
}
];
我有一个简单的 Apollo 设置。在这个 CodeSandbox 示例中,我使用的是 MockedProvider
,但实时的也可以:
https://codesandbox.io/s/winter-glitter-o8ug5?file=/src/App.js:0-1164
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { gql, useQuery, ApolloProvider } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
const client = new ApolloClient({
uri: "https://48p1r2roz4.sse.codesandbox.io",
cache: new InMemoryCache()
});
const EXCHANGE_RATES_1 = gql`
query GetExchangeRates {
rates(currency: "USD") {
rate
}
}
`;
const mocks = [
{
request: {
query: EXCHANGE_RATES_1
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
}
}
];
const MyComponent = () => {
const { data: data1, loading: loading1 } = useQuery(EXCHANGE_RATES_1);
if (loading1) return <p>Loading...</p>;
return (
<div>
<h1>{data1?.rates[0].rate}</h1>
</div>
);
};
const AppMocked = () => {
return (
<MockedProvider addTypename={false} mocks={mocks}>
<MyComponent />
</MockedProvider>
);
};
const AppLive = () => {
return (
<ApolloProvider client={client}>
<MyComponent />
</ApolloProvider>
);
};
export default AppMocked;
我需要在 MyComponent
中添加一个 useQuery
。我知道这是一个奇怪的例子,因为它应该只是一个查询,但它说明了我 运行 遇到的问题。
https://codesandbox.io/s/magical-dewdney-j451d?file=/src/App.js:0-1630
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { gql, useQuery, ApolloProvider } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
const client = new ApolloClient({
uri: "https://48p1r2roz4.sse.codesandbox.io",
cache: new InMemoryCache()
});
const EXCHANGE_RATES_1 = gql`
query GetExchangeRates {
rates(currency: "USD") {
rate
}
}
`;
const EXCHANGE_RATES_2 = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
}
}
`;
const mocks = [
{
request: {
query: EXCHANGE_RATES_1
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
}
},
{
request: {
query: EXCHANGE_RATES_2
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
currency: "YOLO"
}
]
}
}
}
];
const MyComponent = () => {
const { data: data1, loading: loading1 } = useQuery(EXCHANGE_RATES_1);
const { data: data2, loading: loading2 } = useQuery(EXCHANGE_RATES_2);
if (loading1 || loading2) return <p>Loading...</p>;
return (
<div>
<h1>{data1?.rates[0].rate}</h1>
<h2>{data2?.rates[0].currency}</h2>
</div>
);
};
const AppMocked = () => {
return (
<MockedProvider addTypename={false} mocks={mocks}>
<MyComponent />
</MockedProvider>
);
};
const AppLive = () => {
return (
<ApolloProvider client={client}>
<MyComponent />
</ApolloProvider>
);
};
export default AppMocked;
现场版工作正常,但模拟版的 H1 为空。当我注销 data1
时,我可以看到它最初确实有数据,但在随后的渲染中变为 'undefined'
我在文档中看不到任何内容来解释为什么模拟不起作用:https://www.apollographql.com/docs/react/development-testing/testing/
出于某种原因,在您的设置中,查询被调用了不止一次。
这会导致在后台出现“查询不再有模拟响应”错误(请参阅 mockLink.ts),因为每个查询调用都会消耗一个模拟响应。
第一次调用查询时,它 returns 模拟数据,这就是您最初看到它的原因。下一次调用会抛出错误并将数据设置为 undefined
.
我找到了两种解决方法:
选项 1 通过将 fetch-policy
设置为 no-cache
:
<MockedProvider
mocks={mocks}
defaultOptions={{
watchQuery: { fetchPolicy: 'no-cache' },
query: { fetchPolicy: 'no-cache' },
}}
>
<MyComponent />
</MockedProvider>
选项 2 通过提供 newData
函数允许多次使用模拟响应:
const mocks = [
{
request: {
query: EXCHANGE_RATES_1
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
},
newData: () => ({
data: {
rates: [
{
__typename: "ExchangeRate",
rate: "123"
}
]
}
})
},
{
request: {
query: EXCHANGE_RATES_2
},
result: {
data: {
rates: [
{
__typename: "ExchangeRate",
currency: "YOLO"
}
]
}
},
newData: () => ({
data: {
rates: [
{
__typename: "ExchangeRate",
currency: "YOLO"
}
]
}
})
}
];