I have an app that uses:
react-apollo
apollo-link-state
apollo-cache-persist
apollo-link-error
I ran into a weird issue when I was trying to add a pollInterval to a query. The pollInterval causes an overWrite of the local cache state back to the defaults. I am not sure if this is caused directly by the pollInterval or not, but I have been troubleshooting the issue for some time with no luck.
I made a reproduction of the issue on Github here (https://github.com/deltaskelta/apollo-link-iss-573) with instructions on how to see what is happening. If anyone has any idea what is going on I would really appreciate it!
Thanks
EDIT: the full code that is causing the error is posted below
import { ApolloClient } from "apollo-client";
import { ApolloLink } from "apollo-link";
import { ApolloProvider, graphql } from "react-apollo";
import { CachePersistor } from "apollo-cache-persist";
import { InMemoryCache } from "apollo-cache-inmemory";
import { onError } from "apollo-link-error";
import { withClientState } from "apollo-link-state";
import PropTypes from "prop-types";
import React, { Component } from "react";
import gql from "graphql-tag";
export const resolvers = {
Mutation: {
setErrors: (_, { messages }, { cache }) => {
const data = {
errors: {
__typename: "Errors",
messages
}
};
cache.writeData({ data });
return null;
}
}
};
// create the cache
const cache = new InMemoryCache();
const persistor = new CachePersistor({
cache,
storage: window.localStorage,
debug: true
});
// link to the local state cache
const stateLink = withClientState({
cache,
resolvers,
defaults: {
errors: {
__typename: "Errors",
messages: []
}
}
});
// link to intercept graphql errors and write them to the cache, this is almost like a
// middleware
const errorLink = onError(({ graphQLErrors, networkError }) => {
var messages = []; // make a place to push all errors to
// go through the network errors and graphql errors, push them to the errors array and
// then write those errors to the cache
if (graphQLErrors) {
graphQLErrors.forEach(({ message, path }) => {
messages.push(`Error: msg: ${message}, path: ${path}`);
});
}
if (networkError) {
messages.push(`Error: network: ${networkError}`);
}
const data = {
errors: {
__typename: "Errors",
messages
}
};
cache.writeData({ data });
});
// put both links in the frontend apollo client
const client = new ApolloClient({
cache,
link: ApolloLink.from([stateLink, errorLink]),
connectToDevTools: true
});
client.onResetStore(stateLink.writeDefaults);
class Persistor extends React.Component {
static propTypes = {
children: PropTypes.object,
persistor: PropTypes.object
};
componentDidMount() {
this.props.persistor.restore().then(() => {
console.log("restored");
});
}
render() {
return this.props.children;
}
}
class App extends Component {
render() {
return (
<ApolloProvider client={client}>
<Persistor persistor={persistor}>
<Errors />
</Persistor>
</ApolloProvider>
);
}
}
const RootComponent = ({ errors }) => {
return (
<div>
Hello World
{errors.map(e => <div>{e}</div>)}
</div>
);
};
RootComponent.propTypes = {
errors: PropTypes.array
};
const Errors = graphql(
gql`
query GetErrors {
errors #client {
messages
}
}
`,
{
props: ({ data }) => ({ errors: data.errors.messages }),
options: {
pollInterval: 1000 * 10
}
}
)(RootComponent);
export default App;
// TODO:
//
// - cause an error that is written to the cache
// - make a query to poll the error
Related
I finished coding a React app created using the create-react-app (CSR) but I'm now rewriting this entire app using the Next.js framework for better SEO performance.
While rewriting it I had some hard times figuring out how to properly deal with redux and redux-saga to do the fetching and storing data process.
The main reason to use Next.js in this project is to make use of the getInitialProps method, to fetch the data on the server-side before the first page load happens. But for some reason, I'm not able to "await" for the Redux dispatch to complete and get the fetched data on time.
So what ends up happening is that I dispatch the action to fetch the data, but it doesn't get stored in the redux store on time during the initial server-side page load. But when I change routes using next/link the data comes in, but only on client-side, after the server-side rendering happened.
So it kinda defeats the purpose of using the Next.js.
This new code is very similar to the create-react-app project, with some minor changes to fit the Next.js project requirements.
Here is my code.
./pages/_app.js
import App from 'next/app';
import { Provider } from 'react-redux';
import withRedux from 'next-redux-wrapper';
import withReduxSaga from 'next-redux-saga';
import makeStore from '../store/index';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
}
export default withRedux(makeStore)(MyApp);
./pages/index.jsx:
import React from 'react';
import { useRouter } from 'next/router';
import Layout from '../components/Layout';
import SubNavBarCategories from '../components/Pages/Home/SubNavBarCategory';
import * as BlogActions from '../store/actions/blog/categories';
const Blog = (props) => {
const router = useRouter();
const {
blogCategories,
} = props;
return (
<Layout>
<SubNavBarCategories blogCategories={blogCategories} />
</Layout>
);
};
Blog.getInitialProps = async ({ isServer, store }) => {
await store.execSagaTasks(isServer, (dispatch) => {
dispatch(BlogActions.getRecentCategories(5));
});
console.log('await store:', await store.getState().blog.blogCategories);
//output: await store: { data: [], loading: true, fetched: false, error: false }
//expected something like this:
// await store: { data: ['test1', 'category', 'crypto', 'test4', 'Day trade'] loading: false, fetched: true, error: false }
return {
blogCategories: await store.getState().blog.blogCategories,
};
};
export default Blog;
./store/index.js
import {
createStore,
applyMiddleware,
compose,
} from 'redux';
import createSagaMiddleware, { END } from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas';
const sagaMiddleware = createSagaMiddleware();
const makeStore = (initialState) => {
const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;
const store = createStore(
rootReducer,
initialState,
compose(
composeEnhancers(applyMiddleware(sagaMiddleware)),
),
);
store.runSaga = () => {
if (store.saga) {
return;
}
store.sagaTask = sagaMiddleware.run(rootSaga);
};
store.stopSaga = async () => {
if (!store.saga) {
return;
}
store.dispatch(END);
await store.saga.done;
store.saga = null;
};
store.execSagaTasks = async (isServer, tasks) => {
store.runSaga();
tasks(store.dispatch);
await store.stopSaga();
if (!isServer) {
store.runSaga();
}
};
store.runSaga();
return store;
};
export default makeStore;
./store/actions/blog/blog.js
export function getRecentCategories(number) {
return {
type: 'REQUEST_RECENT_CATEGORIES',
payload: {
number,
},
};
}
./store/reducers/blog/blog.js
import update from 'immutability-helper';
const initialState = {
blogCategories: {
data: [],
loading: false,
fetched: false,
error: false,
},
};
export default function blog(state = initialState, action) {
switch (action.type) {
case 'REQUEST_RECENT_CATEGORIES':
return update(state, {
blogCategories: {
loading: { $set: true },
},
});
case 'SUCCESS_RECENT_CATEGORIES':
console.log('actions:', action.payload.data);
//output: actions: blogCategories [ 'test1', 'category', 'crypto', 'test4', 'Day trade' ]
return update(state, {
blogCategories: {
data: { $set: action.payload.data },
loading: { $set: false },
fetched: { $set: true },
error: { $set: false },
},
});
case 'FAILURE_RECENT_CATEGORIES':
return update(state, {
blogCategories: {
fetched: { $set: true },
error: { $set: true },
},
});
default:
return state;
}
}
./store/sagas/blog/getRecentCategories.js
import {
put,
call,
} from 'redux-saga/effects';
import 'isomorphic-fetch';
async function getRecentCategoriesApi(number) {
const res = await fetch(`http://localhost:5000/blog/get/categories/newest/${number}`, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
});
const data = await res.json();
return data;
}
export default function* asyncGetRecentCategoriesApi(action) {
try {
const response = yield call(getRecentCategoriesApi, action.payload.number);
yield put({ type: 'SUCCESS_RECENT_CATEGORIES', payload: { data: response } });
} catch (err) {
yield put({ type: 'FAILURE_RECENT_CATEGORIES' });
}
}
As you can see this app is a pretty ordinary react redux-saga app. Everything else is working as it should besides this getting data from the backend using redux-saga thing.
Is there any way to make getInitialProps method work with redux and redux-saga as intended?
Have a look at the official Next.js example with redux-saga example.
https://github.com/zeit/next.js/tree/canary/examples/with-redux-saga
I can't make a proper server side.
When I start my server and make a fetch for example http://localhost:3000/last-movie-releases
The first fetch is not waited by toPromise(). But all the other ones I do next are good, server side is then alright.
Just a snippet my code below. I dispatch my redux action in the class constructor. (like everybody does)
store
.runSaga(rootSaga)
.toPromise()
.then(() => {
console.log('sagas complete');
const html = ReactDOMServer.renderToString(jsx);
const css = sheets.toString();
res.send(
renderFullPage(html, css, serialize(store.getState()))
);
})
.catch(e => {
console.log(e.message);
res.status(500).send(e.message);
});
ReactDOMServer.renderToString(jsx);
store.close();
Is it a normal behavior ?
PS : My saga making the fetch I am talking about starts with a fork, then a fork again, and a call. Exactly like in the real-word repo
I am wondering if I missed a return somewhere.
/***********************************************
***************** UPDATE BELOW *****************
***********************************************/
I give you my sagas (there is just 2)
import {
take,
put,
call,
fork,
select,
delay,
all,
takeEvery,
takeLatest
} from 'redux-saga/effects';
import * as api from './api';
import * as actions from '../actions';
// each entity defines 3 creators { request, success, failure }
const { movies, movie } = actions;
function* fetchEntity(entity, apiFn, body) {
yield put(entity.request(body));
const { response, error } = yield call(apiFn, body);
if (response) yield put(entity.success(body, response));
else yield put(entity.failure(body, error));
}
// yeah! we can also bind Generators
export const fetchMovies = fetchEntity.bind(null, movies, api.fetchMovies);
export const fetchMovie = fetchEntity.bind(null, movie, api.fetchMovie);
/******************************************************************************/
/********************************* SAGAS **************************************/
/******************************************************************************/
function* sagaFetchMovies() {
yield call(fetchMovies);
}
function* sagaFetchMovie(movieId) {
yield call(fetchMovie, movieId);
}
/******************************************************************************/
/******************************* WATCHERS *************************************/
/******************************************************************************/
function* watchFetchMovies() {
while (true) {
yield take(actions.FETCH_MOVIES);
yield fork(sagaFetchMovies);
}
}
function* watchFetchMovie() {
while (true) {
const { movieId } = yield take(actions.FETCH_MOVIE);
yield fork(sagaFetchMovie, movieId);
}
}
export default function* root() {
yield all([fork(watchFetchMovies), fork(watchFetchMovie)]);
}
/***********************************************
***************** UPDATE BELOW *****************
***********************************************/
I show you where I dispatch my action ;)
...
class Movie extends Component {
constructor(props) {
super(props);
this.state = { isSlideShowOpened: false };
const movie = props.app.movie.results.filter(e => e.id === Number(props.match.params.movieId));
if (movie.length === 0) {
props.fetchMovie(props.match.params.movieId); // <---- I dispatch here because componentWillMount is deprecated :s
}
}
...
...
class Movies extends PureComponent {
constructor(props) {
super(props);
this.state = {};
if (props.app.movies.results.length === 0) {
props.fetchMovies(); // <---- I dispatch here because componentWillMount is deprecated :s
}
}
...
There is a big caveat with #loadable/component server side rendering lol
#loadable/component forces you to split the code for each of your routes, and eventually use a fallback (spinner when downloading the js bundle)
Let me remind you #loadable/component is the only module on the market able to do split code for server side rendering lol
Well none of your sagas will be waited by #loadable/component. I don't have an alternative, this isn't that bad for google and bing I think...
My react router looks like something like this for example
import React from 'react';
import loadable from '#loadable/component';
import Loading from './Exception/Loading';
const Home = loadable(() => import('./Home/index'), { fallback: <Loading /> });
const Movies = loadable(() => import('./Movies/index'), { fallback: <Loading /> });
const Movie = loadable(() => import('./Movie/index'), { fallback: <Loading /> });
const Slide1 = loadable(() => import('./Slides/Slide1'), { fallback: <Loading /> });
const Forbidden = loadable(() => import('./Exception/403'));
const NoMatch = loadable(() => import('./Exception/404'));
const ServerDown = loadable(() => import('./Exception/500'));
const indexRoutes = [
{
exact: true,
path: '/',
component: Home
},
{
exact: true,
path: '/last-movie-releases',
component: Movies
},
{
path: '/movie-details/:movieId/:slideshow?',
component: Movie
},
{
path: '/slide1',
component: Slide1
},
{ path: '/403', component: Forbidden },
{ path: '/404', component: NoMatch },
{ path: '/500', component: ServerDown },
{ name: 'NoMatch', component: NoMatch }
];
export default indexRoutes;
I am trying to implement react-apollo to store my local states, I can write to them using client.writeData() but when i try to access them, I keep getting errors
I tried following https://github.com/wesbos/Advanced-React/tree/master/finished-application/frontend. I tried implementing apollo-link-state as well but keeps throwing error.
withData.js
import withApollo from "next-with-apollo";
import { ApolloClient } from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
const cache = new InMemoryCache();
function createClient({ headers }) {
return new ApolloClient({
cache,
link: new createHttpLink({
uri: "http://localhost:4000/",
request: operation => {
operation.setContext({
fetchOptions: {
credentials: "same-origin"
},
headers: {
"Content-Type": "application/json"
}
});
}
}),
clientState: {
resolvers: {
Query: {
getLocalData: (_, { text }, { cache }) => {
const query = gql`
query getLocalData {
loading #client
}
`;
const previous = cache.readQuery({ query });
return previous.loading;
}
},
Muatation: {
toggleLoading: (_, { text }, { cache }) => {
const query = gql`
query getLocalData {
loading #client
}
`;
var previous = cache.readQuery({ query });
cache.writeData({ data: { loading: !previous.loading } });
return null;
}
}
},
defaults: {
loading: true,
},
typeDefs: {}
}
});
}
export default withApollo(createClient);
_app.js
import App, { Container } from 'next/app';
import Page from '../components/Page';
import { ApolloProvider } from 'react-apollo';
import withData from '../lib/withData';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
// this exposes the query to the user
pageProps.query = ctx.query;
return { pageProps };
}
render() {
const { Component, apollo, pageProps } = this.props;
return (
<Container>
<ApolloProvider client={apollo}>
<Page>
<Component {...pageProps} />
</Page>
</ApolloProvider>
</Container>
);
}
}
export default withData(MyApp);
I expect to run efficiently
but the actual output is: Could not find "client" in the context of ApolloConsumer. Wrap the root component in an
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.
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-librarys 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()
});
});
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.
I am trying to mock a query #client and I am not getting.
I mocked the query from graphql server correctly and it's working.
import React from 'react';
import renderer from 'react-test-renderer';
import wait from 'waait';
import ExchangeRates from './ExchangeRates';
import { MockedProvider } from 'react-apollo/test-utils';
import { sucessMockrates, errorMockrates } from '../../mocks/exchangeRatesMock';
describe('ExchangeRates', () => {
it('should render rate', async () => {
const component = renderer.create(
<MockedProvider mocks={[sucessMockrates]} addTypename={false}>
<ExchangeRates />
</MockedProvider>
);
await wait(0);
const p = component.root.findByType('p');
expect(p.children).toContain('AED: 3.67');
});
it('should render loading state initially', () => {
const component = renderer.create(
<MockedProvider mocks={[]}>
<ExchangeRates />
</MockedProvider>
);
const tree = component.toJSON();
expect(tree.children).toContain('Loading...');
});
it('should show error UI', async () => {
const component = renderer.create(
<MockedProvider mocks={[errorMockrates]} addTypename={false}>
<ExchangeRates />
</MockedProvider>
);
await wait(0);
const tree = component.toJSON();
expect(tree.children).toContain('Error!');
});
});
I am using the graphql server link from apollo tutorial
But when I tried to test the apollo query with local state I got an error.
My query:
import gql from 'graphql-tag';
export default gql`
query {
allocations #client {
list
}
}
`;
and my apollo client setup:
const cache = new InMemoryCache();
const defaultState = {
allocations: {
__typename: 'Allocations',
list: [],
},
};
const listQuery = gql`
query getAllocations {
allocations #client {
list
}
}
`;
const stateLink = withClientState({
cache,
defaults: defaultState,
resolvers: {
addAllocation: (
_,
{ userName },
{ cache }
) => {
const previousState = cache.readQuery({ query: listQuery });
const { list } = previousState.allocations;
const data = {
...previousState,
allocations: {
...previousState.allocations,
list: [
...list,
{
userName
},
],
},
};
cache.writeQuery({ query: listQuery, data });
return data.allocations;
},
},
},
});
const client = new ApolloClient({
link: ApolloLink.from([
stateLink,
new HttpLink({
uri: 'https://w5xlvm3vzz.lp.gql.zone/graphql',
}),
]),
cache,
});
My test with apollo local state:
import React from 'react';
import renderer from 'react-test-renderer';
import AllocationListPage from './AllocationListPage';
import { MockedProvider } from 'react-apollo/test-utils';
import { sucessMockAllocations } from '../../../mocks/allocationListMock';
describe('AllocationListPage', () => {
it('should render list of allocations', () => {
renderer.create(
<MockedProvider mocks={[sucessMockAllocations]} addTypename={false}>
<AllocationListPage />
</MockedProvider>
);
});
});
The error I got: TypeError:
Cannot destructure property list of 'undefined' or 'null'.
I need to mock the initial state of apollo local state, and I don't know how.
Thanks in advance.
I got setup my apollo link state with this component:
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { ApolloProvider } from 'react-apollo';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import { ApolloClient } from 'apollo-client';
import { stateLink, cache } from '../graphql/stateLink';
import { ApolloLink } from 'apollo-link';
import { SchemaLink } from 'apollo-link-schema';
const setupClient = mocks => {
const typeDefs = `
type Query {
test: String!
}
`;
const schema = makeExecutableSchema({ typeDefs });
addMockFunctionsToSchema({
schema,
mocks,
preserveResolvers: false,
});
return new ApolloClient({
cache,
link: ApolloLink.from([stateLink, new SchemaLink({ schema })]),
});
};
class ApolloLinkStateSetup extends PureComponent {
render() {
return (
<ApolloProvider client={setupClient(this.props.mocks)}>
{this.props.children}
</ApolloProvider>
);
}
}
ApolloLinkStateSetup.defaultProps = {
mocks: {},
};
ApolloLinkStateSetup.propTypes = {
children: PropTypes.object.isRequired,
mocks: PropTypes.object,
};
export default ApolloLinkStateSetup;
You can mock the graphql queries with makeExecutableSchema and addMockFunctionsToSchema from graphql-tools. This mock can be useful to create the front-end side without the back-end side.