A lot of our code makes requests to external services. For example,
a crash reporting client, like raven
sends an exception and related information to Sentry.
If we include raven
client, how do we verify that it is setup and configured
correctly, and actually sends the crash information? We do not want to find out
that the system has been running red, yet without any errors getting through!
I typically use a zero-configuration wrapper around a crash reporter, like crash-reporter-middleware or node-sentry-error-reporter. These clients ensure that all errors are actually sent from a Node process, including rejected promises and exceptions from the server middleware. How do I make sure the error is actually sent?
Consider a small example where the client sends an error manually
1 | // example.js |
Somewhere deep inside the Node process a HTTP POST request is fired by the raven
library. We usually do not want to actually make a request, and raven
does not allow
spying on the send. Thus we need a mock server to work as Sentry receiver to verify
that the error is being sent.
Luckily, there are mock server libraries, like nock that make testing such requests a breeze. For example, if we want to confirm that a request is received, we can setup an expectation first, before the request happens
1 | // mock-sentry.js |
The above assumes that we configure raven
with the following
SENTRY_URL=http://aaa:111@localhost/11
. Here is our test code
Two details
To make this unit testing more flexible, we can do the following.
Use the full package name
Instead of loading the package under test using relative path, we should load it using full name
1 | // BAD |
To allow full module name, we should run the test with extra NODE_PATH
folder
1 | NODE_PATH=.. node example.js |
which assumes the typical file structure
1 | projects/ |
By looking one folder up, the Node require
will find node-sentry-error-reporter
folder
and will load just like any other NPM module.
Load mock server code separately
Instead of loading the mock server, and loading the test code from inside the mock code, use the external preload feature available in Node
1 | // BAD |
1 | NODE_PATH=.. node mock-sentry.js |
Here is a better alternative. mock-sentry.js
will NOT know about any other file
1 | // GOOD |
1 | NODE_PATH=.. node -r ./mock-sentry.js mock-sentry.js |
The -r
flag (--require
) preloads a module (note the relative path) before running the file
at the end of the command. You can even preload multiple modules by using the -r
option
multiple times. Other testing tools, like mocha allow using
this flag too; thus setting up mock server responses in unit tests is super simple too.
You can see the testing code in the test folder and how it is called in the package.json.