Server Testing Documentation
This project is maintained by cliffeby
I am a retired civil engineer studying the MEAN stack as an avocation. I’ve found the software development “community” unparallelled in support for all levels of users. When you hit a roadblock, video tutorials, blogs, Stack Overflow, etc. provide a wealth of content. For me, a quick search, a crtl-c/crlt-v and my problem is solved. No other profession offers more to it colleagues. However getting past the HW or sample app has often been a struggle for me. As I navigate that world with my Roch app, I will document some of the “not so sample” issues and questions that arise.
This GitHub page is the first of several planned blogs on my efforts to get beyond HW. I expect that the document will be updated as I learn more about the MEAN Stack.
Cliff Eby - 2017 - updated Aug 2020
In an attempt to learn a little about testing, I tried to write some Mocha tests for my API server in a MEAN stack project. Once I included JWT authorization to the REST routes, I really struggled to get the test framework working. After I abandoned the traditional "ng test" approach (more on that later), I started to ask questions "What should I test?" "Since I control the entire stack, can I adequately test my API on the client side?" "What level of error reporting should my API generate?" and most importantly, "Will my API tests ease front end development – What tradeoffs will I encounter?"
A search for "best practices" for API and/or REST testing produced very little. Articles suggested consistency, comprehensiveness, middleware and documentation, but none addressed it in the context of an authenticated/authorized self-owned MEAN stack.
The following is a guide for the above context. It contains principles and a framework along with some "How to" suggestions.
WHY:There are over 70 HTTP status codes. If you use status codes that are not common, you will force developers to search for your intent.
There are many articles and opinions on the proper use of express-server middleware for catching and reporting errors. With two exceptions, I struggle to see the benefit of detailed status codes and unique messages. The exceptions are:
Score.findById(req.params.id)
.exec(function(err, score){
if (err) {
console.log("Error retrieving score";);
}
else {
if ( !score) {
res.statusCode = 404;
console.log("Not FOUND - get Score");
}
res.json(score);
}});`
None was used for early development. A Test and Dev server were configured. Make sure that your tests (both during test script creation and once complete) do not pollute your server data.
POST
PUT
GET - all
GET - one
DELETE
Behavior |
Tool/Responsibility |
Technique |
Login |
Auth0 |
Client-side login uses Auth0 for authentication |
Roles |
Auth0 |
Using rules in Auth0, users are granted permissions for each endpoint and CRUD action. A role based JWT is issued by Auth0 |
JWT security |
Auth0 Server developer |
Client secret is needed to modify JWT. Must not be made public |
Authorize Routes |
Developer Uses express-jwt, express-jwt-authz, and jwks-rsa |
router.route('/scores')
|
Test user authorization |
POSTMAN and Auth0 Developer to check UnauthorizedError response - JWT Malformed and No Authorization Token |
Login to Auth0 via Postman. See Auth0 API documentation for required header and body. TEST access_token for valid and invalid JWTs. |
User Identification |
POSTMAN and Auth0 Developer to check UnauthorizedError response -Insufficient Scope |
TEST id_token for expected user, role and scopes |
Endpoint unknown |
POSTMAN Developer |
TEST that unrecognized endpoint is handled |
|
||
Known endpoint - POST |
||
a. Is endpoint accessible
b. Is response timely
c. Requested and expected properties
d. Schema
e. Data |
POSTMAN Developer |
TEST unauthorized, authorized, and role/scope status codes and messages
TEST response time TEST response body for properties: required, requested and expected TEST schema for correct types TEST one property for specific data |
Known endpoint - PUT |
||
a. Is endpoint accessible
b. Is response timely
c. Data |
POSTMAN Developer |
TEST unauthorized, authorized, and role/scope status codes and messages. TEST response time TEST not null and one property for specific data update |
Known endpoint - GET all |
||
a. Is endpoint accessible
b. Is response timely
c. Data |
POSTMAN Developer |
TEST unauthorized, authorized, and role/scope status codes and messages
TEST response time TEST for array of objects |
Known endpoint - GET one |
|
|
a. Is endpoint accessible
b. Is response timely
c. Data |
POSTMAN Developer |
TEST unauthorized, authorized, and role/scope status codes and messages. TEST response time TEST body is not null/ID not found |
Known endpoint - DELETE |
|
|
a. Is endpoint accessible
b. Is response timely
c. Data |
POSTMAN Developer |
TEST unauthorized, authorized, and role/scope status codes and messages. TEST response time TEST body is not null/ID not found |
I previously dabbled in POSTMAN, but rarely got beyond GET and DELETE. In trying debug my basic Mocha/JWT tests, I turned to POSTMAN to see header request and response data. The Auth0 Authentication API and Management API documentation and Lars Bilde's video https://www.youtube.com/watch?v=DVMCq8v5b7I gave me the basics. Along the way, I tried some POSTMAN tests and then the test runner. Once I found that you can export the tests to a Newman command line test runner, I abandoned Mocha and dove in.
In general, POSTMAN is giving me all I need. I like that it's easy to break out a single test from a collection and run it. Having the http data response (html or json) readily viewable and a console log made writing the test script easy. My only frustration was remembering to frequently save and backup my work. For me, it seemed easy to overwrite my work.
The following describes my testing approach using POSTMAN and Newman:
My test scripts make use of _postman. _ to allow for test runner iteration by role. These data are stored in POSTMAN's Environments (roch1) that are easily manipulated.
To get JWT access_ and id_ tokens, Auth0 requires the Headers Keys/Values shown below with Content-Type keys set to application/x-www-form-urlencoded.
Prior to the POST, many environmental variables are set and are used by subsequent tests in the collection.
Since this is a POST to Auth0, the only test is to assure that it is successful. Then, JWT access_ and id_ tokens are stored in the postman.setGlobalVariable collection. I chose global variable because these tokens are unreadable and long. It keeps the Environment section readable.
The above POST creates a JWT access_token that allows API access. Setting Authorization in the Header to Bearer followed by the access token, then setting the audience to a unique string defined in Auth0 and changing the Content-type to application/json, is all that is needed. Not shown is that this access_token includes a scope of create:score that matches the server's express router requirement.
router.route("/scores")
.post(jwtCheck, jwtAuthz(["create:score"], options), scoreController.postScore)
Next, the TEST scripts are created. They are basic JavaScript and I use if/else to test for role conditions. Like any testing library, the syntax takes some time to master, but I like that it is concise and all in one location.
The entire Roch collection test can run in POSTMAN or in Newman. Using a file named "data" (json or csv), are defined for each iteration. For example, I change the username and password for each iteration with a pdata.json file:
[{
"username": "admin@roch.com",
"password": "Password"
},
{
"username": "rplayer@roch.com",
"password": "Password"
},
{
"username": "rmember@roch.com",
"password": "Password"
}]
Exporting all or part of the collection creates a json file that can be used as a Newman input to run at the command line.
C:\Users\cliff\WebstormProjects\RochV003\ngApp>newman run server/tests/roch2.postman_collection.json -d server/tests/pdata.json . Alternatively, you can run the collection's iterations in the POSTMAN runner.
Sources
https://derickbailey.com/2014/09/06/proper-error-handling-in-expressjs-route-handlers/
https://www.joyent.com/node-js/production/design/errors
http://blog.restcase.com/rest-api-error-codes-101/
https://kostasbariotis.com/rest-api-error-handling-with-express-js/
https://webapplog.com/intro-to-express-js-parameters-error-handling-and-other-middleware/
http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/
https://www.owasp.org/index.php/REST_Security_Cheat_Sheet
https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/