Get headers with executeOperation on Apollo Server (apollo-server) for integrations tests

Viewed 1840

Since the deprecation of apollo-server-testing I am using the new way of doing integration tests with apollo-server (included in apollo-server 2.25.0). From the mutation signin I set my refresh token in the OutgoingMessage header's (in 'Set-Cookie').

Simplified resolver

    @Mutation(() => RefreshTokenOutput)
    async refreshToken(@Ctx() { response, contextRefreshToken }: Context): Promise<RefreshTokenOutput> {
        if (contextRefreshToken) {
            const { accessToken, refreshToken } = await this.authService.refreshToken(contextRefreshToken);
            response.setHeader(
                'Set-Cookie',
                cookie.serialize('refreshToken', refreshToken, {
                    httpOnly: true,
                    maxAge: maxAge,
                    secure: true,
                })
            );
            return { accessToken: accessToken };
        } else {
            throw new AuthenticationError();
        }
    }

Test case

            // given:
            const { user, clearPassword } = await userLoader.createUser16c();
            const input = new UserSigninInput();
            input.email = user.email;
            input.password = clearPassword;

            const MUTATE_signin = gql`
                mutation signin($userInput: UserSigninInput!) {
                    signin(input: $userInput) {
                        accessToken
                    }
                }
            `;

            // when:
            const res = await server.executeOperation(
                { query: MUTATE_signin, variables: { userInput: input }, operationName: 'signin' },
                buildContext(user)
            );

I'm trying to test if this token is correctly set and well formed. Did you have any idea on how I can access this header with executeOperation ?

3 Answers

I was able to set headers like this:

const res = await apolloServer.executeOperation({ query: chicken, variables: { id: 1 } }, {req: {headers: 'Authorization sdf'}});

server.executeOperation calls processGraphQLRequest

and processGraphQLRequest return type is GraphQLResponse

export interface GraphQLResponse {
  data?: Record<string, any> | null;
  errors?: ReadonlyArray<GraphQLFormattedError>;
  extensions?: Record<string, any>;
  http?: Pick<Response, 'headers'> & Partial<Pick<Mutable<Response>, 'status'>>;
}

I'm not sure, but i think headers in GraphQLResponse.http

you can find call structure in github repo.

https://github.com/apollographql/apollo-server/blob/6b9c2a0f1932e6d8fb94a8662cc1da24980aec6f/packages/apollo-server-core/src/requestPipeline.ts#L126

Apollo defines executeOperation as:

  public async executeOperation(
    request: Omit<GraphQLRequest, 'query'> & {
      query?: string | DocumentNode;
    },
    integrationContextArgument?: ContextFunctionParams,
  ) {

integrationContextArgument is optional and ContextFunctionParams is just an alias to any. As mentioned in an answer above, any context JSON passed to the executeOperation function will be sent to Apollo's processGraphQLRequest() function

graphQLServerOptions() function processes that JSON. For more advanced scenarios, it seems that a context resolver function, not just JSON context data, can be passed in using the context field

Reference: https://github.com/apollographql/apollo-server/blob/e9ae0f28d11d2fdfc5abd5048c85acf70de21592/packages/apollo-server-core/src/ApolloServer.ts#L1014

Related