4
votes

Comment tester une requête GraphQL fournissant un jeton d'authentification avec Apollo Server?

La

Documentation de test sur l'intégration d'Apollo Server montre comment tester requêtes simples utilisant createTestClient:

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

Pour essayer de tester une requête qui nécessite un jeton d'autorisation , j'ai essayé de passer le jwtToken comme champ supplémentaire à l'objet passé à la requête comme ci-dessous:

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

Malheureusement, cela ne fonctionne pas. En essayant de l'exécuter, j'obtiens la réponse suivante:

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

Une idée comment tester correctement les requêtes qui nécessitent un jeton d'autorisation?

En utilisant: p>

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


0 commentaires

3 Réponses :


3
votes

Vous pouvez créer une nouvelle instance de serveur avec un contexte distinct pour vos tests. Quelque chose comme ça (la syntaxe peut ne pas être 100% correcte, mais vous aurez l'idée):

// 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);
  },
});


0 commentaires

2
votes

La solution de Mikael a fonctionné pour moi. Pour développer cela, j'ai pu importer le même ApolloServer que j'utilise dans le fichier principal du serveur app.js, puis écraser la propriété context dans le test pour ajouter le jeton de support requis.

// 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({...})

Ensuite, l'écrasement du contexte dans mon test ressemblait à ceci.

// 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;


4 commentaires

Où placez-vous votre processus d'authentification si votre contexte contient uniquement comment récupérer le jeton où qu'il se trouve?


Cela n'authentifie pas la demande entrante. Le but ici est de définir un en-tête d'autorisation dans la requête que nous envoyons de l'API GraphQL à l'API REST externe (ou à une autre source de données). Dans mon exemple, j'utilise le même jeton de la demande que je reçois et je le transmets dans la demande que j'envoie à l'API REST externe. J'espère que cela aidera à rendre les choses un peu plus claires.


Ma question aurait dû être plus claire, mais vous y avez quand même répondu. Mon point était que si le contexte ne traite que de l'extraction, l'authentification serait dans chaque résolveur, ce qui est pénible. Mais étant donné que vous avez une API externe, je suppose que vous la gérez dans les middlewares de cette API.


cela ne résout pas le problème, il veut passer le jeton dans la requête pour écrire un test d'intégration sans se moquer des données



1
votes

J'ai rencontré le même problème et j'ai trouvé cette bibliothèque:

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

À partir de la documentation: Pourquoi ne pas utiliser apollo-server-testing? Vous ne pouvez pas vraiment écrire de vrais tests d'intégration avec apollo-server-testing, car il ne prend pas en charge les serveurs qui reposent sur l'option context étant une fonction qui utilise l'objet req


0 commentaires