1.4.0 • Published 3 years ago

oliver-test v1.4.0

Weekly downloads
12
License
ISC
Repository
github
Last release
3 years ago

Oliver Test

npm NPM npm

A lightweight and easy-to-use library for testing JavaScript and TypeScript.

Contents

Installation

Add the node module to your project:

$ npm install oliver-test

Add a test command:

// package.json

...
  "scripts": {
    "test": "node <path-to-test-initiator-file>"
  }
...

Releases

For a complete list of releases and features, see the Releases Doc

Running Tests

In order to run tests with Oliver Test, you need to create at least:

  • One 'initiator' file that imports and calls runTestDir(testDir: string) and provides a path to your test files.
  • One or more test suite files that import and call test(name: string, testBody:function).

See Writing Tests for details on creating these files.

Run your tests by running the 'initiator' file through the console, either directly with node <path-to-test-initiator-file> or as an npm script (if you have set one up) with npm run test.

For example, consider a project with the following structure:

├── package.json
├── run-tests.js
└── tests
    ├── index.test.ts
    ├── injector.test.ts
    └── profiler.test.js
// package.json

...
  "scripts": {
    "test": "node run-tests.js"
  }
...
// run-tests.js

const { runTestDir } = require('oliver-test');
runTestDir('./tests');

To run all the the tests in ./tests you would run node run-tests.js or npm run test.

Writing Tests

Test Suites

Oliver Test expects tests to be organized into test suite files.

The test driver will identify any file as a test suite if it ends in .test.js or .test.ts. Each test suite may contain any number of tests, which may contain any number of assertions.

Tests are created by calling test(name: string, testBody:function) and providing the test body as a callback function. Assertions are imported as methods of the expect object.

Example test suite:

// example.test.js

const { test, expect } = require('oliver-test');

test("Addition", function() {
    let sum = 2+2;
    expect.equal(sum, 4);
})

test("Array Length", function() {
    let arr = [1,2,3];
    expect.true(arr.length > 0);
})

Assertions

Assertions are all implemented as methods of the expect object. These are the supported assertions as of the latest version:

AssertionBehavior
equal(actual:any, expected:any)Checks that actual is strongly equal to expected.
notEqual(actual:any, expected:any)Checks that actual is not strongly equal to expected.
equalLoose(actual:any, expected:any)Checks that actual is loosely equal to expected.
notEqualLoose(actual:any, expected:any)Checks that actual is not loosely equal to expected.
null(actual:any)Checks that actual is null.
notNull(actual:any)Checks that actual is not null.
undefined(actual:any)Checks that actual is undefined.
notUndefined(actual:any)Checks that actual is not undefined.
truthy(actual:any)Checks that actual is truthy.
true(actual:any)Checks that actual is equal to true.
falsey(actual:any)Checks that actual is falsey.
false(actual:any)Checks that actual is equal to false.
throwsError(operation:function)Checks that operation throws any error.
throws(errorClass,operation)Checks that operation throws an error of type errorClass.

beforeEach()

The beforeEach(action:function) function receives a callback function and sets it to be called immediately before every subsequent test body in the same file. It is typically called before any test in the same file. This is useful to ensure that variables are set/reset to specific values before each test.

Example usage:

// example.test.js

const { expect, test, beforeEach } = require('olive-test');

let num;
const numVal = 5;

beforeEach(()=>{
  num = numVal;
})

test("Change num", ()=>{
  num = numVal*2;
  expect.notEqual(num,numVal);
})


test("num has been reset", ()=>{
  expect.equal(num,numVal);
})

Handling Errors

If an error is not caught within an individual test body the test will fail and print the error.

If an error is not caught during a test suite the suite will fail regardless of how many individual tests had passed.

Any output to stderr is considered an error and will fail the test suite.

Mocking

Oliver Test provides two methods for mocking:

  • when(obj:object, funcName:string, ...args:any) and
  • mock(className:class).

when()

The when function is used to force a specific behavior on any method of an object when it receieves specific arguments to it's parameters. When that method is next called it will examine the arguments it receives and perform the matching mock behavior. If no behavior is defined for the arguments, it will perform its original behavior.

The following methods may be chained indefinitely on to the end of when to dictate the mocked behavior:

MethodBehavior
thenDo(action:function)The method will execute the provided function.
thenReturn(val:any)The method will return the provided value.
thenThrow(err:Error)The method will throw the provided error.

When you chain multiple of these behaviors together, the method will perform one of them in order each time it called. When there is only one remaining, that one will be used indefintely.

Example usage of when:

// example.test.ts

const { when } = require('oliver-test');

const myObj = {
  val: "original value",
  getVal() { return this.val }
}

when(myObj, "getVal", 2)
  .thenDo(()=>console.log("mocked log"))
  .thenReturn("mocked value");

myObj.getVal()    // returns "original value"
myObj.getVal(1)   // returns "original value"
myObj.getVal(2)   // prints "mocked log"
myObj.getVal(2)   // returns "mocked value"
myObj.getVal(2)   // returns "mocked value"

mock()

The mock function receives a class as a parameter and returns an object with all of the methods of that class but none of the member variables. It also adds a new method: when(funcName:string, ...args:any). This method wraps the when function from Oliver Test, but only mocks methods of the mocked object and provides itself for the object parameter.

This allows you to mock any classes that the object you are testing depends on. Bear in mind that if any of the mocked class's methods depend on member variable they will not work. You should use when to mock any method that needs to be called from the mocked class.

Example usage of mock:

// example.test.ts

const { mock } = require('oliver-test');

const testObj = {
  useOtherObject(obj,arg=0){
    obj.getVal(arg)
  }
}

class myClass = {
  constructor() {}
  getVal() { return "original value" }
}

let mockObj = mock(myClass);
mockObj.when("getVal", 2)
  .thenDo(()=>console.log("mocked log"))
  .thenReturn("mocked value");

testObj.useOtherObj(mockObj)    // returns "original value"
testObj.useOtherObj(mockObj,1)   // returns "original value"
testObj.useOtherObj(mockObj,2)   // prints "mocked log"
testObj.useOtherObj(mockObj,2)   // returns "mocked value"
testObj.useOtherObj(mockObj,2)   // returns "mocked value"

TypeScript Warning

When using mock in TypeScript you will need to cast the returned object to any. If you don't TypeScript will not accept the mocked object as an instance of the provided class because of the missing fields and additional when method.

Test Output

A future release will allow the user to specify a verbose option to determine the ammount of output.

The test driver runs all tests suites concurrently and prints their results as soon as they complete, regardless of their order.

Reporting Suites

Each test suite is shown with a summary and list of indidual test names. The icon to the left of each test indicates its success.

Reporting Errors

If a test fails an explanation will be printed directly beneath its name. If there are any suite-level errors they are printed at the end of the summary regardless of when they occurred in the suite file.

Timing

Test durations are recorded as the composite time during which each individual test ran. This does not include the duration of operations performed by the test driver when starting, compiling, or reporting.

1.4.0

3 years ago

1.3.2

3 years ago

1.3.0

3 years ago

1.2.1

3 years ago

1.2.0

3 years ago

1.1.1

3 years ago

1.1.2

3 years ago

1.1.0

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago