npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

chaos-engine

v1.1.3

Published

A package for running destructive tests on functions.

Downloads

4

Readme

Chaos Engine

Overview

npm version

In simple terms, chaos engineering is the practice of testing your system or program's resilience by occasionally causing it to fail. It helps to expose unknown errors and weaknesses.

This package is a testing tool that allows the user to run a wide range of negative/destructive tests on their code functions.

To get started, install from npm: npm install chaos-engine.

Table of content

Basic Usage

Say we have a sample function named func1. This function accepts three parameters, and each of them should be a number. It then adds them up and returns a number value. Now, let's try to break it.

var chaosEngine = require("chaos-engine");

const { describe, createChaos } = chaosEngine;

var func1 = function add(a, b, c) {
    if (typeof a !== 'number' || typeof b !== 'number' || typeof c !== 'number' ) throw new Error('params should be a number');
    return a+b+c;
}

//describe your function
let description;
description = describe
                .title('adds three numbers.')
                .accepts(3)
                .types('number')
                .returns('number')
                .getDescription();

// run destructive tests on the function
let chaos_result = createChaos.destroy(func1, description);
console.log(chaos_result);

/* Output:
{
  description: {
    title: 'a function for adding.',
    params: 3,
    types: [ 'number', 'number', 'number' ],
    return_value: 'number'
  },
  chaos_report: {
    no_params: [
      {
        payload: 'no payload sent',
        response: 'params should be a number'
      }
    ],
    single_params: [
      { payload: null, response: 'params should be a number' },
      { payload: undefined, response: 'params should be a number' },
      { payload: true, response: 'params should be a number' },
      { payload: false, response: 'params should be a number' },
      { payload: {}, response: 'params should be a number' },
      { payload: [], response: 'params should be a number' },
      { payload: 1.35, response: 'params should be a number' },
      { payload: 'sandra', response: 'params should be a number' },
      { payload: 10, response: 'params should be a number' },
      {
        payload: '[email protected]',
        response: 'params should be a number'
      }...
    ],
    multiple_params: [
      { payload: [ 1, 2, 3 ], response: 6 },
      {
        payload: [ 'x', 'i', 0 ],
        response: 'params should be a number'
      },
      {
        payload: [ 1, true, false ],
        response: 'params should be a number'
      },
      {
        payload: [ true, undefined, null ],
        response: 'params should be a number'
      },
      { payload: [ 1, 2, 3 ], response: 6 },
      {
        payload: [ 'letter', 'biro', 'pen' ],
        response: 'params should be a number'
      },
      {
        payload: [ 8, { a: 2, b: 4, c: 5 }, 9 ],
        response: 'params should be a number'
      },
      { payload: [ 8, {}, 9 ], response: 'params should be a number' },
      ...]
  }
}
*/

Let's test another function func2 that has not implemented any validation or error checks.

var chaosEngine = require("chaos-engine");

const { describe, createChaos } = chaosEngine;

var func2 = function add(a, b, c) {
    return a+b+c;
}

//describe your function
let description;
description = describe
                .title('another function for adding.')
                .accepts(3)
                .types(['number'])
                .returns('number')
                .getDescription();

// run destructive tests on the function
let chaos_result = createChaos.destroy(func2, description);
console.log(chaos_result);

/*Output:
{
  description: {
    title: 'another function for adding.',
    params: 3,
    types: [ 'number', 'number', 'number' ],
    return_value: 'number'
  },
  chaos_report: {
    no_params: [ { payload: 'no payload sent', response: NaN } ],
    single_params: [
      { payload: null, response: NaN },
      { payload: undefined, response: NaN },
      { payload: true, response: NaN },
      { payload: false, response: NaN },
      { payload: {}, response: '[object Object]undefinedundefined' },
      { payload: [], response: 'undefinedundefined' },
      { payload: 0, response: NaN },
      { payload: 1.35, response: NaN },
      { payload: 0.987, response: NaN },
      { payload: 'sandra', response: 'sandraundefinedundefined' },
      { payload: 10, response: NaN },
      { payload: [ 1, 2 ], response: '1,2undefinedundefined' },
      { payload: [ 1, 2, 3 ], response: '1,2,3undefinedundefined' },...],
    multiple_params: [
      { payload: [ 1, 2, 3 ], response: 6 },
      { payload: [ 'x', 'i', 0 ], response: 'xi0' },
      { payload: [ 1, true, false ], response: 2 },
      { payload: [ true, undefined, null ], response: NaN },
      { payload: [ 1, true, false ], response: 2 },
      { payload: [ 1, true, false ], response: 2 },
      { payload: [ 1, false, true ], response: 2 },
      { payload: [ 1, 2, 3 ], response: 6 },
      {
        payload: [ 'letter', 'biro', 'pen' ],
        response: 'letterbiropen'
      },
      {
        payload: [ 8, { a: 2, b: 4, c: 5 }, 9 ],
        response: '8[object Object]9'
      },
      { payload: [ 8, {}, 9 ], response: '8[object Object]9' },
      { payload: [ 8, [], 9 ], response: '89' },...
    ]
  }
}
*/

P.S: Output results have been shortened here for easy reading.

Comparing the two outputs, we can see from the different responses that although the functions do the same thing, only one looks out for errors and handles them.

⬆ back to top

Description

There are three main properties involved in generating of a chaos report: .describe(), .supply(), and .destroy().

  1. .describe():

This property allows you to describe what your function does. It has five chainable methods.

| method | accepts | description | | ------------ |-------------| -----| | title | String | This explains what the function does. | | accepts | Integer | This refers to the number of arguments the function accepts. | | types | String | This shows what type of arguments the function expects. If the function accepts more than one argument and they are all of the same type, the user can pass just one string e.g .accepts(3).types('number') will return params: 3, types: [ 'number', 'number', 'number' ]. | | returns | Srting | This refers to the type of value the function will return if the correct arguments are passed. | | getDescription (required) | | This return an object containing the description. | | getDescriptionString | | This return a string containing the description. |

Example:

let description;
description = describe
                .title('adds numbers.')
                .accepts(3)
                .types('number')
                .returns('number')
                .getDescription();

console.log(description);
/*Output:
{
    title: 'adds numbers.',
    params: 3,
    types: [ 'number', 'number', 'number' ],
    return_value: 'number'
}*/

The chaining should always follow the format used in the example.

The value(s) passed into .types() can only either be 'string', 'number', 'undefined', 'null', 'boolean', 'symbol', or 'bigint'.

If the chain contains any other method not in the table above, it returns an InvalidMethod error. It also throws a TypeError message if an invalid datatype is passed into any of the methods.

Adding .getDescription() to the end of the chain returns an object containing the functions description. To get the description as a string, use .getDescriptionString() instead, and ensure that the title value starts with an action word. Both will return a TypeError if they are not the last in the chain. It will also return an empty object if no other method is called.

  1. .supply():

Chaos-engine comes with a predefined array of random arguments that are passed through the function provided. Calling the .supply() property allows you to provide your selection of arguments as an array.

| parameters | type | description | | ------------ |-------------| -----| | array (required) | Array | This is the array containing the user's arguments. |

Calling .supply() without chaining .destroy() only returns the arrays.

Example:

var arr =   [1, 5, 8, [9, 8], "kl", {1: 'v', 2: 'b'}, 'must', 'contain', 'ten', 'values'];


let chaos_result = createChaos.supply(arr);
console.log(chaos_result);

/*Output:
ChaosEngine {
  report: {},
  arr: [
    1,
    5,
    8,
    [ 9, 8 ],
    'kl',
    { '1': 'v', '2': 'b' },
    'must',
    'contain',
    'ten',
    'values'
  ],
  arr2: [
    [ 1, 'ten', 1, 'values' ],
    [ 5, 'values', 'values', 1, 5, 1 ],
    [
      'must',
      'kl',
      'values',
      8,
      'contain',
      { '1': 'v', '2': 'b' },
      'values'
    ],
    [
      'values',
      1,
      5,
      8,
      { '1': 'v', '2': 'b' },
      'kl',
      { '1': 'v', '2': 'b' },
      [ 9, 8 ],
      'values',
      'must'
    ],
    [ 1, [ 9, 8 ], 'kl', 'values', 'must', 'must' ],
    [ 'must', 8, { '1': 'v', '2': 'b' }, [ 9, 8 ], 8, 1, 1 ],
    [ 'kl', 'ten', 8, 'ten' ],
    [ 1, 'kl', { '1': 'v', '2': 'b' }, { '1': 'v', '2': 'b' } ],
    [ 5, 'kl', 'values', { '1': 'v', '2': 'b' } ],
    [
      'ten',
      'kl',
      [ 9, 8 ],
      { '1': 'v', '2': 'b' },
      8,
      { '1': 'v', '2': 'b' }
    ]
  ]
}
*/

The chaos engine creates a second array of arrays arr2 by selecting random values from the array supplied. It then uses the array for the multiple params test(explained in no. 3).

It returns a TypeError if:

  • If the property is called without passing an array.

It returns an ArgumentError if:

  • the array is empty.
  • the array contains less than ten values or more than ten thousand values.
  1. .destroy(): This property does the majority of the work. It is what runs the destructive tests. It can be used without the .supply() property. If used together, .supply() must always be chained before .destroy().

It accepts three arguments. The arguments must always follow the order: .destroy(fn, description, limit). If you will not pass a description but want to set a limit, place an empty object in its place: .destroy(my_func, {}, 10).

| parameters | type | description | | ------------ |-------------| -----| | fn (required) | function | The function to be tested. | | description | object /string | This contains the description of the function being passed. It is generated using the .describe() property. The default value is {}.| | limit | Integer | This refers to how many times the function should be tested. The default value is the length of the array.|

It returns an object containing the description (if one was passed as earlier explained), a chaos_report object containing the test results, and a total property showing the total number of tests. The chaos report contains three arrays:

  • no_params: This displays the response received when no argument is passed to the function.
  • single_params: This displays all arguments passed to the function and responses received for each of them. Here, all values in the predefined array or the one supplied are passed as single arguments. So, even if it is an array value, the function will receive it as a single argument.
  • multiple_params: This also displays all arguments passed to the function and responses received for each of them. Here, the function always receives an array containing several values. The array values are then separated and passed as individual arguments. This means that a function will receive this [1, 2, [3, 'a'], {a: 'name', b: 'age'}] but interpret it as 1, 2, [3, 'a'], {a: 'name', b: 'age'}. Nested objects are not affected.

Example:

var arr =   [1, 5, 8, [9, 8], "kl", {1: 'v', 2: 'b'}, 'must', 'contain', 'ten', 'values', 1, 5, 8, 1, 5, 8,1, 5, 8,1, 5, 8,1, 5, 8,1, 5, 8,[9, 8], "kl", {a: 8, b: 9}, "sandra", "mandara", null, undefined, {}, false, true, [], 134567876543234567, 987654345678];
console.log(arr.length) //to show how `limit` works

let description;
description = describe
              .title("luhn checker")
              .accepts(3)
              .types('array')
              .returns('number')
              .getDescription();

let chaos_result = createChaos.supply(arr).destroy(func1, description, 10)
console.log(chaos_result);

/*Output:
41
{
  description: {
    title: 'luhn checker',
    params: 3,
    types: [ 'array', 'array', 'array' ],
    return_value: 'number'
  },
  chaos_report: {
    no_params: [
      {
        payload: 'no payload sent',
        response: 'params should be a number'
      }
    ],
    single_params: [
      { payload: 1, response: 'params should be a number' },
      { payload: 5, response: 'params should be a number' },
      { payload: 8, response: 'params should be a number' },
      { payload: [ 9, 8 ], response: 'params should be a number' },
      { payload: 'kl', response: 'params should be a number' },
      {
        payload: { '1': 'v', '2': 'b' },
        response: 'params should be a number'
      },
      { payload: 'must', response: 'params should be a number' },
      { payload: 'contain', response: 'params should be a number' },
      { payload: 'ten', response: 'params should be a number' },
      { payload: 'values', response: 'params should be a number' }
    ],
    multiple_params: [
      {
        payload: [ 8, undefined ],
        response: 'params should be a number'
      },
      {
        payload: [ 1, 'values', 987654345678, undefined ],
        response: 'params should be a number'
      },
      {
        payload: [ [ 9, 8 ], 1, 1, [ 9, 8 ], 1, 8, false, 8 ],
        response: 'params should be a number'
      },
      {
        payload: [ null, 'contain', 5, 5, 1, 5, 8, 'mandara', 'must' ],
        response: 'params should be a number'
      },
      {
        payload: [ undefined, 5 ],
        response: 'params should be a number'
      },
      {
        payload: [ 1, [ 9, 8 ], false ],
        response: 'params should be a number'
      },
      {
        payload: [ true, 8, [ 9, 8 ], 1, 5, [], 987654345678 ],
        response: 'params should be a number'
      },
      { payload: [ 1, 8, 8, 8, 1 ], response: 17 },
      { payload: [ 8, 5, 'mandara', 'values' ], response: '13mandara' },
      {
        payload: [ 5, 'mandara', [ 9, 8 ], false, [] ],
        response: 'params should be a number'
      }
    ]
  },
  total: 21
}*/

As seen above, the array supplied contains 41 values. However, because limit equals 10, the chaos engine only carried out 10 tests each for single_params and multiple_params.

An ArgumentError is thrown if:

  • limit is lower than 10 or exceeds 100,000.
  • limit is higher than length of the array.

This package currently only provides 30 predefined values to test with. If you choose not to supply your array, the limit cannot be higher than 30.

⬆ back to top