Posting guards is only half the battle. A truly professional crew constantly runs drills to ensure every system is in perfect working order before the storm hits. It’s time to build your safety net.
Part 8: Running Ship Drills (Automated Testing)
- Current Rank: Quartermaster
- Objective: To write automated tests for your application, ensuring code quality, preventing regressions, and building a safety net that allows you to make changes with confidence.
The Captain’s Briefing (Background and Theory)
Our ship is complex now. It has a routing system, a view layer, a database interface, authentication guards, and specialist services. If you change a single line of code in the AppraisalService
, how can you be certain you didn’t accidentally break the login system? Do you manually click through every single feature of the entire ship after every single change?
That is the path to madness. A professional crew runs drills. An automated test is a drill for your code. It’s a script you write that checks if a piece of your application behaves exactly as you expect. You can run thousands of these drills in seconds, giving you immediate feedback.
The Drill Sergeant: Mocha
Sails.js comes equipped with a battle-hardened testing framework called Mocha right out of the box. Mocha provides a simple structure for organizing your tests:
describe('the system being tested', ...)
: This creates a “test suite,” a collection of related drills. For example,describe('AppraisalService', ...)
it('should do this specific thing', ...)
: This is the individual drill or “test case.” Its description should read like a sentence explaining what should happen. For example,it('should calculate the correct tax', ...)
- Assertions: Inside the
it()
block, you perform an action and then assert that the outcome is what you expected. An assertion is a simple check that throws an error if the condition is false. For example:assert.equal(actualValue, expectedValue)
. If they aren’t equal, the test fails.
The Test Environment
Crucially, you never want your drills to interfere with your real cargo. blog.sailscasts.com explains that Sails is configured to use a special test environment when you run your tests. As part of this setup, it’s common practice to use an in-memory or separate test database, ensuring your tests run in a clean, isolated environment and don’t touch your development data. Good tests clean up after themselves, a principle mentioned in the Sails docs for effective testing app.studyraid.com.
The Bootstrap File: Hoist the Sails!
To test any part of Sails, the app itself needs to be running. Sails provides a special file, test/bootstrap.test.js
, for this purpose. Before any of your drills are run, this bootstrap file runs sails.lift()
to start the app in the test environment. After all your drills are complete, it runs sails.lower()
to shut it down cleanly. You don’t need to touch this file, but it’s important to know it’s working for you behind the scenes.
Today, we will write a Unit Test. A unit test focuses on the smallest possible “unit” of code—in our case, a single service function—in complete isolation.
Key Concepts Checklist
Automated Test
: A script that verifies the correctness of your application code.Mocha
: The JavaScript testing framework that comes with Sails.describe()
: Defines a test suite.it()
: Defines a single test case.Assertion
: A statement that checks if a condition is true (e.g.,assert.equal()
).Unit Test
: A test for a small, isolated piece of functionality.Test Environment
: A separate configuration used for running tests to prevent side effects.npm test
: The universal command to run all automated tests in a project.
Mission Log: Quest - “The Appraiser’s Examination”
We hired a new Appraiser in part 5, but how do we know they are trustworthy? We will write a formal examination (a unit test) to verify that the AppraisalService
is, and always will be, calculating taxes correctly.
Task 1: Prepare the Examination Room
- Test files live in the
test/
directory. By convention, we’ll create a folder for our unit tests. - In your code editor, create a new folder named
unit
inside thetest/
directory. - Inside
test/unit/
, create a new file namedAppraisalService.test.js
.
- Test files live in the
Task 2: Write the Examination Questions
Open
test/unit/AppraisalService.test.js
and add the following test code. This is a classic Mocha test suite.const assert = require('assert'); // We are testing our AppraisalService describe('AppraisalService', function() { // This is the specific test case it('should correctly calculate the 15% Crown\'s Tax on a value', function() { // Step 1: Arrange - Set up our inputs and expected outputs const originalValue = 1000; const expectedTaxedValue = 850; // 1000 - 15% // Step 2: Act - Run the code we are testing const actualTaxedValue = AppraisalService.getTaxedValue(originalValue); // Step 3: Assert - Check if the result is what we expected assert.equal(actualTaxedValue, expectedTaxedValue, 'The calculated tax was not correct.'); }); it('should handle a value of zero', function() { assert.equal(AppraisalService.getTaxedValue(0), 0); }); });
Task 3: Run the Drill
- You run tests from the command line using the
npm test
command. This command is pre-configured in yourpackage.json
file by Sails. In your terminal, inside the project root, run:
npm test
You should see output from Mocha showing your tests running. If all is well, it will end with a satisfying green message:
AppraisalService ✓ should correctly calculate the 15% Crown's Tax on a value ✓ should handle a value of zero 2 passing (20ms)
This confirms your
AppraisalService
is working as expected.
- You run tests from the command line using the
Task 4: Witness a Failed Drill (The Safety Net in Action)
- Now, let’s see what happens when we break something. This is the most important part of testing.
- Open your service file:
api/services/AppraisalService.js
. Temporarily change the tax rate. Let’s say the crown gets greedy. Change
0.15
to0.20
.// In AppraisalService.js const CROWN_TAX_RATE = 0.20; // Changed from 0.15
Save the file and run the drill again from your terminal:
npm test
This time, the test will fail. Mocha will give you a detailed, bright red report showing you exactly what went wrong.
AppraisalService 1) should correctly calculate the 15% Crown's Tax on a value ... 1 passing (21ms) 1 failing 1) AppraisalService should correctly calculate the 15% Crown's Tax on a value: AssertionError [ERR_ASSERTION]: The calculated tax was not correct. + expected - actual - 800 + 850
Your test just acted as your safety net! It caught a bug (a “regression”) automatically. You now know precisely what you broke.
- Go back to
AppraisalService.js
, change the rate back to0.15
, and runnpm test
one more time to see everything pass.
Mission Debrief (Review & Outcomes)
Flawless execution! The drill was a success. You have now established a fundamental process for ensuring the quality and stability of your ship.
You’ve created a unit test that verifies your business logic, and more importantly, you’ve seen how that test protects you from introducing new bugs down the line. As your application grows, your test suite will become your most trusted advisor, giving you the confidence to refactor code, add new features, and sail your application into new waters without fear of capsizing. You can even integrate tools like Istanbul to measure your test coverage, as noted by Packt packtpub.com.
Rewards & Promotion
- +300 Doubloons
- Achievement Unlocked: You have built an automated safety net to protect your application from regressions.
- Badge Earned:
Shipshape Scrutineer
🔬
- Badge Earned:
- Promotion to: First Mate
Incredible work. As First Mate, you are now second-in-command. You have mastered the ship’s internal workings, its crew, its defenses, and its procedures. There is only one task left: to prepare this vessel for its maiden voyage into the wider world.