Mocks
Sinon
Maybe your software integrates with other APIs, probably it connects to a database, and such resources won’t/shouldn’t be available for testing. For those situations, try sinon.js. There are lots of convenient ways to mock resources and all of those can be found in the documentation, but the one I use the most is replacing my http client request.
import needle from 'needle'; import sinon from 'sinon'; import { FakeNeedle } from './mocks/needle/fake-needle'; sinon.replace(needle, 'request', sinon.fake(new FakeNeedle().request));
In this example, I switched needle‘s request function for a fake one of mine, that will be called unbeknownst to the code. This way I can control exactly what happens during tests with HTTP calls to other APIs.
export class FakeNeedle { private readonly baseRequest: unknown; constructor() { // This is a real request object that I stringified to a JSON this.baseRequest = JSON.parse( fs.readFileSync('test/mocks/needle/request.json').toString()); } // This is the method that will be used instead of the real one public request = (method: NeedleHttpVerbs, url: string, data: BodyData, _options?: NeedleOptions, callback?: NeedleCallback): ReadableStream => { // It looks for a file keyed by the URL and parameters received. const fileName: string = crypto.createHash('md5') .update(url + JSON.stringify(data)).digest('hex') + '.json'; const filePath: string = path.join('test/mocks/needle', url, fileName); // If the file is not found, your test is broken if (!fs.existsSync(filePath)) { console.debug('method: ' + method); console.debug('call ' + url); console.debug('data ' + JSON.stringify(data)); console.debug('path: ' + fileName); process.exit(0); } else { // Based on the URL and parameters, a preset response is returned const body: unknown = JSON.parse(fs.readFileSync(filePath).toString()); const request: NeedleResponse = JSON.parse( JSON.stringify(this.baseRequest)); request.body = body; callback(undefined, request, body); } return undefined; } }
That it! Of course you can also give files a more intuitive name and choose them inside a switch statement, your call!