0.6.16 • Published 4 years ago

@clubfest/table-test v0.6.16

Weekly downloads
2
License
MIT
Repository
github
Last release
4 years ago

Objective

table-test is a library inspired by Golang's data-driven, table-driven testing:

  • Create test cases, each with a name and an output that you want to verify, and call the main library function runTest using the test cases.
    • runTest will display a summary of the results in the console for Node.js and in the browser for frontend javascript.

npm.io

  • A test case can be fixed automatically if the output value is JSON-serializable (and obviously, the function that produces the output value needs to be implemented correctly).
    • For frontend javascript, the auto-generated test code link is in the test report; all you need to do is copy-paste the code.
    • For Node.js, the test code (e.g. fracTest.js) can be updated automatically by piping the test output to npx @clubfest/table-test:
      • node fracTest.js | npx @clubfest/table-test

npm.io

Real-life example

  • Suppose we have a fraction library with these cases that we want to test:

    namegotwant
    testing plusfrac.make(1, 4).plus(1).toFloat()1.25
    testing dividefrac.make(2, 4).over(2).toFloat()0.25
    division by 0frac.make(1, 2).over(0)Error: denominator must be non-zero.
  • The test code you need to write using table-test would be:

    // fracTest.js
    import * as frac from "./frac.js";
    import { runTest } from './node_modules/@clubfest/table-test/index.js'
    
    runTest({
      testCases: [
        {
          name: 'testing plus',
          got: frac.make(1, 4).plus(1).toFloat(),
        },
        {
          name: 'testing toFloat',
          got: frac.make(2, 4).over(2).toFloat(),
        },
        {
          name: 'division by 0 should throw exception',
          gotFunc: _ => {
            return frac.make(1, 2).over(0);
          },
        },
      ],
    });

Viewing and fixing test results in Node JS

  • In Node.js, the test can be run via:

    $ node fracTest.js 
    
    ----------------------------------------
    
    ❌ 3 / 3 cases failed for fracTest.js:
      ❌ testing plus
        got:
          1.25
        want:
          undefined
      ❌ testing toFloat
        got:
          0.25
        want:
          undefined
      ❌ division by 0 should throw exception
        got:
          "got error: Error: denominator must be non-zero."
        want:
          undefined
        stack trace:
          Error: denominator must be non-zero.
              ...
    
    🔧 To auto-fix the above test (i.e. assuming that the implementation is correct), run the following:
        /usr/local/n/versions/node/10.16.0/bin/node fracTest.js | npx @clubfest/table-test
  • To autofix the test, assuming that the implementation is correct, i.e. the got values are as expected, run this:

    $ node fracTest.js | npx @clubfest/table-test 
    🔧 ✅  file:///.../fracTest.js has been autofixed!

Caveat:

  • autofix updates the code irreversibly. To undo the change, make sure you have that the original file is version-controlled or opened in an editor before running autofix.
  • autofix only works for nicely formatted code, i.e. each field is on a separate line, and each test case has a name that is unique within the test file.

Viewing and fixing test results in Browser JS

  • To run the test in the browser, set up an html page (index.html) that imports the test as a module, and visit the page via a local server:

    <!DOCTYPE html>
    <html>
      <head>
        <script type='module' src='fracTest.js'></script>
      </head>
    <body>
    </body>
    </html>

    npm.io

  • To auto-fix the test, assuming that the implementation is correct, click on the Quick fix link and copy-paste the content into your test file:

    npm.io

Demo of test case features

Demo: https://slowbubble.github.io/table-test/

First, install the package as a dev dependency (or copy the repo into your project):

$ npm i --save-dev @clubfest/table-test

Terminal:

$ node allTests.js 
...
✅ All 3 cases passed for eqTest.js.
❌ 2 / 8 cases failed for table-test test:
  ❌ intentional demo of failure
    got:
      3.14159
    want:
      3.14
  ❌ intentional demo of async failure
    got:
      "got error: testing reject"
    want:
      3.14

allTests.js:

import './eqTest.js';
import './indexTest.js';

indexTest.js:

import { runTest } from './index.js'

runTest({testName: 'table-test test', testCases: [
  {
    name: 'testing number',
    got: 1,
    want: 1,
  },
  {
    name: 'testing object equality',
    got: {a: 1, b: 2},
    want: {b: 2, a: 1},
  },
  {
    name: 'testing exception',
    gotFunc: _ => {
      throw 'testing exception';
    },
    wantErrSubstring: "testing",
  },
  {
    name: 'testing async',
    gotFunc: _ => {
      return new Promise(resolve => {
        setTimeout(_ => {
          resolve(3.14);
        }, 9);
      });
    },
    want: 3.14,
  },
  {
    name: 'intentional demo of failure',
    got: 3.14159,
    want: 3.14,
  },
  {
    name: 'intentional demo of async failure',
    gotFunc: _ => {
      return new Promise((resolve, reject) => {
        setTimeout(_ => {
          reject('testing reject');
        }, 9);
      });
    },
    want: 3.14,
  },
  {
    name: 'testing custom comparisonFunc',
    got: 3.14159,
    want: 3.14,
    comparisonFunc: (got, want) => {
      return Math.abs(got - want) < 0.01;
    },
  },
  {
    name: 'testing async error',
    gotFunc: _ => {
      return new Promise((resolve, reject) => {
        setTimeout(_ => {
          reject('testing reject');
        }, 9);
      });
    },
    wantErrSubstring: 'testing',
  },
]});

To run the tests in the browser, just import the script that contains the runTest call in the html page:

index.html:

<!DOCTYPE html>
<html>
  <head>
    <script type='module' src='allTests.js'></script>
  </head>
<body>
</body>
</html>

Result:

npm.io

Caveat

Some test setup may require the test to exit explicitly, in which you would need to run the test like this from allTests.js:

import { isNodeJs } from './index.js'
import eqTest from './eqTest.js';
import indexTest from './indexTest.js';

(async _ => {
  await indexTest();
  await eqTest();

  if (isNodeJs()) {
    process.exit(0);
  }
})();
0.6.16

4 years ago

0.6.15

4 years ago

0.6.14

4 years ago

0.6.13

4 years ago

0.6.12

4 years ago

0.6.11

4 years ago

0.6.9

4 years ago

0.6.8

4 years ago

0.6.7

4 years ago

0.6.6

4 years ago

0.6.5

4 years ago

0.6.3

4 years ago

0.6.2

4 years ago

0.6.4

4 years ago

0.6.1

4 years ago

0.5.2

4 years ago

0.5.1

4 years ago

0.4.3

4 years ago

0.4.1

4 years ago

0.4.2

4 years ago

0.4.0

4 years ago

0.3.2

4 years ago

0.3.4

4 years ago

0.3.3

4 years ago

0.3.0

4 years ago

0.3.1

4 years ago

0.2.5

4 years ago

0.2.4

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.0

4 years ago