Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Commit

Permalink
Merge pull request #275 from apollostack/ssr-fixes
Browse files Browse the repository at this point in the history
Fix issue with SSR on a mutation wrapping a query
  • Loading branch information
Tom Coleman authored Oct 17, 2016
2 parents 93bf1a2 + 6512735 commit e725114
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Expect active development and potentially significant breaking changes in the `0

### vNext

- Bug: Fix issue with SSR queries running twice when a mutation wraps a query [#274](https://github.com/apollostack/react-apollo/issue/274)


### v0.5.10

- Bug: Fix issue with changing outer props *and not changing variables*, ultimately caused by https://github.com/apollostack/apollo-client/pull/694
Expand Down
5 changes: 2 additions & 3 deletions src/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function withApollo(WrappedComponent) {
}

// Make sure we preserve any custom statics on the original component.
return hoistNonReactStatics(WithApollo, WrappedComponent);
return hoistNonReactStatics(WithApollo, WrappedComponent, { fetchData: true });
};

export interface OperationOption {
Expand Down Expand Up @@ -498,8 +498,7 @@ export default function graphql(
if (operation.type === DocumentType.Query) (GraphQL as any).fetchData = fetchData;

// Make sure we preserve any custom statics on the original component.
return hoistNonReactStatics(GraphQL, WrappedComponent);

return hoistNonReactStatics(GraphQL, WrappedComponent, { fetchData: true });
};

};
95 changes: 95 additions & 0 deletions test/react-web/server/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,61 @@ describe('SSR', () => {
});
});

it('should pick up queries deep in the render tree', () => {

const query = gql`{ currentUser { firstName } }`;
const data = { currentUser: { firstName: 'James' } };
const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data }, delay: 50 }
);
const apolloClient = new ApolloClient({ networkInterface });

const WrappedElement = graphql(query)(({ data }) => (
<div>{data.loading ? 'loading' : data.currentUser.firstName}</div>
));

const Page = () => (<div><span>Hi</span><div><WrappedElement /></div></div>);

const app = (<ApolloProvider client={apolloClient}><Page/></ApolloProvider>);

return getDataFromTree(app)
.then(() => {
const markup = ReactDOM.renderToString(app);
expect(markup).toMatch(/James/);
});
});

it('should handle nested queries that depend on each other', () => {
const idQuery = gql`{ currentUser { id } }`;
const idData = { currentUser: { id: '1234' } };
const userQuery = gql`query getUser($id: String) { user(id: $id) { firstName } }`;
const variables = { id: '1234' };
const userData = { user: { firstName: 'James' } };
const networkInterface = mockNetworkInterface(
{ request: { query: idQuery }, result: { data: idData }, delay: 50 },
{ request: { query: userQuery, variables }, result: { data: userData }, delay: 50 },
);
const apolloClient = new ApolloClient({ networkInterface });

const withId = graphql(idQuery);
const withUser = graphql(userQuery, {
skip: ({ data: { loading } }) => loading,
options: ({ data }) => ({ variables: { id: data.currentUser.id } }),
});
const Component = ({ data }) => (
<div>{data.loading ? 'loading' : data.user.firstName}</div>
);
const WrappedComponent = withId(withUser(Component));

const app = (<ApolloProvider client={apolloClient}><WrappedComponent /></ApolloProvider>);

return getDataFromTree(app)
.then(() => {
const markup = ReactDOM.renderToString(app);
expect(markup).toMatch(/James/);
});
});

it('should correctly skip queries (deprecated)', () => {

const query = gql`{ currentUser { firstName } }`;
Expand Down Expand Up @@ -264,6 +319,46 @@ describe('SSR', () => {
;
});

it('should correctly handle SSR mutations, reverse order', () => {

const query = gql`{ currentUser { firstName } }`;
const data1 = { currentUser: { firstName: 'James' } };

const mutation = gql`mutation { logRoutes { id } }`;
const mutationData= { logRoutes: { id: 'foo' } };

const networkInterface = mockNetworkInterface(
{ request: { query }, result: { data: data1 }, delay: 5 },
{ request: { query: mutation }, result: { data: mutationData }, delay: 5 }
);
const apolloClient = new ApolloClient({ networkInterface });

const withQuery = graphql(query, {
props: ({ ownProps, data }) => {
expect(ownProps.mutate).toBeTruthy();
return {
data,
};
},
});

const withMutation = graphql(mutation);
const Element = (({ data }) => (
<div>{data.loading ? 'loading' : data.currentUser.firstName}</div>
));

const WrappedElement = withMutation(withQuery(Element));

const app = (<ApolloProvider client={apolloClient}><WrappedElement /></ApolloProvider>);

return getDataFromTree(app)
.then(() => {
const markup = ReactDOM.renderToString(app);
expect(markup).toMatch(/James/);
})
;
});

it('should not require `ApolloProvider` to be the root component', () => {

const query = gql`{ currentUser { firstName } }`;
Expand Down
2 changes: 1 addition & 1 deletion typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ declare module 'hoist-non-react-statics' {
*
* Returns the target component.
*/
function hoistNonReactStatics(targetComponent: any, sourceComponent: any): any;
function hoistNonReactStatics(targetComponent: any, sourceComponent: any, customStatics: {[name: string]: boolean}): any;
namespace hoistNonReactStatics {}
export = hoistNonReactStatics;
}
Expand Down

0 comments on commit e725114

Please sign in to comment.