part-8.jpg

Learn Sails.js - Part 8

🛈

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

    1. Test files live in the test/ directory. By convention, we’ll create a folder for our unit tests.
    2. In your code editor, create a new folder named unit inside the test/ directory.
    3. Inside test/unit/, create a new file named AppraisalService.test.js.
  • Task 2: Write the Examination Questions

    1. 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

    1. You run tests from the command line using the npm test command. This command is pre-configured in your package.json file by Sails.
    2. In your terminal, inside the project root, run:

      npm test
      
    3. 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.

  • Task 4: Witness a Failed Drill (The Safety Net in Action)

    1. Now, let’s see what happens when we break something. This is the most important part of testing.
    2. Open your service file: api/services/AppraisalService.js.
    3. Temporarily change the tax rate. Let’s say the crown gets greedy. Change 0.15 to 0.20.

      // In AppraisalService.js
      const CROWN_TAX_RATE = 0.20; // Changed from 0.15
      
    4. Save the file and run the drill again from your terminal:

      npm test
      
    5. 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.

    6. Go back to AppraisalService.js, change the rate back to 0.15, and run npm 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 🔬
  • 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.