StarpTech / apollo-datasource-http

Optimized JSON HTTP Data Source for Apollo Server
MIT License
73 stars 32 forks source link

Mocking of the comminucation #33

Open kdybicz opened 2 years ago

kdybicz commented 2 years ago

I'm trying to replace apollo-datasource-rest with your library, but I'm struggling with mocking of the external communication:

import { MockAgent, setGlobalDispatcher } from 'undici';

const mockAgent = new MockAgent();
setGlobalDispatcher(mockAgent);
mockAgent.disableNetConnect();
...
const mockPool = mockAgent.get(BASE_URL);
...
mockPool.intercept({ path: '/v1/something', method: 'GET' }).reply(404, '');
...
const api = new MyAPI();
const result = await api.doSomething('aaa', 'bbb');

Above is failing because DataSource is successfully reaching to the unmocked REST resource and gets rejected with HTTP 401. I don't find mocking you use in your tests as best approach and would like to make the undici mocking work with apollo-datasource-http, though I might need some help with that. Any suggestions?

dmateiu commented 2 years ago

@kdybicz I had the very same issue and was able to fix this, after stumbling across another issue in the undici repo, see https://github.com/nodejs/undici/issues/996.

The MockAgent does not intercept Pool requests, instead you need to injection the agent during tests.

For your tests to work, you would therefore need to adapt the constructor on your MyAPI class to accept the mock client as a parameter.

// my-api.data-source.ts

class MyAPI extends HTTPDataSource {
  constructor(pool: Pool) { // <-- Accept Pool here
    super(baseUrl, {
      pool,
    })
  }
}
// my-api.data-source.test.ts

import type { MockClient } from 'undici';
import { MockAgent, setGlobalDispatcher } from 'undici';

const mockAgent = new MockAgent();
setGlobalDispatcher(mockAgent);
mockAgent.disableNetConnect();

const mockPool = mockAgent.get<MockClient>(BASE_URL);
mockPool.intercept({ path: '/v1/something', method: 'GET' }).reply(404, '');

const api = new MyAPI(mockPool); // <-- Inject mock client here

const result = await api.doSomething('aaa', 'bbb');

I hope this solves your problem.

kdybicz commented 2 years ago

@dmateiu Thank You for your reply, looks like you're right and I think this might be a use case example for docs! I till need to sort out ie. if I can ensure proper timeout was set on my request, etc. but this for sure unblocks future work!