diff --git a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts index 819245d8..950fca7a 100644 --- a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts +++ b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts @@ -690,136 +690,194 @@ export function testApolloServer( expect(formatError).toHaveBeenCalledTimes(1); }); - it('defers context eval with thunk until after options creation', async () => { - const uniqueContext = { key: 'major' }; + describe('context field', () => { const typeDefs = gql` type Query { hello: String } `; + const resolvers = { Query: { - hello: (_parent, _args, context) => { - expect(context).toEqual(Promise.resolve(uniqueContext)); - return 'hi'; - }, + hello: () => 'hi', }, }; - const spy = jest.fn(() => ({})); - const { url: uri } = await createApolloServer({ - typeDefs, - resolvers, - context: spy, - }); - const apolloFetch = createApolloFetch({ uri }); - - expect(spy).not.toBeCalled(); - - await apolloFetch({ query: '{hello}' }); - expect(spy).toHaveBeenCalledTimes(1); - await apolloFetch({ query: '{hello}' }); - expect(spy).toHaveBeenCalledTimes(2); - }); - - it('allows context to be async function', async () => { - const uniqueContext = { key: 'major' }; - const spy = jest.fn(() => 'hi'); - const typeDefs = gql` - type Query { - hello: String - } - `; - const resolvers = { - Query: { - hello: (_parent, _args, context) => { - expect(context.key).toEqual('major'); - return spy(); + it('defers context eval with thunk until after options creation', async () => { + const uniqueContext = { key: 'major' }; + const typeDefs = gql` + type Query { + hello: String + } + `; + const resolvers = { + Query: { + hello: (_parent, _args, context) => { + expect(context).toEqual(Promise.resolve(uniqueContext)); + return 'hi'; + }, }, - }, - }; - const { url: uri } = await createApolloServer({ - typeDefs, - resolvers, - context: async () => uniqueContext, + }; + const spy = jest.fn(() => ({})); + const { url: uri } = await createApolloServer({ + typeDefs, + resolvers, + context: spy, + }); + + const apolloFetch = createApolloFetch({ uri }); + + expect(spy).not.toBeCalled(); + + await apolloFetch({ query: '{hello}' }); + expect(spy).toHaveBeenCalledTimes(1); + await apolloFetch({ query: '{hello}' }); + expect(spy).toHaveBeenCalledTimes(2); }); - const apolloFetch = createApolloFetch({ uri }); - - expect(spy).not.toBeCalled(); - await apolloFetch({ query: '{hello}' }); - expect(spy).toHaveBeenCalledTimes(1); - }); - - it('clones the context for every request', async () => { - const uniqueContext = { key: 'major' }; - const spy = jest.fn(() => 'hi'); - const typeDefs = gql` - type Query { - hello: String - } - `; - const resolvers = { - Query: { - hello: (_parent, _args, context) => { - expect(context.key).toEqual('major'); - context.key = 'minor'; - return spy(); + it('clones the context for every request', async () => { + const uniqueContext = { key: 'major' }; + const spy = jest.fn(() => 'hi'); + const typeDefs = gql` + type Query { + hello: String + } + `; + const resolvers = { + Query: { + hello: (_parent, _args, context) => { + expect(context.key).toEqual('major'); + context.key = 'minor'; + return spy(); + }, }, - }, - }; - const { url: uri } = await createApolloServer({ - typeDefs, - resolvers, - context: uniqueContext, + }; + const { url: uri } = await createApolloServer({ + typeDefs, + resolvers, + context: uniqueContext, + }); + + const apolloFetch = createApolloFetch({ uri }); + + expect(spy).not.toBeCalled(); + + await apolloFetch({ query: '{hello}' }); + expect(spy).toHaveBeenCalledTimes(1); + await apolloFetch({ query: '{hello}' }); + expect(spy).toHaveBeenCalledTimes(2); }); - const apolloFetch = createApolloFetch({ uri }); + describe('as a function', () => { + it('can accept and return `req`', async () => { + expect( + await createApolloServer({ + typeDefs, + resolvers, + context: ({ req }) => ({ req }), + }), + ).not.toThrow; + }); - expect(spy).not.toBeCalled(); + it('can accept nothing and return an empty object', async () => { + expect( + await createApolloServer({ + typeDefs, + resolvers, + context: () => ({}), + }), + ).not.toThrow; + }); - await apolloFetch({ query: '{hello}' }); - expect(spy).toHaveBeenCalledTimes(1); - await apolloFetch({ query: '{hello}' }); - expect(spy).toHaveBeenCalledTimes(2); - }); + it('can be an async function', async () => { + const uniqueContext = { key: 'major' }; + const spy = jest.fn(() => 'hi'); + const typeDefs = gql` + type Query { + hello: String + } + `; + const resolvers = { + Query: { + hello: (_parent, _args, context) => { + expect(context.key).toEqual('major'); + return spy(); + }, + }, + }; + const { url: uri } = await createApolloServer({ + typeDefs, + resolvers, + context: async () => uniqueContext, + }); - it('returns thrown context error as a valid graphql result', async () => { - const nodeEnv = process.env.NODE_ENV; - delete process.env.NODE_ENV; - const typeDefs = gql` - type Query { - hello: String - } - `; - const resolvers = { - Query: { - hello: () => { - throw Error('never get here'); - }, - }, - }; - const { url: uri } = await createApolloServer({ - typeDefs, - resolvers, - context: () => { - throw new AuthenticationError('valid result'); - }, + const apolloFetch = createApolloFetch({ uri }); + + expect(spy).not.toBeCalled(); + await apolloFetch({ query: '{hello}' }); + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('returns thrown context error as a valid graphql result', async () => { + const nodeEnv = process.env.NODE_ENV; + delete process.env.NODE_ENV; + const typeDefs = gql` + type Query { + hello: String + } + `; + const resolvers = { + Query: { + hello: () => { + throw Error('never get here'); + }, + }, + }; + const { url: uri } = await createApolloServer({ + typeDefs, + resolvers, + context: () => { + throw new AuthenticationError('valid result'); + }, + }); + + const apolloFetch = createApolloFetch({ uri }); + + const result = await apolloFetch({ query: '{hello}' }); + expect(result.errors.length).toEqual(1); + expect(result.data).toBeUndefined(); + + const e = result.errors[0]; + expect(e.message).toMatch('valid result'); + expect(e.extensions).toBeDefined(); + expect(e.extensions.code).toEqual('UNAUTHENTICATED'); + expect(e.extensions.exception.stacktrace).toBeDefined(); + + process.env.NODE_ENV = nodeEnv; + }); }); - const apolloFetch = createApolloFetch({ uri }); + describe('as an object', () => { + it('can be an empty object', async () => { + expect( + await createApolloServer({ + typeDefs, + resolvers, + context: {}, + }), + ).not.toThrow; + }); - const result = await apolloFetch({ query: '{hello}' }); - expect(result.errors.length).toEqual(1); - expect(result.data).toBeUndefined(); - - const e = result.errors[0]; - expect(e.message).toMatch('valid result'); - expect(e.extensions).toBeDefined(); - expect(e.extensions.code).toEqual('UNAUTHENTICATED'); - expect(e.extensions.exception.stacktrace).toBeDefined(); - - process.env.NODE_ENV = nodeEnv; + it('can contain arbitrary values', async () => { + expect( + await createApolloServer({ + typeDefs, + resolvers, + context: { value: 'arbitrary' }, + }), + ).not.toThrow; + }); + }); }); it('propogates error codes in production', async () => { diff --git a/packages/apollo-server/src/__tests__/index.test.ts b/packages/apollo-server/src/__tests__/index.test.ts index 0d739c2b..91eac79b 100644 --- a/packages/apollo-server/src/__tests__/index.test.ts +++ b/packages/apollo-server/src/__tests__/index.test.ts @@ -25,6 +25,10 @@ describe('apollo-server', () => { expect(() => new ApolloServer({ typeDefs, mocks: true })).not.toThrow; }); + // These tests are duplicates of ones in apollo-server-integration-testsuite + // We don't actually expect Jest to do much here, the purpose of these + // tests is to make sure our typings are correct, and to trigger a + // compile error if they aren't describe('context field', () => { describe('as a function', () => { it('can accept and return `req`', () => {