使用 React 测试 useSubscription apollo 挂钩
Testing useSubscription apollo hooks with react
测试 useSubscription
挂钩我发现有点困难,因为该方法 omitted/not 记录在 Apollo docs 中(在撰写本文时)。据推测,应该使用 @apollo/react-testing
中的 <MockedProvider />
来模拟它,就像 link.
中给出的示例中的突变一样
正在测试我正在处理的订阅的加载状态:
分量:
const GET_RUNNING_DATA_SUBSCRIPTION = gql`
subscription OnLastPowerUpdate {
onLastPowerUpdate {
result1,
result2,
}
}
`;
const Dashboard: React.FC<RouteComponentProps & Props> = props => {
const userHasProduct = !!props.user.serialNumber;
const [startGetRunningData] = useMutation(START_GET_RUNNING_DATA);
const [stopGetRunningData] = useMutation(STOP_GET_RUNNING_DATA);
useEffect(() => {
startGetRunningData({
variables: { serialNumber: props.user.serialNumber },
});
return () => {
stopGetRunningData();
};
}, [startGetRunningData, stopGetRunningData, props]);
const SubscriptionData = (): any => {
const { data, loading } = useSubscription(GET_RUNNING_DATA_SUBSCRIPTION);
if (loading) {
return <Heading>Data loading...</Heading>;
}
const metrics = [];
if (data) {
console.log('DATA NEVER CALLED IN TEST!');
}
return metrics;
};
if (!userHasProduct) {
return <Redirect to="/enter-serial" />;
}
return (
<>
<Header />
<PageContainer size="midi">
<Panel>
<SubscriptionData />
</Panel>
</PageContainer>
</>
);
};
并成功测试订阅的加载状态:
import React from 'react';
import thunk from 'redux-thunk';
import { createMemoryHistory } from 'history';
import { create } from 'react-test-renderer';
import { Router } from 'react-router-dom';
import wait from 'waait';
import { MockedProvider } from '@apollo/react-testing';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import Dashboard from './Dashboard';
import {
START_GET_RUNNING_DATA,
STOP_GET_RUNNING_DATA,
GET_RUNNING_DATA_SUBSCRIPTION,
} from './queries';
const mockStore = configureMockStore([thunk]);
const serialNumber = 'AL3286wefnnsf';
describe('Dashboard page', () => {
let store: any;
const fakeHistory = createMemoryHistory();
const mocks = [
{
request: {
query: START_GET_RUNNING_DATA,
variables: {
serialNumber,
},
},
result: {
data: {
startFetchingRunningData: {
startedFetch: true,
},
},
},
},
{
request: {
query: GET_RUNNING_DATA_SUBSCRIPTION,
},
result: {
data: {
onLastPowerUpdate: {
result1: 'string',
result2: 'string'
},
},
},
},
{
request: {
query: STOP_GET_RUNNING_DATA,
},
result: {
data: {
startFetchingRunningData: {
startedFetch: false,
},
},
},
},
];
afterEach(() => {
jest.resetAllMocks();
});
describe('when initialising', () => {
beforeEach(() => {
store = mockStore({
user: {
serialNumber,
token: 'some.token.yeah',
hydrated: true,
},
});
store.dispatch = jest.fn();
});
it('should show a loading state', async () => {
const component = create(
<Provider store={store}>
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={fakeHistory}>
<Dashboard />
</Router>
</MockedProvider>
</Provider>,
);
expect(component.root.findAllByType(Heading)[0].props.children).toBe(
'Data loading...',
);
});
});
});
添加另一个测试以等待数据从传入的模拟中解析出来,按照上一个示例from the docs 测试 useMutation 的说明,您必须等待它。
测试失败:
it('should run the data', async () => {
const component = create(
<Provider store={store}>
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={fakeHistory}>
<Dashboard />
</Router>
</MockedProvider>
</Provider>,
);
await wait(0);
});
错误测试抛出:
No more mocked responses for the query: subscription OnLastPowerUpdate {
依赖关系:
"@apollo/react-common": "^3.1.3",
"@apollo/react-hooks": "^3.1.3",
"@apollo/react-testing": "^3.1.3",
我已经尝试过的事情:
- 反应测试渲染器/酶/@testing-library/react
- awaiting next tick
- initialising the client 测试不同
Github 回购示例:
https://github.com/harrylincoln/apollo-subs-testing-issue
有人能帮忙吗?
我在这里看到的问题是您在 Dashboard
组件内声明了 SubscriptionData
组件,因此下次 Dashboard
组件重新呈现时,SubscriptionData
组件将被重新创建,您将看到错误消息:
No more mocked responses for the query: subscription OnLastPowerUpdate
我建议您将 SubscriptionData
组件从 Dashboard
组件中取出,这样它只会被创建一次
const SubscriptionData = (): any => {
const { data, loading } = useSubscription(GET_RUNNING_DATA_SUBSCRIPTION);
if (loading) {
return <Heading>Data loading...</Heading>;
}
const metrics = [];
if (data) {
console.log('DATA NEVER CALLED IN TEST!');
}
return metrics;
};
const Dashboard: React.FC<RouteComponentProps & Props> = props => {
const userHasProduct = !!props.user.serialNumber;
const [startGetRunningData] = useMutation(START_GET_RUNNING_DATA);
const [stopGetRunningData] = useMutation(STOP_GET_RUNNING_DATA);
useEffect(() => {
startGetRunningData({
variables: { serialNumber: props.user.serialNumber },
});
return () => {
stopGetRunningData();
};
}, [startGetRunningData, stopGetRunningData, props]);
if (!userHasProduct) {
return <Redirect to="/enter-serial" />;
}
return (
<>
<Header />
<PageContainer size="midi">
<Panel>
<SubscriptionData />
</Panel>
</PageContainer>
</>
);
};
对于测试,您可以尝试这样的操作:
let component;
it('should show a loading state', async () => {
component = create(
<Provider store={store}>
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={fakeHistory}>
<Dashboard />
</Router>
</MockedProvider>
</Provider>,
);
expect(component.root.findAllByType(Heading)[0].props.children).toBe(
'Data loading...',
);
await wait(0);
});
it('should run the data', async () => {
expect(
// another test here
component.root...
).toBe();
});
测试 useSubscription
挂钩我发现有点困难,因为该方法 omitted/not 记录在 Apollo docs 中(在撰写本文时)。据推测,应该使用 @apollo/react-testing
中的 <MockedProvider />
来模拟它,就像 link.
正在测试我正在处理的订阅的加载状态:
分量:
const GET_RUNNING_DATA_SUBSCRIPTION = gql`
subscription OnLastPowerUpdate {
onLastPowerUpdate {
result1,
result2,
}
}
`;
const Dashboard: React.FC<RouteComponentProps & Props> = props => {
const userHasProduct = !!props.user.serialNumber;
const [startGetRunningData] = useMutation(START_GET_RUNNING_DATA);
const [stopGetRunningData] = useMutation(STOP_GET_RUNNING_DATA);
useEffect(() => {
startGetRunningData({
variables: { serialNumber: props.user.serialNumber },
});
return () => {
stopGetRunningData();
};
}, [startGetRunningData, stopGetRunningData, props]);
const SubscriptionData = (): any => {
const { data, loading } = useSubscription(GET_RUNNING_DATA_SUBSCRIPTION);
if (loading) {
return <Heading>Data loading...</Heading>;
}
const metrics = [];
if (data) {
console.log('DATA NEVER CALLED IN TEST!');
}
return metrics;
};
if (!userHasProduct) {
return <Redirect to="/enter-serial" />;
}
return (
<>
<Header />
<PageContainer size="midi">
<Panel>
<SubscriptionData />
</Panel>
</PageContainer>
</>
);
};
并成功测试订阅的加载状态:
import React from 'react';
import thunk from 'redux-thunk';
import { createMemoryHistory } from 'history';
import { create } from 'react-test-renderer';
import { Router } from 'react-router-dom';
import wait from 'waait';
import { MockedProvider } from '@apollo/react-testing';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import Dashboard from './Dashboard';
import {
START_GET_RUNNING_DATA,
STOP_GET_RUNNING_DATA,
GET_RUNNING_DATA_SUBSCRIPTION,
} from './queries';
const mockStore = configureMockStore([thunk]);
const serialNumber = 'AL3286wefnnsf';
describe('Dashboard page', () => {
let store: any;
const fakeHistory = createMemoryHistory();
const mocks = [
{
request: {
query: START_GET_RUNNING_DATA,
variables: {
serialNumber,
},
},
result: {
data: {
startFetchingRunningData: {
startedFetch: true,
},
},
},
},
{
request: {
query: GET_RUNNING_DATA_SUBSCRIPTION,
},
result: {
data: {
onLastPowerUpdate: {
result1: 'string',
result2: 'string'
},
},
},
},
{
request: {
query: STOP_GET_RUNNING_DATA,
},
result: {
data: {
startFetchingRunningData: {
startedFetch: false,
},
},
},
},
];
afterEach(() => {
jest.resetAllMocks();
});
describe('when initialising', () => {
beforeEach(() => {
store = mockStore({
user: {
serialNumber,
token: 'some.token.yeah',
hydrated: true,
},
});
store.dispatch = jest.fn();
});
it('should show a loading state', async () => {
const component = create(
<Provider store={store}>
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={fakeHistory}>
<Dashboard />
</Router>
</MockedProvider>
</Provider>,
);
expect(component.root.findAllByType(Heading)[0].props.children).toBe(
'Data loading...',
);
});
});
});
添加另一个测试以等待数据从传入的模拟中解析出来,按照上一个示例from the docs 测试 useMutation 的说明,您必须等待它。
测试失败:
it('should run the data', async () => {
const component = create(
<Provider store={store}>
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={fakeHistory}>
<Dashboard />
</Router>
</MockedProvider>
</Provider>,
);
await wait(0);
});
错误测试抛出:
No more mocked responses for the query: subscription OnLastPowerUpdate {
依赖关系:
"@apollo/react-common": "^3.1.3",
"@apollo/react-hooks": "^3.1.3",
"@apollo/react-testing": "^3.1.3",
我已经尝试过的事情:
- 反应测试渲染器/酶/@testing-library/react
- awaiting next tick
- initialising the client 测试不同
Github 回购示例:
https://github.com/harrylincoln/apollo-subs-testing-issue
有人能帮忙吗?
我在这里看到的问题是您在 Dashboard
组件内声明了 SubscriptionData
组件,因此下次 Dashboard
组件重新呈现时,SubscriptionData
组件将被重新创建,您将看到错误消息:
No more mocked responses for the query: subscription OnLastPowerUpdate
我建议您将 SubscriptionData
组件从 Dashboard
组件中取出,这样它只会被创建一次
const SubscriptionData = (): any => {
const { data, loading } = useSubscription(GET_RUNNING_DATA_SUBSCRIPTION);
if (loading) {
return <Heading>Data loading...</Heading>;
}
const metrics = [];
if (data) {
console.log('DATA NEVER CALLED IN TEST!');
}
return metrics;
};
const Dashboard: React.FC<RouteComponentProps & Props> = props => {
const userHasProduct = !!props.user.serialNumber;
const [startGetRunningData] = useMutation(START_GET_RUNNING_DATA);
const [stopGetRunningData] = useMutation(STOP_GET_RUNNING_DATA);
useEffect(() => {
startGetRunningData({
variables: { serialNumber: props.user.serialNumber },
});
return () => {
stopGetRunningData();
};
}, [startGetRunningData, stopGetRunningData, props]);
if (!userHasProduct) {
return <Redirect to="/enter-serial" />;
}
return (
<>
<Header />
<PageContainer size="midi">
<Panel>
<SubscriptionData />
</Panel>
</PageContainer>
</>
);
};
对于测试,您可以尝试这样的操作:
let component;
it('should show a loading state', async () => {
component = create(
<Provider store={store}>
<MockedProvider mocks={mocks} addTypename={false}>
<Router history={fakeHistory}>
<Dashboard />
</Router>
</MockedProvider>
</Provider>,
);
expect(component.root.findAllByType(Heading)[0].props.children).toBe(
'Data loading...',
);
await wait(0);
});
it('should run the data', async () => {
expect(
// another test here
component.root...
).toBe();
});