Mocha / Chai testing best practices with a database

I’m working through the Information Security/Quality Assurance curriculum and have some questions about best practices regarding unit/functional tests.

It seems the paradigm is that each test should be self-contained and not rely on any previous test. In most of the projects, these tests cover interacting with a database.

In order for a GET function interacting with a database to be properly tested, a document must already exist in the database. However, the project assignments split up the tests (e.g. a set of GET tests, a set of POST tests, etc).

Should each individual test perform multiple database actions (i.e. to test a GET function, first perform a POST, then a GET, then a DELETE)? It seems redundant to have a GET test and then a separate POST test and a separate DELETE test if the first GET test requires all 3 functions in order to be self-contained and not rely on any previous test.

Right now I’m trying to keep the tests separate to complete the assignment and so the tests are extremely redundant; what is the best practice for a real world situation?

Another question regarding the testing frameworks is when dealing with external APIs which communicate over the internet and thus have latency delays and timeouts and ‘spam’ rejections. Most of these challenges (if following the tutorials) would have us use a MongoDB instance hosted on mLab, and so far I haven’t had a problem with them, but with other external APIs. The 4th Information Security/Quality Assurance project requires getting stock prices, and recommends an API (Google Finance) that no longer exists. I’ve used Alpha Vantage for other projects and it works fine for this project, however their API only allows so many calls within a certain time period. I’m completing the 5 functional tests for the challenge, and they all pass by themselves, but they fail when run together because the external API is rejecting my request based on call volume.

What is the proper solution to this, both for the assignment and for real world purposes? Set timeouts? Less functional tests? Accept that its an uncontrollable externality and move on?

One of the features of Mocha specifically is that tests are run serially. Would it be bad practice then to make a suite of tests for a specific API endpoint that test database functions logically in order? For example, for the anonymous message board, a suite of tests designed for the ‘/api/threads/:board’ endpoint, where the tests are first a POST (create a thread), then a GET (return threads on board), then a PUT (update a thread), then a DELETE (remove the thread)? The only alternative that I can think of would be that just in order to test a POST fully, you’d cause a POST, then a GET, then a DELETE… and repeat all those for the GET test, etc.

Hi,

In order to not repeat your tests, you need to make it run in order. For example, if you want to test how well the API manages a GET request, first you should populate your database, just like you said; so, in order to make those tests I would go for the POST endpoint firstly, and then GET those results in a second test. I don’t know if that’s what you mean.

Regarding the API for the Stock Price Checker, I know what you mean… In my opinion, freeCodeCamp shouldn’t be relying on external APIs which can cause a lot of trouble for the campers. Examples of this are the Twitch API (from the legacy curriculum) and the Stock Prices Checker in the Advanced Node part. Both using external APIs which dramatically changed (Twitch) or disappeared (Google Finance). Yeah, campers should try to look for another API themselves and, in my case, I’m quite happy because I learnt a lot of things along the way, but I think, for many people, that scenario would increase the chances for some campers to give up on FCC or at least get frustrated.

That being said, don’t use Alpha Vantage. As you said, you get the job done until you face the testing stage. By then, the annoying “Thank you for using Alpha Vantage! Please visit…” shows up and your tests won’t pass. I used IEX API, which happens to be free, way more flexible, work like a charm and the only requirement is to place the attribution text wherever you use the API. You can see my API working here where I used IEX’s API.

If you try and use timeouts to try to pass the tests, you won’t have success either. At least for me, didn’t work at all because the tests are not asynchronous. If you set a timeout, it will move to the next test case and if all of them have timeouts, the tests are over and none of them are green.

Hope it helps.

Happy coding!

Hi,

In case this helps anyone else out there, here’s my addition to this thread:

I ended up using Alpha Vantage for my stock-price-checker project mostly because it was the most detailed and the easiest to get set up. I actually tried setting up IEX (IEXcloud actually, because their other API is being sunset in 2019), but there was some error with their email-validation so I couldn’t get set up.

Back on track: Unfortunately, due to the limitations of Alpha Vantage’s API (5 requests per minute on the free accounts), my Mocha/Chai tests were returning errors and not passing. Keep in mind that the 5 functional tests required for the project’s user stories fire off in a relatively quick series and actually total 7 stock-price requests (1 + 1 + 1 + 2 + 2).

To resolve this issue (without having to change my external stock-price API), I introduced “pauses” of 20 seconds between each of my tests using the afterEach() method. I placed it right after the suite("GET /api/stock-prices => stockData object", function() line in my tests/2_functional-tests.js file so that it applies to all the tests within the suite, but the Mocha documentation states that you can place it anywhere within the given test suite that you want it to work in.

(Please don’t be put off by the “we” voice in my code below; it’s how I comment my code, partly for studying purposes and partly for future reference/sharing with others purposes)

afterEach(function(done) {
    this.timeout(30000)  // We'll set the timeout for this "test" to 10 seconds longer than our pause length so that our afterEach doesn't risk timing out and failing
    setTimeout( function() {
        console.log("Paused for 20 seconds to not exceed Alpha Vantage's API's limit of 5 requests per minute.");
        done();
    }, 20000);
});  // END of afterEach() "pauser"

Here’s hoping this helps somebody else who’s code works perfectly fine in the real world but still fails the Mocha/Chai test suite.

As an aside, for anyone who’s code is struggling to capture the IP address during the Chai tests ( don’t ask how I know :upside_down_face: ), you can pass headers in your Chai tests using .set() as indicated in the Chai documentation.

Here’s my Stock Price Checker in case someone wants to poke at it.