Документация по тестированию интеграции с сервером Apollo показывает, как тестировать простые запросы с помощью 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"
}






Вы можете создать новый экземпляр сервера с отдельным контекстом для своих тестов. Что-то вроде этого (может быть, не на 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: '[email protected]',
};
// 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);
},
});
Решение Микаэля у меня сработал. Чтобы расширить это, я смог импортировать тот же самый ApolloServer, который я использую, в основной файл сервера app.js, а затем перезаписать свойство контекста в тесте, чтобы добавить требуемый токен носителя.
// 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({...})
Это не аутентифицирует входящий запрос. Цель здесь — установить заголовок авторизации в запросе, который мы отправляем из GraphQL API во внешний REST API (или другой источник данных). В моем примере я использую тот же токен из запроса, который я получаю, и передаю его в запросе, который я отправляю во внешний REST API. Я надеюсь, что это поможет сделать это немного более ясным.
Мой вопрос должен был быть более ясным, но вы все равно ответили на него. Моя точка зрения заключалась в том, что если контекст имеет дело только с извлечением, аутентификация будет в каждом распознавателе, что является проблемой. Но учитывая, что у вас есть внешний API, я предполагаю, что вы имеете дело с ним в промежуточных слоях этого API.
это не решает проблему, он хочет передать токен в запросе на написание интеграционного теста без издевательства над данными
Я столкнулся с той же проблемой и нашел эту библиотеку:
https://github.com/zapier/apollo-server-integration-testing
Из документов: Почему бы не использовать тестирование сервера apollo? Вы не можете написать настоящие интеграционные тесты с помощью apollo-server-testing, потому что он не поддерживает серверы, которые полагаются на опцию контекста, являющуюся функцией, которая использует объект req.
Куда вы поместите свой процесс аутентификации, если ваш контекст содержит только то, как получить токен, где бы он ни находился?