Declarative test framework
npm install @travetto/testInstall: @travetto/test
``bash
npm install @travetto/test
yarn add @travetto/test
`
This module provides unit testing functionality that integrates with the framework. It is a declarative framework, using decorators to define tests and suites. The test produces results in the following formats:
* TAP 13, default and human-readable
* JSON, best for integrating with at a code level
* xUnit, standard format for CI/CD systems e.g. Jenkins, Bamboo, etc.
Note: All tests should be under the */ folders. The pattern for tests is defined as as a standard glob using Node's built in globbing support.
/await. A simple example would be:
Code: Example Test Suite
`typescript
import assert from 'node:assert';import { Suite, Test } from '@travetto/test';
@Suite()
class SimpleTest {
#complexService: {
doLongOperation(): Promise;
getText(): string;
};
@Test()
async test1() {
const value = await this.#complexService.doLongOperation();
assert(value === 5);
}
@Test()
test2() {
const text = this.#complexService.getText();
assert(/abc/.test(text));
}
}
`Assertions
A common aspect of the tests themselves are the assertions that are made. Node provides a built-in assert library. The framework uses AST transformations to modify the assertions to provide integration with the test module, and to provide a much higher level of detail in the failed assertions. For example:Code: Example assertion for deep comparison
`typescript
import assert from 'node:assert';import { Suite, Test } from '@travetto/test';
@Suite()
class SimpleTest {
@Test()
async test() {
assert.deepStrictEqual({ size: 20, address: { state: 'VA' } }, {});
}
}
`would translate to:
Code: Transpiled test Code
`javascript
import { __decorate } from "tslib";
import * as Δmethod from "@travetto/schema/src/decorator/method.js";
import * as Δdebug from "@travetto/runtime/src/debug.js";
import * as Δcheck from "@travetto/test/src/assert/check.js";
import * as Δfunction from "@travetto/runtime/src/function.js";
import * as Δschema from "@travetto/schema/src/decorator/schema.js";
const Δm_1 = ["@travetto/test", "doc/assert-example.ts"];
import assert from 'node:assert';
import { Suite, Test } from '@travetto/test';
let SimpleTest = class SimpleTest {
static { Δfunction.registerFunction(SimpleTest, Δm_1, { hash: 1887908328, lines: [5, 12] }, { test: { hash: 102834457, lines: [8, 11, 10] } }, false); }
async test() {
if (Δdebug.tryDebugger)
debugger;
Δcheck.AssertCheck.check({ module: Δm_1, line: 10, text: "{ size: 20, address: { state: 'VA' } }", operator: "deepStrictEqual" }, true, { size: 20, address: { state: 'VA' } }, {});
}
};
__decorate([
Test(),
Δmethod.Method({ returnType: {} })
], SimpleTest.prototype, "test", null);
SimpleTest = __decorate([
Suite(),
Δschema.Schema()
], SimpleTest);
`This would ultimately produce the error like:
Code: Sample Validation Error
`typescript
AssertionError(
message="{size: 20, address: {state: 'VA' }} should deeply strictly equal {}"
)
`The equivalences for all of the assert operations are:
*
assert(a == b) as assert.equal(a, b)
* assert(a !== b) as assert.notEqual(a, b)
* assert(a === b) as assert.strictEqual(a, b)
* assert(a !== b) as assert.notStrictEqual(a, b)
* assert(a >= b) as assert.greaterThanEqual(a, b)
* assert(a > b) as assert.greaterThan(a, b)
* assert(a <= b) as assert.lessThanEqual(a, b)
* assert(a < b) as assert.lessThan(a, b)
* assert(a instanceof b) as assert.instanceOf(a, b)
* assert(a.includes(b)) as assert.ok(a.includes(b))
* assert(/a/.test(b)) as assert.ok(/a/.test(b))In addition to the standard operations, there is support for throwing/rejecting errors (or the inverse). This is useful for testing error states or ensuring errors do not occur.
$3
throws/doesNotThrow is for catching synchronous rejectionsCode: Throws vs Does Not Throw
`typescript
import assert from 'node:assert';import { Suite, Test } from '@travetto/test';
@Suite()
class SimpleTest {
@Test()
async testThrows() {
assert.throws(() => {
throw new Error();
});
assert.doesNotThrow(() => {
let a = 5;
});
}
}
`$3
rejects/doesNotReject is for catching asynchronous rejectionsCode: Rejects vs Does Not Reject
`typescript
import assert from 'node:assert';import { Suite, Test } from '@travetto/test';
@Suite()
class SimpleTest {
@Test()
async testRejects() {
await assert.rejects(async () => {
throw new Error();
});
await assert.doesNotReject(async () => {
let a = 5;
});
}
}
`$3
Additionally, the throws/rejects assertions take in a secondary parameter to allow for specification of the type of error expected. This can be:
* A regular expression or string to match against the error's message
* A class to ensure the returned error is an instance of the class passed in
* A function to allow for whatever custom verification of the error is neededCode: Example of different Error matching paradigms
`typescript
import assert from 'node:assert';import { Suite, Test } from '@travetto/test';
@Suite()
class SimpleTest {
@Test()
async errorTypes() {
assert.throws(() => {
throw new Error('Big Error');
}, 'Big Error');
assert.throws(() => {
throw new Error('Big Error');
}, /B.*Error/);
await assert.rejects(() => {
throw new Error('Big Error');
}, Error);
await assert.rejects(() => {
throw new Error('Big Error');
}, (error: Error) =>
error.message.startsWith('Big') && error.message.length > 4
);
}
}
`Running Tests
To run the tests you can either call the Command Line Interface by invokingTerminal: Test Help Output
`bash
$ trv test --helpUsage: test [options] [first:string] [globs...:string]
Options:
-f, --format Output format for test results (default: "tap")
-c, --concurrency Number of tests to run concurrently (default: 9)
-t, --tags Tags to target or exclude when using globs
-o, --format-options Format options
-h, --help display help for command
`The regexes are the patterns of tests you want to run, and all tests must be found under the
test/` folder.Like output, all promises are also intercepted. This allows the code to ensure that all promises have been resolved before completing the test. Any uncompleted promises will automatically trigger an error state and fail the test.