Skip to content

Commit

Permalink
Merge pull request apollographql#68 from apollostack/more-tests
Browse files Browse the repository at this point in the history
More tests to increase test coverage
  • Loading branch information
helfer authored Jul 29, 2016
2 parents 30da93c + c82201a commit 5b1575d
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 25 deletions.
13 changes: 13 additions & 0 deletions src/integrations/expressApollo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as express from 'express';
import * as bodyParser from 'body-parser';
import { apolloExpress, graphiqlExpress } from './expressApollo';
import testSuite, { Schema, CreateAppOptions } from './integrations.test';
import { expect } from 'chai';
import ApolloOptions from './apolloOptions';

function createApp(options: CreateAppOptions = {}) {
const app = express();
Expand All @@ -17,6 +19,17 @@ function createApp(options: CreateAppOptions = {}) {
return app;
}

describe('expressApollo', () => {
it('throws error if called without schema', function(){
expect(() => apolloExpress(undefined as ApolloOptions)).to.throw('Apollo Server requires options.');
});

it('throws an error if called with more than one argument', function(){
expect(() => (<any>apolloExpress)({}, 'x')).to.throw(
'Apollo Server expects exactly one argument, got 2');
});
});

describe('integration:Express', () => {
testSuite(createApp);
});
2 changes: 1 addition & 1 deletion src/integrations/expressApollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function apolloExpress(options: ApolloOptions | ExpressApolloOptionsFunct

if (arguments.length > 1) {
// TODO: test this
throw new Error(`Apollo Server expects exactly one argument, got ${arguments.length + 1}`);
throw new Error(`Apollo Server expects exactly one argument, got ${arguments.length}`);
}

return async (req: express.Request, res: express.Response, next) => {
Expand Down
123 changes: 114 additions & 9 deletions src/integrations/integrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLError,
BREAK,
} from 'graphql';

// tslint:disable-next-line
Expand All @@ -21,20 +23,35 @@ const QueryType = new GraphQLObjectType({
fields: {
testString: {
type: GraphQLString,
resolve(_, params, context) {
if (context) {
context();
}
resolve() {
return 'it works';
},
},
testContext: {
type: GraphQLString,
resolve(_, args, context) {
return context;
},
},
testRootValue: {
type: GraphQLString,
resolve(rootValue) {
return rootValue;
},
},
testArgument: {
type: GraphQLString,
args: { echo: { type: GraphQLString } },
resolve(root, { echo }) {
return `hello ${echo}`;
},
},
testError: {
type: GraphQLString,
resolve() {
throw new Error('Secret error message');
},
},
},
});

Expand Down Expand Up @@ -137,6 +154,18 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
});
});

it('rejects the request if the method is not POST', () => {
app = createApp({excludeParser: true});
const req = request(app)
.get('/graphql')
.send();
return req.then((res) => {
expect(res.status).to.be.oneOf([404, 405]);
// HAPI doesn't return allow header, so we can't test this.
// return expect(res.headers['allow']).to.equal('POST');
});
});

it('throws an error if POST body is missing', () => {
app = createApp({excludeParser: true});
const req = request(app)
Expand Down Expand Up @@ -292,20 +321,96 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
});

it('passes the context to the resolver', () => {
let results;
const expected = 'it works';
const expected = 'context works';
app = createApp({apolloOptions: {
schema: Schema,
context: () => results = expected,
context: expected,
}});
const req = request(app)
.post('/graphql')
.send({
query: 'query test{ testString }',
query: 'query test{ testContext }',
});
return req.then((res) => {
expect(res.status).to.equal(200);
return expect(results).to.equal(expected);
return expect(res.body.data.testContext).to.equal(expected);
});
});

it('passes the rootValue to the resolver', () => {
const expected = 'it passes rootValue';
app = createApp({apolloOptions: {
schema: Schema,
rootValue: expected,
}});
const req = request(app)
.post('/graphql')
.send({
query: 'query test{ testRootValue }',
});
return req.then((res) => {
expect(res.status).to.equal(200);
return expect(res.body.data.testRootValue).to.equal(expected);
});
});

it('returns errors', () => {
const expected = 'Secret error message';
app = createApp({apolloOptions: {
schema: Schema,
}});
const req = request(app)
.post('/graphql')
.send({
query: 'query test{ testError }',
});
return req.then((res) => {
expect(res.status).to.equal(200);
return expect(res.body.errors[0].message).to.equal(expected);
});
});

it('applies formatError if provided', () => {
const expected = '--blank--';
app = createApp({apolloOptions: {
schema: Schema,
formatError: (err) => ({ message: expected }),
}});
const req = request(app)
.post('/graphql')
.send({
query: 'query test{ testError }',
});
return req.then((res) => {
expect(res.status).to.equal(200);
return expect(res.body.errors[0].message).to.equal(expected);
});
});

it('applies additional validationRules', () => {
const expected = 'AlwaysInvalidRule was really invalid!';
const AlwaysInvalidRule = function (context) {
return {
enter() {
context.reportError(new GraphQLError(
expected
));
return BREAK;
},
};
};
app = createApp({apolloOptions: {
schema: Schema,
validationRules: [AlwaysInvalidRule],
}});
const req = request(app)
.post('/graphql')
.send({
query: 'query test{ testString }',
});
return req.then((res) => {
expect(res.status).to.equal(400);
return expect(res.body.errors[0].message).to.equal(expected);
});
});

Expand Down
13 changes: 13 additions & 0 deletions src/integrations/koaApollo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as koa from 'koa';
import * as koaRouter from 'koa-router';
import * as koaBody from 'koa-bodyparser';
import { apolloKoa, graphiqlKoa } from './koaApollo';
import ApolloOptions from './apolloOptions';
import { expect } from 'chai';

import testSuite, { Schema, CreateAppOptions } from './integrations.test';

Expand All @@ -27,6 +29,17 @@ function destroyApp(app) {
app.close();
}

describe('koaApollo', () => {
it('throws error if called without schema', function(){
expect(() => apolloKoa(undefined as ApolloOptions)).to.throw('Apollo Server requires options.');
});

it('throws an error if called with more than one argument', function(){
expect(() => (<any>apolloKoa)({}, 'x')).to.throw(
'Apollo Server expects exactly one argument, got 2');
});
});

describe('integration:Koa', () => {
testSuite(createApp, destroyApp);
});
8 changes: 1 addition & 7 deletions src/integrations/koaApollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function apolloKoa(options: ApolloOptions | KoaApolloOptionsFunction): Ko
}

if (arguments.length > 1) {
throw new Error(`Apollo Server expects exactly one argument, got ${arguments.length + 1}`);
throw new Error(`Apollo Server expects exactly one argument, got ${arguments.length}`);
}

return async (ctx, next) => {
Expand All @@ -36,12 +36,6 @@ export function apolloKoa(options: ApolloOptions | KoaApolloOptionsFunction): Ko

const formatErrorFn = optionsObject.formatError || graphql.formatError;

if (ctx.method !== 'POST') {
ctx.set('Allow', 'POST');
ctx.status = 405;
return ctx.body = 'Apollo Server supports only POST requests.';
}

if (!ctx.request.body) {
ctx.status = 500;
return ctx.body = 'POST body missing. Did you forget "app.use(koaBody())"?';
Expand Down
26 changes: 18 additions & 8 deletions src/modules/operationStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ const QueryType = new GraphQLObjectType({
fields: {
testString: {
type: GraphQLString,
resolve() {
/*resolve() {
return 'it works';
},
},*/
},
testRootValue: {
type: GraphQLString,
resolve(root) {
/*resolve(root) {
return root + ' works';
},
},*/
},
testContextValue: {
type: GraphQLString,
resolve(root, args, context) {
/*resolve(root, args, context) {
return context + ' works';
},
},*/
},
testArgumentValue: {
type: GraphQLInt,
resolve(root, args, context) {
/*resolve(root, args, context) {
return args['base'] + 5;
},
},*/
args: {
base: { type: new GraphQLNonNull(GraphQLInt) },
},
Expand All @@ -61,6 +61,16 @@ describe('operationStore', () => {
return expect(print(store.get('testquery'))).to.deep.equal(expected);
});

it('can store queries and return them with getMap', () => {
const query = `query testquery{ testString }`;
const query2 = `query testquery2{ testRootValue }`;

const store = new OperationStore(Schema);
store.put(query);
store.put(query2);
return expect(store.getMap().size).to.equal(2);
});

it('throws a parse error if the query is invalid', () => {
const query = `query testquery{ testString`;

Expand Down

0 comments on commit 5b1575d

Please sign in to comment.