Testing a Sass Function in 5 Minutes

Share this article

The other day, I was playing with the include-media library from Eduardo Bouças and I wanted to quickly test a function I built so I started writing a little mixin to help me test a lot of different scenarios. After a couple of minutes, I came up with the most minimalistic Sass testing engine you could possibly get.

While this article might be slightly technical, I believe it can be helpful to many people as testing it should be the responsibility of every developer. Also, when going through things one after the other, you’ll see that it actually is not that difficult to understand.

Creating a dummy function to test

Everything starts with a function to test. For our purpose, I suggest we go with a very simple function. Let’s say, a function to double a number.

@function double($value) {
  @return $value * 2;
}

Sounds simple enough. Although, and only for our demo concerns, we are going to voluntarily introduce a bug inside our function so that we can actually see that one of our tests fails.

@function double($value) {
  // Voluntarily introduced bug for demonstration purpose
  @if $value == 3 {
    @return 5;
  }

  @return $value * 2;
}

Writing tests

You might find it surprising, but writing tests in our system is as simple as writing a Sass map where keys are function inputs, and values are expected results.

$tests-double: (
  1: 2,
  2: 4,
  3: 6,
  4: 8
);

That’s it! We’ve written our tests. Again: on the left side are the inputs, and on the right side the expected outputs.

The test runner

So far, so good. We have built our function and we have written our tests. We now only need to create the test runner.

If you are familiar with Sass, you might already understand where this is going. Our test runner is going to iterate on the test map, calling the function for each input and making sure that it matches the expected output. Then, it will print the result of our tests.

Here is what our test runner looks like:

/// Run a function ($function) on a test suite ($tests)
/// @param {Map} $tests - Test suite
/// @param {String} $function - Name of function to test
@mixin run-tests($tests, $function) { .. }

Alright. Let’s dig into the belly of the beast. The idea is to build a string with the result of each test, and once everything has been done, print the string with the @error directive. We could also pass it to the content property of a pseudo-element for instance, but it’s slightly more complex so we’ll stick to @error.

First thing to do is to iterate on the test suite. For each test, we dynamically call the function from its name (with the call(..) function) and we check if the result is as expected.

@mixin run-tests($tests, $function) {
  $output: '';

  @each $test, $expected-result in $tests {
    $result: call($function, $test...);

    @if $result == $expected-result {
      // Test passed
      $output: $output + 'Test passed; ';
    } @else {
      // Test failed
      $output: $output + 'Test failed; ';
    }
  }

  // Print output
  @error $output;
}

At this point, we have our system working. Let’s run it on our test suite to see what it looks like.

@include run-tests($tests-double);
Test passed; Test passed; Test failed; Test passed;

Hey! That’s a start right? Now we only need to make the output a bit more helpful (and friendly).

Pimping the output

This is the moment where you can customize the output to make it look like you want. There is no single way to do this, you can output whatever you prefer. Note that as per the CSS specification, you can have a line break in your string using \a.

In my case, here is what I went with:

@mixin run-tests($tests, $function) {
  $output: '';
  $length: length($tests);
  $failing: 0;

  @each $test, $expected-result in $tests {
    $result: call($function, $test...);
    $test-index: index(map-keys($tests), $test);
    $output: $output + '\a Test #{$test-index} out of #{$length}... ';

    @if $result == $expected-result {
      // Test passed
      $output: $output + '✔';
    } @else {
      // Test failed
      $failing: $failing + 1;
      $output: $output + '✘\a   Expected : `#{$expected-result}`.\a   Actual   : `#{$result}`.';
    }
  }

  // Print output
  @error 'Started tests for function `#{$function}`\a '
    + '-----------------------------------'
    + $output + '\a '
    + '-----------------------------------\a '
    + 'Over: #{$length - $pass} test(s) out of #{$length} failing.';
}

If we run it again over on our $tests-double for the double function, here is what we got:

Started tests for function `double`
-----------------------------------
Test 1 out of 4... ✔
Test 2 out of 4... ✔
Test 3 out of 4... ✘
  Expected : `6`.
  Actual   : `5`.
Test 4 out of 4... ✔
-----------------------------------
Over: 1 test(s) out of 4 failing.

Now that’s pretty neat, isn’t it?

Testing functions with multiple arguments

In our example, our function had a single argument but we can rely on the fact that Sass maps accepts anything as keys (including lists) to test functions with several parameters as well. It would look like this:

@function my-function($string, $color, $length) { .. }

$tests-my-function: (
  ('a', red, 42px): 'My expected result',
  // ...
);

If you have a look back at our mixin, you’ll see that we add an ellipsis (...) to the $test variable when calling the function with call(..).

$result: call($function, $test...);

This means we pass the value $test as an arglist. In other words, if $test is a list (e.g. ('a', red, 42px)), then it will be passed as several arguments instead as a list.

Final thoughts

There you have it, folks: the most minimalistic Sass testing engine ever. This tiny testing system can come in very handy to test the few functions you could have in your project, especially if you plan on providing it to other developers (framework, library…). Also, I found out it is extremely convenient to quickly test a function on SassMeister. Just drop the mixin and your function there, and run your tests!

Of course if you are looking for more in-depth solution, you might want to have a look at True by Eric Suzanne. As a full testing framework for Sass, it is more suited for global unit test infrastructure.

If you want to have a look at (a slightly more advanced version of) the code, I opened the SassyTester repository to gather everything.

So what do you think?

Frequently Asked Questions (FAQs) about Testing SASS Function

What is the Importance of Testing SASS Functions?

Testing SASS functions is crucial in web development as it ensures the functionality and efficiency of your CSS preprocessor. It helps in identifying and fixing bugs, enhancing the performance of your website, and ensuring that your SASS functions are working as expected. By testing your SASS functions, you can ensure that your website’s design and layout are consistent across different browsers and platforms.

How Can I Test SASS Functions?

Testing SASS functions can be done using various tools and methodologies. One common method is using a SASS testing framework like True. True is a unit-testing tool that can be integrated with your SASS projects. It allows you to write tests directly in your SASS files, which can then be run in Node.js or any web browser.

What are the Best Practices for Testing SASS Functions?

Some of the best practices for testing SASS functions include writing tests for each function, using a consistent naming convention for your tests, and ensuring that your tests cover all possible scenarios. It’s also important to regularly run your tests and update them as necessary when changes are made to the functions.

Can I Use JavaScript for Testing SASS Functions?

Yes, JavaScript can be used for testing SASS functions. Tools like Jest can be used to test your SASS functions. Jest is a JavaScript testing framework that allows you to write tests in a simple and clear syntax.

What are the Common Challenges in Testing SASS Functions?

Some of the common challenges in testing SASS functions include dealing with complex functions, managing dependencies, and ensuring cross-browser compatibility. These challenges can be overcome by using a robust testing framework, writing clear and concise tests, and regularly reviewing and updating your tests.

How Can I Improve My SASS Testing Skills?

Improving your SASS testing skills can be achieved by practicing regularly, reading and learning from the code of others, and staying updated with the latest trends and best practices in SASS testing. Participating in coding challenges and contributing to open-source projects can also help improve your skills.

What is the Role of SASS in Web Development?

SASS plays a crucial role in web development by making CSS more powerful and maintainable. It provides features like variables, nesting, mixins, and functions, which can help in writing more efficient and reusable CSS code.

How Can I Debug SASS Functions?

Debugging SASS functions can be done using various tools and techniques. One common method is using the SASS inspect function, which allows you to inspect the value of a SASS expression. You can also use the SASS @debug directive, which prints the value of a SASS expression to the console.

Can I Test SASS Functions Without a Testing Framework?

While it’s possible to test SASS functions without a testing framework, it’s not recommended. A testing framework provides a structured and systematic approach to testing, making it easier to write, manage, and run tests.

What are the Benefits of Using a SASS Testing Framework?

Using a SASS testing framework provides several benefits. It allows you to write tests in a structured and systematic manner, making it easier to manage and run tests. It also provides tools and features that can help in writing more effective tests, such as assertion functions and test runners.

Kitty GiraudelKitty Giraudel
View Author

Non-binary trans accessibility & diversity advocate, frontend developer, author. Real life cat. She/they.

sasssass functionssass mixinssass testingStuRtdd
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week