如何使用Apollo Server测试提供身份验证令牌的GraphQL查询?

时间:2019-02-28 14:39:14

标签: typescript graphql jestjs apollo-server

Apollo Server Integration testing documentation显示了如何使用createTestClient测试简单查询:

const { query } = createTestClient(server);
const res = await query({ query: GET_LAUNCH, variables: { id: 1 } });

在尝试测试需要授权令牌的查询时,我尝试将jwtToken作为额外字段传递给传递给查询的对象,如下所示:

const res = await query({ 
  query: MY_QUERY, 
  http: { headers: { authorization: `Bearer ${jwtToken}` } },
});

不幸的是,这不起作用。尝试运行它时,我得到以下响应:

{
  "http": {
    "headers": {}
  },
  "errors": [{
    "message": "must authenticate",
    "locations": [{
      "line": 2,
      "column": 3
    }],
    "path": ["myQuery"],
    "extensions": {
      "code": "UNAUTHENTICATED"
    }
  }],
  "data": {
    "myQuery": null
  }
}

您知道如何正确测试需要授权令牌的查询吗?

使用:

  "devDependencies": {
    "jest": "^23.6.0",
    "apollo-server-testing": "^2.4.8"
  }

3 个答案:

答案 0 :(得分:2)

Mikael's solution为我工作。为了对此进行扩展,我能够导入我在主app.js服务器文件中使用的同一ApolloServer,然后覆盖测试中的context属性以添加所需的承载令牌。

// apollo-server.js
const { ApolloServer } = require('apollo-server-express');

const resolvers = require('./resolvers');
const typeDefs = require('./schema');

const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => ({ bearerToken: req.headers.authorization }),
});

module.exports = apolloServer;

然后在测试中覆盖上下文如下。

// graphql.test.js
const apolloServer = require('./apollo-server');

apolloServer.context = () => ({ bearerToken: `Bearer <token>` });

const { query } = createTestClient(apolloServer);

const QUERY = gql`
  // ...
`;

const response = await query({ query: QUERY });
expect(response.data).eql({...})

答案 1 :(得分:1)

我遇到了同样的问题,并找到了这个库:

https://github.com/zapier/apollo-server-integration-testing

从文档中: 为什么不使用apollo-server-testing? 您不能真正使用apollo-server-testing编写真正的集成测试,因为它不支持依赖context选项作为使用req对象的函数的服务器

答案 2 :(得分:0)

您可以创建一个具有单独上下文的新服务器实例以进行测试。这样的事情(在语法上可能不是100%正确的,但是您会明白的):

// Create a test user, no need to mess with JWT here, just create a plain object
// that resembles a user in your system.
const testUser = {
  id: 'testId',
  email: 'test@example.com',
};

// Use this for both test servers and real servers
export function getContext(models, viewer) {
  return {
    ...models,
    viewer,
  };
}

// Create test server
const testServer = new ApolloServer({
  typeDefs,
  resolvers,
  context: getContext({}, testUser),
});

const { query } = createTestClient(testServer);

// The actual server (you know better how this looks on your end, but just for
// the concept)
const realServer = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req, res }) => {
    const user = decodeUser(req.headers.authorization);

    return getContext({}, user);
  },
});