CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sass-true

Unit testing framework for Sass code with JavaScript test runner integration

Pending
Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Sophisticated error catching system allowing tests to validate error conditions without stopping compilation, with support for both function and mixin contexts.

Capabilities

Error Function

Handles errors in function contexts with optional error catching for testing error states.

/**
 * Error handling function for use inside functions
 * @param $message - The error message to report
 * @param $source - Optional source identifier for error context (e.g., function name)
 * @param $catch - Whether to catch the error and return it as a value instead of throwing
 * @returns Error message string when $catch is true
 * @throws Sass @error when $catch is false
 */
@function error($message, $source: null, $catch: $catch-errors);

Usage Examples:

@use 'pkg:sass-true' as *;
@use 'sass:meta';

// In your function code
@function divide($a, $b) {
  @if (meta.type-of($a) != 'number') or (meta.type-of($b) != 'number') {
    @return error(
      '$a and $b must both be numbers',
      'divide()',
      true  // Catch error for testing
    );
  }
  
  @if $b == 0 {
    @return error(
      'Cannot divide by zero', 
      'divide()',
      true
    );
  }
  
  @return math.div($a, $b);
}

// Testing error conditions
@include test('Function error handling') {
  @include assert-equal(
    divide(10, 0),
    'ERROR [divide()]: Cannot divide by zero'
  );
  
  @include assert-equal(
    divide('10', 5),
    'ERROR [divide()]: $a and $b must both be numbers'
  );
  
  // Test successful case
  @include assert-equal(divide(10, 2), 5);
}

Error Mixin

Handles errors in mixin contexts, outputting CSS comments when catching errors.

/**
 * Error handling mixin for use inside mixins and other CSS contexts
 * @param $message - The error message to report
 * @param $source - Optional source identifier for error context (e.g., mixin name)
 * @param $catch - Whether to catch the error and output as CSS comment instead of throwing
 * @output CSS comment with error details when $catch is true
 * @throws Sass @error when $catch is false
 */
@mixin error($message, $source: null, $catch: $catch-errors);

Usage Examples:

@use 'pkg:sass-true' as *;

// In your mixin code
@mixin button($type: 'primary', $size: 'medium') {
  $valid-types: ('primary', 'secondary', 'danger');
  $valid-sizes: ('small', 'medium', 'large');
  
  @if not index($valid-types, $type) {
    @include error(
      'Invalid button type: #{$type}. Valid types: #{$valid-types}',
      'button()',
      true  // Catch for testing
    );
  } @else if not index($valid-sizes, $size) {
    @include error(
      'Invalid button size: #{$size}. Valid sizes: #{$valid-sizes}',
      'button()',  
      true
    );
  } @else {
    // Generate button styles
    padding: button-padding($size);
    background-color: button-color($type);
  }
}

// Testing mixin error handling
@include test('Mixin error handling') {
  @include assert('Should output error for invalid type') {
    @include output {
      @include button('invalid-type');
    }
    
    @include contains-string('ERROR [button()]');
    @include contains-string('Invalid button type: invalid-type');
  }
  
  @include assert('Should work correctly with valid inputs') {
    @include output {
      @include button('primary', 'large');
    }
    
    @include expect {
      padding: 1rem 2rem;
      background-color: #007bff;
    }
  }
}

Configuration

Global Error Catching

Control error behavior globally with the $catch-errors setting.

/**
 * Global error catching configuration
 * @type bool | 'warn'
 * @default false
 */
$catch-errors: false !default;

Configuration Examples:

@use 'pkg:sass-true' as * with (
  $catch-errors: true  // Catch all errors globally
);

// Or set during testing
$catch-errors: 'warn' !global;  // Catch errors and show warnings

@include test('Error behavior with global catching') {
  // Errors will be caught and returned/output as comments
  @include assert-equal(
    problematic-function(),
    'ERROR: Something went wrong'
  );
}

// Reset for production
$catch-errors: false !global;

Warning Mode

When $catch-errors is set to 'warn', errors are caught but also displayed as warnings:

@use 'pkg:sass-true' as * with (
  $catch-errors: 'warn'
);

@function test-function() {
  @return error('This will be caught and warned');
}

// This will output a warning to the console and return the error string
$result: test-function();

Advanced Usage

Conditional Error Catching

Override global settings for specific error calls:

@use 'pkg:sass-true' as *;

@function strict-function($value) {
  @if $value == null {
    // Always throw, never catch (even if $catch-errors is true)
    @return error('Value cannot be null', 'strict-function()', false);
  }
  
  @if $value < 0 {
    // Conditionally catch for testing
    @return error('Value must be positive', 'strict-function()', true);
  }
  
  @return $value * 2;
}

Error Message Formatting

Error messages follow a consistent format:

  • With source: "ERROR [source]: message"
  • Without source: "ERROR: message"
@include test('Error message formatting') {
  @include assert-equal(
    error('Something failed', 'my-function()', true),
    'ERROR [my-function()]: Something failed'
  );
  
  @include assert-equal(
    error('Generic error', null, true),
    'ERROR: Generic error'
  );
}

Testing Complex Error Scenarios

@use 'pkg:sass-true' as *;

@function validate-config($config) {
  @if meta.type-of($config) != 'map' {
    @return error(
      'Configuration must be a map',
      'validate-config()',
      true
    );
  }
  
  $required-keys: ('theme', 'breakpoints');
  @each $key in $required-keys {
    @if not map-has-key($config, $key) {
      @return error(
        'Missing required key: #{$key}',
        'validate-config()',
        true
      );
    }
  }
  
  @return $config;
}

@include test('Configuration validation') {
  @include assert-equal(
    validate-config('not-a-map'),
    'ERROR [validate-config()]: Configuration must be a map'
  );
  
  @include assert-equal(
    validate-config((theme: 'dark')),
    'ERROR [validate-config()]: Missing required key: breakpoints'
  );
  
  @include assert-equal(
    validate-config((theme: 'dark', breakpoints: (mobile: 768px))),
    (theme: 'dark', breakpoints: (mobile: 768px))
  );
}

Error Handling in Mixins with Conditional Output

When using error handling in mixins, use conditional blocks to prevent generating invalid CSS:

@mixin width($length) {
  @if (meta.type-of($length) != 'number') {
    @include error('$length must be a number', 'width()', true);
  } @else {
    // Only generate CSS if no error
    width: $length;
  }
}

@include test('Conditional mixin output') {
  @include assert('Should output error comment only') {
    @include output {
      @include width('invalid');
    }
    
    @include contains-string('ERROR [width()]');
    // Should NOT contain 'width:' property
  }
}

Error State Testing Patterns

Comprehensive Error Testing

@include describe('Error Handling') {
  @include describe('Input Validation') {
    @include it('handles null values') {
      @include assert-equal(
        my-function(null),
        'ERROR [my-function()]: Input cannot be null'
      );
    }
    
    @include it('handles wrong types') {
      @include assert-equal(
        my-function('string'),
        'ERROR [my-function()]: Expected number, got string'
      );
    }
  }
  
  @include describe('Boundary Conditions') {
    @include it('handles zero values') {
      @include assert-equal(
        divide-function(10, 0),
        'ERROR [divide-function()]: Division by zero'
      );
    }
  }
}

Mixed Success and Error Testing

@include test('Function handles all cases correctly') {
  // Test successful cases
  @include assert-equal(safe-function(10), 20);
  @include assert-equal(safe-function(0), 0);
  
  // Test error cases  
  @include assert-equal(
    safe-function(-1),
    'ERROR [safe-function()]: Negative values not allowed'
  );
  
  @include assert-equal(
    safe-function(null),
    'ERROR [safe-function()]: Value required'
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-sass-true

docs

css-output-testing.md

error-handling.md

index.md

javascript-integration.md

test-structure.md

value-assertions.md

tile.json