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

Commit

Permalink
added inital test coverage for SSR (#75)
Browse files Browse the repository at this point in the history
* added inital test coverage for SSR

* added timeout to ensure ssr doesn't fail

* fix typings definitions

* package bump
  • Loading branch information
James Baxley committed Jun 24, 2016
1 parent d255aa8 commit a4e1646
Show file tree
Hide file tree
Showing 72 changed files with 472 additions and 27,316 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"**/.DS_Store": true,
// "node_modules": true,
"test-lib": true,
"lib": true,
"lib": false,
"coverage": true
}
}
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Expect active development and potentially significant breaking changes in the `0.x` track. We'll try to be diligent about releasing a `1.0` version in a timely fashion (ideally within 1 or 2 months), so that we can take advantage of SemVer to signify breaking changes from that point on.

### v0.3.10

Bug: fixed bug where SSR would fail due to later updates. This should also prevent unmounted components from throwing errors.

### v0.3.9

Feature: provide add `watchQuery` to components via `connect`
Expand Down
12 changes: 12 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
LODASH
*/
declare module 'lodash.isobject' {
import main = require('~lodash/index');
export = main.isObject;
}

declare module 'lodash.isequal' {
import main = require('~lodash/index');
export = main.isEqual;
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-apollo",
"version": "0.3.9",
"version": "0.3.10",
"description": "React data container for Apollo Client",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -47,14 +47,15 @@
"enzyme": "^2.2.0",
"graphql": "^0.5.0",
"gzip-size": "^3.0.0",
"isomorphic-fetch": "^2.2.1",
"istanbul": "^0.4.2",
"jsdom": "^8.3.1",
"minimist": "^1.2.0",
"mocha": "^2.3.3",
"pretty-bytes": "^3.0.1",
"react": "^15.0.1",
"react-addons-test-utils": "^15.0.1",
"react-dom": "^15.0.0",
"react-dom": "^15.1.0",
"redux": "^3.4.0",
"remap-istanbul": "^0.5.1",
"source-map-support": "^0.4.0",
Expand Down
1 change: 0 additions & 1 deletion src/ApolloProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/// <reference path="../typings/main.d.ts" />
/* tslint:disable:no-unused-variable */
import * as React from 'react';
/* tslint:enable:no-unused-variable */
Expand Down
36 changes: 25 additions & 11 deletions src/connect.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/// <reference path="../typings/main.d.ts" />

import {
Component,
Expand Down Expand Up @@ -119,6 +118,7 @@ export default function connect(opts?: ConnectOptions) {
public state: any; // redux state
public props: any; // passed props
public version: number;
public hasMounted: boolean;
private unsubscribeFromStore: Function;

// data storage
Expand Down Expand Up @@ -169,6 +169,10 @@ export default function connect(opts?: ConnectOptions) {
this.bindStoreUpdates();
}

componentDidMount() {
this.hasMounted = true;
}

componentWillReceiveProps(nextProps) {
// we got new props, we need to unsubscribe and re-watch all handles
// with the new data
Expand Down Expand Up @@ -196,6 +200,7 @@ export default function connect(opts?: ConnectOptions) {
this.unsubscribeFromStore();
this.unsubscribeFromStore = null;
}
this.hasMounted = false;
}

bindStoreUpdates(): void {
Expand Down Expand Up @@ -310,8 +315,11 @@ export default function connect(opts?: ConnectOptions) {

this.hasQueryDataChanged = true;

// update state to latest of redux store
this.setState(this.store.getState());
if (this.hasMounted) {
// update state to latest of redux store
this.setState(this.store.getState());
}


return refetchMethod(...args);
};
Expand Down Expand Up @@ -351,8 +359,10 @@ export default function connect(opts?: ConnectOptions) {
stopPolling,
}, data);

// update state to latest of redux store
this.setState(this.store.getState());
if (this.hasMounted) {
// update state to latest of redux store
this.setState(this.store.getState());
}
};

this.queryHandles[key] = handle.subscribe({
Expand Down Expand Up @@ -425,9 +435,11 @@ export default function connect(opts?: ConnectOptions) {

this.hasMutationDataChanged = true;

// update state to latest of redux store
// this forces a render of children
this.setState(store.getState());
if (this.hasMounted) {
// update state to latest of redux store
// this forces a render of children
this.setState(store.getState());
}

return {
errors,
Expand All @@ -452,9 +464,11 @@ export default function connect(opts?: ConnectOptions) {

this.hasMutationDataChanged = true;

// update state to latest of redux store
// this forces a render of children
this.setState(store.getState());
if (this.hasMounted) {
// update state to latest of redux store
// this forces a render of children
this.setState(store.getState());
}

resolve();
})
Expand Down
3 changes: 1 addition & 2 deletions test/ApolloProvider.tsx → test/client/ApolloProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/// <reference path="../typings/main.d.ts" />

import * as React from 'react';
import * as chai from 'chai';
Expand All @@ -14,7 +13,7 @@ const { expect } = chai;

import ApolloClient from 'apollo-client';

import ApolloProvider from '../src/ApolloProvider';
import ApolloProvider from '../../src/ApolloProvider';

interface ChildContext {
store: Object;
Expand Down
11 changes: 4 additions & 7 deletions test/connect/mutations.tsx → test/client/connect/mutations.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
/// <reference path="../../typings/main.d.ts" />

import * as React from 'react';
import * as chai from 'chai';
import { mount } from 'enzyme';
import { createStore, combineReducers, applyMiddleware, ReducersMapObject } from 'redux';
import { connect as ReactReduxConnect } from 'react-redux';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import gql from 'apollo-client/gql';
import assign = require('object-assign');
// import { spy } from 'sinon';

import ApolloClient from 'apollo-client';
Expand All @@ -17,13 +14,13 @@ import chaiEnzyme = require('chai-enzyme');
chai.use(chaiEnzyme()); // Note the invocation at the end
const { expect } = chai;

import mockNetworkInterface from '../mocks/mockNetworkInterface';
import mockNetworkInterface from '../../mocks/mockNetworkInterface';
import {
Passthrough,
ProviderMock,
} from '../mocks/components';
} from '../../mocks/components';

import connect from '../../src/connect';
import connect from '../../../src/connect';

describe('mutations', () => {
it('should bind mutation data to props', () => {
Expand Down
12 changes: 4 additions & 8 deletions test/connect/props.tsx → test/client/connect/props.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
/// <reference path="../../typings/main.d.ts" />

import * as React from 'react';
import * as chai from 'chai';
import { mount } from 'enzyme';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { connect as ReactReduxConnect } from 'react-redux';
import { createStore } from 'redux';
import gql from 'apollo-client/gql';
import assign = require('object-assign');
// import { spy } from 'sinon';

import ApolloClient from 'apollo-client';

Expand All @@ -17,13 +13,13 @@ import chaiEnzyme = require('chai-enzyme');
chai.use(chaiEnzyme()); // Note the invocation at the end
const { expect } = chai;

import mockNetworkInterface from '../mocks/mockNetworkInterface';
import mockNetworkInterface from '../../mocks/mockNetworkInterface';
import {
Passthrough,
ProviderMock,
} from '../mocks/components';
} from '../../mocks/components';

import connect from '../../src/connect';
import connect from '../../../src/connect';

describe('props', () => {
it('should pass `ApolloClient.query` as props.query', () => {
Expand Down
10 changes: 3 additions & 7 deletions test/connect/queries.tsx → test/client/connect/queries.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
/// <reference path="../../typings/main.d.ts" />

import * as React from 'react';
import * as chai from 'chai';
import { mount } from 'enzyme';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { connect as ReactReduxConnect } from 'react-redux';
import gql from 'apollo-client/gql';
import assign = require('object-assign');
// import { spy } from 'sinon';

import ApolloClient from 'apollo-client';

Expand All @@ -17,13 +13,13 @@ import chaiEnzyme = require('chai-enzyme');
chai.use(chaiEnzyme()); // Note the invocation at the end
const { expect } = chai;

import mockNetworkInterface from '../mocks/mockNetworkInterface';
import mockNetworkInterface from '../../mocks/mockNetworkInterface';
import {
Passthrough,
ProviderMock,
} from '../mocks/components';
} from '../../mocks/components';

import connect from '../../src/connect';
import connect from '../../../src/connect';

describe('queries', () => {
it('doesn\'t rerun the query if it doesn\'t change', (done) => {
Expand Down
8 changes: 2 additions & 6 deletions test/connect/redux.tsx → test/client/connect/redux.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
/// <reference path="../../typings/main.d.ts" />

import * as React from 'react';
import * as chai from 'chai';
import { mount } from 'enzyme';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { connect as ReactReduxConnect } from 'react-redux';
import gql from 'apollo-client/gql';
import assign = require('object-assign');
// import { spy } from 'sinon';

import ApolloClient from 'apollo-client';

Expand All @@ -17,13 +14,12 @@ import chaiEnzyme = require('chai-enzyme');
chai.use(chaiEnzyme()); // Note the invocation at the end
const { expect } = chai;

import mockNetworkInterface from '../mocks/mockNetworkInterface';
import {
Passthrough,
ProviderMock,
} from '../mocks/components';
} from '../../mocks/components';

import connect from '../../src/connect';
import connect from '../../../src/connect';

describe('redux integration', () => {
it('should allow mapStateToProps', () => {
Expand Down
1 change: 0 additions & 1 deletion test/mocks/components.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/// <reference path="../../typings/main.d.ts" />

import * as React from 'react';

Expand Down
5 changes: 2 additions & 3 deletions test/mocks/mockNetworkInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
import {
GraphQLResult,
Document,
parse,
print,
} from 'graphql';

Expand Down Expand Up @@ -53,7 +52,7 @@ export class MockNetworkInterface implements NetworkInterface {
public query(request: Request) {
return new Promise((resolve, reject) => {
const parsedRequest: ParsedRequest = {
query: parse(request.query),
query: request.query,
variables: request.variables,
debugName: request.debugName,
};
Expand All @@ -76,7 +75,7 @@ export class MockNetworkInterface implements NetworkInterface {
} else {
resolve(result);
}
}, delay ? delay : 0);
}, delay ? delay : 1);
});
}
}
Expand Down
55 changes: 55 additions & 0 deletions test/server/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as chai from 'chai';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import ApolloClient, { createNetworkInterface } from 'apollo-client';
import { connect, ApolloProvider } from '../../src';
import 'isomorphic-fetch';

// Globally register gql template literal tag
import gql from 'apollo-client/gql';

const { expect } = chai;

const client = new ApolloClient({
networkInterface: createNetworkInterface('https://www.graphqlhub.com/playground')
});

describe('SSR', () => {
it('should render the expected markup', (done) => {
const Element = ({ data }) => {
return <div>{data.loading ? 'loading' : 'loaded'}</div>;
}

const WrappedElement = connect({
mapQueriesToProps: ({ ownProps }) => ({
data: {
query: gql`
query Feed {
currentUser {
login
}
}
`
}
})
})(Element);

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

try {
const data = ReactDOM.renderToString(component);
expect(data).to.match(/loading/);
// We do a timeout to ensure the rest of the application does not fail
// after the render
setTimeout(() => {
done();
}, 1000);
} catch (e) {
done(e);
}
});
});
6 changes: 5 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
"removeComments": true,
"jsx": "react"
},
"include": [
"./global.d.ts"
],
"exclude": [
"typings",
"typings/globals",
"typings/modules",
"node_modules",
"dist",
"lib",
Expand Down
2 changes: 1 addition & 1 deletion typings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"ambientDependencies": {
"globalDependencies": {
"enzyme": "registry:dt/enzyme#1.2.0+20160324040416",
"mocha": "registry:dt/mocha#2.2.5+20160317120654",
"react": "registry:dt/react#0.14.0+20160319053454",
Expand Down
Loading

0 comments on commit a4e1646

Please sign in to comment.