New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

alsatian

Package Overview
Dependencies
Maintainers
1
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alsatian - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

.nyc_output/81086f40c3f1e13b7dc49d1de304e067.json

22

CONTRIBUTING.md

@@ -5,20 +5,22 @@ # Contributing to alsatian

## First of thanks
## First off - thanks
Social coding is great so thank you for being a part of it! Hats off to you!!!
## Asking for help
## The process
Everybody needs help sometimes and we are completely open to answering all and any questions you may have before, during or after contributing or even if you aren't contributing and just have a question. Just raise an issue and we'll gladly get back to you.
### 1. Issue
## Before you create a pull request
If there's no issue that covers the new feature or bug you'd like to fix then create one. Otherwise if noone is assigned to the existing issue just let us know you'd like to work on it.
All you need to do is complete the following checklist
### 2. Do your thing
* Create an issue for the pull request
* Add JSDocs if relevant
* Write tests in order to prove the code works
Get your creative juices flowing, work however you want - there should be plenty of tools in place to help you along the way.
## Creating a pull request
### 3. Pull request
Now you're ready to create a pull request go ahead, all you'll need to do is link it to the issue you created earlier and your done. You can also of course add any further information you'd like but otherwise you're done!
There's a checklist whenever you create your pull request that'll help you check everything is in order before submitting. After you create a pull request our automatic CI checks will inspect your code and flag any issues if there are any. Then an Alsatian member will review the code and OK it to get merged and your wonderful code will be available in the next Alsatian release :)
## Asking for help
Everybody needs help sometimes and we are completely open to answering any and all questions you may have before, during or after contributing or even if you aren't contributing and just have a question. Just raise an issue or tag us in a comment and we'll gladly get back to you.
import { Expect, Matcher, TestOutputStream, TestSet } from "./";
import { AsyncSetup, AsyncTeardown, AsyncTest, FocusTest, FocusTests, IgnoreTest, IgnoreTests, Setup, Teardown, Test, TestCase, TestFixture, Timeout } from "./decorators";
import { AsyncSetup, AsyncSetupFixture, AsyncTeardown, AsyncTeardownFixture, AsyncTest, FocusTest, FocusTests, IgnoreTest, IgnoreTests, Setup, SetupFixture, Teardown, TeardownFixture, Test, TestCase, TestFixture, Timeout } from "./decorators";
import { Any, FunctionSpy, SpyOn, SpyOnProperty } from "./spying";

@@ -8,2 +8,2 @@ import { TestCaseResult, TestFixtureResults, TestOutcome, TestResults, TestSetResults } from "./results";

import { TestRunner } from "./running";
export { Any, AsyncSetup, AsyncTeardown, AsyncTest, Expect, FocusTest, FocusTests, IgnoreTest, IgnoreTests, Matcher, Setup, FunctionSpy, SpyOn, SpyOnProperty, Teardown, Test, TestCase, TestRunner, TestSet, Timeout, TestSetResults, TestOutcome, METADATA_KEYS, TestFixture, TestOutputStream, MatchError, TestFixtureResults, TestResults, TestCaseResult, TestTimeoutError };
export { Any, AsyncSetup, AsyncSetupFixture, AsyncTeardown, AsyncTeardownFixture, AsyncTest, Expect, FocusTest, FocusTests, IgnoreTest, IgnoreTests, Matcher, Setup, SetupFixture, FunctionSpy, SpyOn, SpyOnProperty, Teardown, TeardownFixture, Test, TestCase, TestRunner, TestSet, Timeout, TestSetResults, TestOutcome, METADATA_KEYS, TestFixture, TestOutputStream, MatchError, TestFixtureResults, TestResults, TestCaseResult, TestTimeoutError };

@@ -9,3 +9,5 @@ "use strict";

exports.AsyncSetup = decorators_1.AsyncSetup;
exports.AsyncSetupFixture = decorators_1.AsyncSetupFixture;
exports.AsyncTeardown = decorators_1.AsyncTeardown;
exports.AsyncTeardownFixture = decorators_1.AsyncTeardownFixture;
exports.AsyncTest = decorators_1.AsyncTest;

@@ -17,3 +19,5 @@ exports.FocusTest = decorators_1.FocusTest;

exports.Setup = decorators_1.Setup;
exports.SetupFixture = decorators_1.SetupFixture;
exports.Teardown = decorators_1.Teardown;
exports.TeardownFixture = decorators_1.TeardownFixture;
exports.Test = decorators_1.Test;

@@ -20,0 +24,0 @@ exports.TestCase = decorators_1.TestCase;

@@ -7,5 +7,7 @@ declare const TEST_FIXTURE: "alsatian:test-fixture";

declare const SETUP: "alsatian:setup";
declare const SETUP_FIXTURE: "alsatian:setup-fixture";
declare const TEARDOWN: "alsatian:teardown";
declare const TEARDOWN_FIXTURE: "alsatian:teardown-fixture";
declare const TEST_CASES: "alsatian:testcases";
declare const TIMEOUT: "alsatian:timeout";
export { TEST_FIXTURE, TESTS, FOCUS, IGNORE, IGNORE_REASON, SETUP, TEARDOWN, TEST_CASES, TIMEOUT };
export { TEST_FIXTURE, TESTS, FOCUS, IGNORE, IGNORE_REASON, SETUP, SETUP_FIXTURE, TEARDOWN, TEARDOWN_FIXTURE, TEST_CASES, TIMEOUT };

@@ -20,4 +20,8 @@ // currently typing these values to string as literal causes

exports.SETUP = SETUP;
var SETUP_FIXTURE = "alsatian:setup-fixture";
exports.SETUP_FIXTURE = SETUP_FIXTURE;
var TEARDOWN = "alsatian:teardown";
exports.TEARDOWN = TEARDOWN;
var TEARDOWN_FIXTURE = "alsatian:teardown-fixture";
exports.TEARDOWN_FIXTURE = TEARDOWN_FIXTURE;
var TEST_CASES = "alsatian:testcases";

@@ -24,0 +28,0 @@ exports.TEST_CASES = TEST_CASES;

import { AsyncSetup } from "./async-setup-decorator";
import { AsyncSetupFixture } from "./async-setup-fixture-decorator";
import { AsyncTeardown } from "./async-teardown-decorator";
import { AsyncTeardownFixture } from "./async-teardown-fixture-decorator";
import { AsyncTest } from "./async-test-decorator";

@@ -9,3 +11,5 @@ import { FocusTest } from "./focus-test-decorator";

import { Setup } from "./setup-decorator";
import { SetupFixture } from "./setup-fixture-decorator";
import { Teardown } from "./teardown-decorator";
import { TeardownFixture } from "./teardown-fixture-decorator";
import { TestCase } from "./test-case-decorator";

@@ -15,2 +19,2 @@ import { Test } from "./test-decorator";

import { Timeout } from "./timeout-decorator";
export { AsyncSetup, AsyncTeardown, AsyncTest, FocusTest, FocusTests, IgnoreTest, IgnoreTests, Setup, Teardown, TestFixture, Test, TestCase, Timeout };
export { AsyncSetup, AsyncSetupFixture, AsyncTeardown, AsyncTeardownFixture, AsyncTest, FocusTest, FocusTests, IgnoreTest, IgnoreTests, Setup, SetupFixture, Teardown, TeardownFixture, TestFixture, Test, TestCase, Timeout };
"use strict";
var async_setup_decorator_1 = require("./async-setup-decorator");
exports.AsyncSetup = async_setup_decorator_1.AsyncSetup;
var async_setup_fixture_decorator_1 = require("./async-setup-fixture-decorator");
exports.AsyncSetupFixture = async_setup_fixture_decorator_1.AsyncSetupFixture;
var async_teardown_decorator_1 = require("./async-teardown-decorator");
exports.AsyncTeardown = async_teardown_decorator_1.AsyncTeardown;
var async_teardown_fixture_decorator_1 = require("./async-teardown-fixture-decorator");
exports.AsyncTeardownFixture = async_teardown_fixture_decorator_1.AsyncTeardownFixture;
var async_test_decorator_1 = require("./async-test-decorator");

@@ -18,4 +22,8 @@ exports.AsyncTest = async_test_decorator_1.AsyncTest;

exports.Setup = setup_decorator_1.Setup;
var setup_fixture_decorator_1 = require("./setup-fixture-decorator");
exports.SetupFixture = setup_fixture_decorator_1.SetupFixture;
var teardown_decorator_1 = require("./teardown-decorator");
exports.Teardown = teardown_decorator_1.Teardown;
var teardown_fixture_decorator_1 = require("./teardown-fixture-decorator");
exports.TeardownFixture = teardown_fixture_decorator_1.TeardownFixture;
var test_case_decorator_1 = require("./test-case-decorator");

@@ -22,0 +30,0 @@ exports.TestCase = test_case_decorator_1.TestCase;

import { ContentsMatchError } from "./contents-match-error";
import { EmptyMatchError } from "./empty-match-error";
import { EqualMatchError } from "./equal-match-error";

@@ -14,2 +15,2 @@ import { ErrorMatchError } from "./error-match-error";

import { TruthyMatchError } from "./truthy-match-error";
export { MatchError, ExactMatchError, EqualMatchError, RegexMatchError, TruthyMatchError, ContentsMatchError, LessThanMatchError, GreaterThanMatchError, ErrorMatchError, FunctionCallMatchError, FunctionCallCountMatchError, TestTimeoutError, PropertySetMatchError };
export { MatchError, ExactMatchError, EqualMatchError, RegexMatchError, TruthyMatchError, ContentsMatchError, LessThanMatchError, GreaterThanMatchError, ErrorMatchError, FunctionCallMatchError, FunctionCallCountMatchError, TestTimeoutError, PropertySetMatchError, EmptyMatchError };
"use strict";
var contents_match_error_1 = require("./contents-match-error");
exports.ContentsMatchError = contents_match_error_1.ContentsMatchError;
var empty_match_error_1 = require("./empty-match-error");
exports.EmptyMatchError = empty_match_error_1.EmptyMatchError;
var equal_match_error_1 = require("./equal-match-error");

@@ -5,0 +7,0 @@ exports.EqualMatchError = equal_match_error_1.EqualMatchError;

@@ -63,2 +63,6 @@ import { FunctionSpyMatcher } from "./matchers";

/**
* Checks that an array is empty, a string is empty, or an object literal has no properties
*/
toBeEmpty(): void;
/**
* Checks that a function throws an error when executed

@@ -65,0 +69,0 @@ */

@@ -153,2 +153,23 @@ "use strict";

/**
* Checks that an array is empty, a string is empty, or an object literal has no properties
*/
Matcher.prototype.toBeEmpty = function () {
if (null === this.actualValue || undefined === this.actualValue) {
throw new TypeError("toBeEmpty requires value passed in to Expect not to be null or undefined");
}
if (typeof this.actualValue === "string" || Array.isArray(this.actualValue)) {
if ((this.actualValue.length === 0) !== this.shouldMatch) {
throw new errors_1.EmptyMatchError(this.actualValue, this.shouldMatch);
}
}
else if (this.actualValue.constructor === Object) {
if ((Object.keys(this.actualValue).length === 0) !== this.shouldMatch) {
throw new errors_1.EmptyMatchError(this.actualValue, this.shouldMatch);
}
}
else {
throw new TypeError("toBeEmpty requires value passed in to Expect to be an array, string or object literal");
}
};
/**
* Checks that a function throws an error when executed

@@ -155,0 +176,0 @@ */

@@ -77,2 +77,3 @@ "use strict";

return __awaiter(this, void 0, void 0, function () {
var error_1;
return __generator(this, function (_a) {

@@ -86,10 +87,19 @@ switch (_a.label) {

_a.sent();
_a.label = 3;
case 3:
_a.trys.push([3, 6, , 8]);
return [4 /*yield*/, this._runTest(this._test.timeout || timeout)];
case 3:
case 4:
_a.sent();
return [4 /*yield*/, this._teardown()];
case 4:
case 5:
_a.sent();
_a.label = 5;
case 5: return [2 /*return*/];
return [3 /*break*/, 8];
case 6:
error_1 = _a.sent();
return [4 /*yield*/, this._teardown()];
case 7:
_a.sent();
throw error_1;
case 8: return [2 /*return*/];
}

@@ -96,0 +106,0 @@ });

@@ -15,2 +15,5 @@ import "reflect-metadata";

private _runTests(testSetRunInfo, results);
private _setupFixture(fixture);
private _teardownFixture(fixture);
private _runFixtureFunctions(fixture, metadataKey);
}

@@ -92,3 +92,3 @@ "use strict";

return __awaiter(this, void 0, void 0, function () {
var currentTestFixtureResults, currentTestResults, errorOccurredRunningTest, _loop_1, arguments_1, this_1, _i, _a, testItem;
var currentTestFixtureResults, currentTestResults, errorOccurredRunningTest, _loop_1, arguments_1, this_1, _i, _a, testItem, lastTestItem;
return __generator(this, function (_b) {

@@ -104,7 +104,15 @@ switch (_b.label) {

previousTestItem = testSetRunInfo.testPlan.testItems[testItemIndex - 1];
// if new fixture
if (!previousTestItem || previousTestItem.testFixture !== testItem.testFixture) {
this_1._outputStream.emitFixture(testItem.testFixture);
currentTestFixtureResults = results.addTestFixtureResult(testItem.testFixture);
}
if (!(!previousTestItem || previousTestItem.testFixture !== testItem.testFixture)) return [3 /*break*/, 4];
if (!previousTestItem) return [3 /*break*/, 2];
return [4 /*yield*/, this_1._teardownFixture(previousTestItem.testFixture.fixture)];
case 1:
_a.sent();
_a.label = 2;
case 2: return [4 /*yield*/, this_1._setupFixture(testItem.testFixture.fixture)];
case 3:
_a.sent();
this_1._outputStream.emitFixture(testItem.testFixture);
currentTestFixtureResults = results.addTestFixtureResult(testItem.testFixture);
_a.label = 4;
case 4:
// if new test

@@ -114,17 +122,17 @@ if (!previousTestItem || previousTestItem.test !== testItem.test) {

}
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
_a.label = 5;
case 5:
_a.trys.push([5, 7, , 8]);
return [4 /*yield*/, testItem.run(testSetRunInfo.timeout)];
case 2:
case 6:
_a.sent();
result = currentTestResults.addTestCaseResult(testItem.testCase.arguments_1);
errorOccurredRunningTest = null;
return [3 /*break*/, 4];
case 3:
return [3 /*break*/, 8];
case 7:
error_1 = _a.sent();
result = currentTestResults.addTestCaseResult(testItem.testCase.arguments_1, error_1);
errorOccurredRunningTest = error_1;
return [3 /*break*/, 4];
case 4:
return [3 /*break*/, 8];
case 8:
// emit onComplete event out of Alsatian if call back has been defined

@@ -162,2 +170,6 @@ if (this_1._onTestCompleteCBs) {

case 4:
lastTestItem = testSetRunInfo.testPlan.testItems[testSetRunInfo.testPlan.testItems.length - 1];
return [4 /*yield*/, this._teardownFixture(lastTestItem.testFixture.fixture)];
case 5:
_b.sent();
this._outputStream.end();

@@ -169,2 +181,55 @@ return [2 /*return*/];

};
TestRunner.prototype._setupFixture = function (fixture) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._runFixtureFunctions(fixture, alsatian_core_1.METADATA_KEYS.SETUP_FIXTURE)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
TestRunner.prototype._teardownFixture = function (fixture) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._runFixtureFunctions(fixture, alsatian_core_1.METADATA_KEYS.TEARDOWN_FIXTURE)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
TestRunner.prototype._runFixtureFunctions = function (fixture, metadataKey) {
return __awaiter(this, void 0, void 0, function () {
var fixtureFunctions, _i, fixtureFunctions_1, fixtureFunction;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fixtureFunctions = Reflect.getMetadata(metadataKey, fixture);
if (!fixtureFunctions) return [3 /*break*/, 5];
_i = 0, fixtureFunctions_1 = fixtureFunctions;
_a.label = 1;
case 1:
if (!(_i < fixtureFunctions_1.length)) return [3 /*break*/, 5];
fixtureFunction = fixtureFunctions_1[_i];
if (!fixtureFunction.isAsync) return [3 /*break*/, 3];
return [4 /*yield*/, fixture[fixtureFunction.propertyKey].call(fixture)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
fixture[fixtureFunction.propertyKey].call(fixture);
_a.label = 4;
case 4:
_i++;
return [3 /*break*/, 1];
case 5: return [2 /*return*/];
}
});
});
};
return TestRunner;

@@ -171,0 +236,0 @@ }());

@@ -33,5 +33,5 @@ "use strict";

TestLoader.prototype._loadTestFixture = function (testFixtureConstructor, defaultFixtureDescription) {
// get test fixture metadata or create new metadata
// to support not requiring the TestFixture decorator.
// This functionality will be removed in 2.0.0 where
// get test fixture metadata or create new metadata
// to support not requiring the TestFixture decorator.
// This functionality will be removed in 2.0.0 where
// TestFixture decorator will become mandatory

@@ -38,0 +38,0 @@ var testFixture = Reflect.getMetadata(alsatian_core_1.METADATA_KEYS.TEST_FIXTURE, testFixtureConstructor)

{
"name": "alsatian",
"version": "1.1.0",
"version": "1.2.0",
"description": "TypeScript and JavaScript testing framework for beautiful and readable tests",

@@ -5,0 +5,0 @@ "author": "James Richford <=> (=)",

<p id="banner" align="center">
<img src="https://github.com/alsatian-test/alsatian/raw/master/documentation/images/alsatian-mascot-logo.png" alt="Alsatian Mascot Logo" />
<p id="tag-line" align="center">Awesomely easy and useful TypeScript and JavaScript testing framework with test cases, compatible with <a href="https://github.com/alsatian-test/alsatian/wiki/using-alsatian-with-selenium">selenium</a>, istanbul and tap reporters.</p>
<p id="tag-line" align="center">Awesomely easy and useful TypeScript and JavaScript testing framework with test cases, compatible with <a href="https://github.com/alsatian-test/alsatian/wiki/using-alsatian-with-selenium">selenium</a>, <a href="https://github.com/alsatian-test/alsatian/wiki/check-test-coverage-with-nyc">coverage checkers</a> and <a href="https://github.com/alsatian-test/alsatian/wiki/using-alsatian-with-tap-reporters">TAP reporters</a>.</p>
</p>

@@ -35,790 +35,77 @@ <p id="badges" align="center">

## Why would I use Alsatian?
The key question! Well Alsatian has a lot going for it here are just a few great things to note:
## Quick Start
* All the awesome features you love from existing frameworks
* TestCase decorator allows you to write smaller, DRY and more readable tests
* No globals!
* TAP support so you can use your favourite TAP reporter
* Great CI process, every pull request and push on every branch is scrutinised to ensure high quality
* 100% coverage all statements, lines, branches are covered in Alsatian tests
* Various services rate us very highly on lots of different factors, check out our badges
* Everything is documented in a friendly and simple way to help you get to the unit test setup of your dreams
* Being written in TypeScript it fits perfectly into your TypeScript but still compatible with JavaScript too!
* Active support if you've got a question, a suggestion or found an issue let us know and we'll get back to you quickly
If you're loving TypeScript then pop on down to our [TypeScript Quick Start](https://github.com/alsatian-test/alsatian/wiki/typescript-setup).
Also it's lightning fast, watch it run all of it's unit tests in super quick time!
![Alsatian Test Run Video](https://github.com/alsatian-test/alsatian/raw/master/documentation/images/alsatian-test-run.gif)
Otherwise if you're more of a JavaScript kinda person, have a gander at our [JavaScript Quick Start](https://github.com/alsatian-test/alsatian/wiki/javascript-setup)
## Installing
Full documentation can be found on our [wiki](https://github.com/alsatian-test/alsatian/wiki/) the examples are usually in TypeScript but should be pretty much the same code for JavaScript (just lose the access modifiers and types).
Good news everybody, we're on NPM.
```
npm install alsatian
```
## Alsatian is different
## Use with JavaScript
Using a different approach than other JavaScript test frameworks allows us to use more powerful patterns.
If you're using JavaScript, no worries you can still use Alsatian with Babel. Currently there is no official support for decorators (see [babel issue](https://github.com/babel/babel#2645)) but you can use a plugin!
Add `transform-decorators-legacy` plugin
```
npm install babel-plugin-transform-decorators-legacy --save-dev
```
Then update your `.babelrc`
```
{
...
"plugins": ["transform-decorators-legacy"]
...
}
```
You should now be able to use Alsatian decorators as in all the examples below, Hooray!
## Running alsatian
### CLI
Alsatian has a CLI for easy use with your package.json or your favourite cli tool
```
alsatian [list of globs]
alsatian "./test/**/*.spec.js" "./special-test.js"
```
#### CLI Options
You can change how Alsatian runs your tests using the available options
| Option | Alias | Description |
| ------------------------- | ------ | ---------------------------------------------------------------------------- |
| --help | -h | Outputs info about how to use the CLI |
| --version | -v | Outputs the version of the CLI |
| --tap | -T | Will make Alsatian output in TAP format (to be consumed by a TAP reporter) |
| --timeout [number in ms] | -t | Sets the maximum time that a test can run for before failing (default 500ms) |
### Node.js
If you're more of a nodey person then you can use that too
```typescript
import { TestSet, TestRunner } from "alsatian";
import { TapBark } from "tap-bark";
// no globals and typing support out of the box with intellisense
import { AsyncTest, Expect, Test, TestCase, TestFixture } from "alsatian";
// create test set
const testSet = TestSet.create();
@TestFixture("whatever you'd like to call the fixture")
export class SetOfTests {
// use the async/await pattern in your tests as you would in your code
@AsyncTest("asychronous test")
public async asyncTest() {
const response = await somethingToHappen();
// add your tests
testSet.addTestsFromFiles("./tests/you-want/to-add/**/*.spec.js");
Expect(response).toBeDefined();
}
// create a test runner
const testRunner = new TestRunner();
// setup the output
testRunner.outputStream
// this will use alsatian's default output if you remove this
// you'll get TAP or you can add your favourite TAP reporter in it's place
.pipe(TapBark.create().getPipeable())
// pipe to the console
.pipe(process.stdout);
// run the test set
testRunner.run(testSet)
// this will be called after all tests have been run
.then((results) => done())
// this will be called if there was a problem
.catch((error) => doSomethingWith(error));
```
### Gulp
If instead you prefer to gulp it up you can write a task similar to how you'd work with Node.js
```typescript
import * as Gulp from "gulp";
import { TestSet, TestRunner } from "alsatian";
import { TapBark } from "tap-bark";
Gulp.task("test", (done: () => any) => {
// create test set
const testSet = TestSet.create();
// add your tests
testSet.addTestsFromFiles("./tests/you-want/to-add/**/*.spec.js");
// create a test runner
const testRunner = new TestRunner();
// setup the output
testRunner.outputStream
// this will use alsatian's default output if you remove this
// you'll get TAP or you can add your favourite TAP reporter in it's place
.pipe(TapBark.create().getPipeable())
// pipe to the console
.pipe(process.stdout);
// run the test set
testRunner.run(testSet)
// and tell gulp when we're done
.then(() => done());
});
```
## Using alsatian
Create your first spec file
```typescript
import { Expect, Test } from "alsatian";
export class ExampleTestFixture {
@Test()
public exampleTest() {
Expect(1 + 1).toBe(2);
}
}
```
Then check all is well
```
> alsatian "./path/to/example.spec.js"
TAP version 13
1..1
ok 1 - exampleTest
```
### Naming Tests
By default, tests will be named the same as their functions and fixtures will be named the same as their class. This will be what is output by alsatian. However, you can give the test or fixture more meaningful name simply by supplying the ```Test``` and ```TestFixture``` annotations with whatever you desire.
```typescript
import { Expect, Test, TestFixture } from "alsatian";
@TestFixture("Awesome Test Fixture")
export class ExampleTestFixture {
@Test("Confirm 1 + 1 is 2")
public test1() {
Expect(1 + 1).toBe(2);
}
}
```
Then check all is well
```
> alsatian ./path/to/example.spec
Awesome Test Fixture
Confirm 1 + 1 is 2
|====================|
Pass: 1/1
Fail: 0/1
Ignore: 0/1
```
### Test Cases
You can pass arguments to your tests simply by using the ```TestCase``` annotation
```typescript
import { Expect, TestCase, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@TestCase(1, 2)
@TestCase(4, 5)
public exampleTest(preIteratedValue: number, expected: number) {
Expect(preIteratedValue++).toBe(expected);
}
}
```
### Matchers
Now you've set up some tests, it's time to check your code is working. Let's start easy.
#### toBe
To be or not to be, that is the question! Simply put this checks whether actual === expected
```typescript
Expect(1 + 1).toBe(2);
Expect(1 + 1).not.toBe(3);
```
#### toEqual
Next we can check if it's pretty much the same actual == expected
```typescript
Expect("1").toEqual(1);
Expect(1 + 1).not.toEqual("3");
```
#### toMatch
Now a cheeky little regular expression if you don't mind
```typescript
Expect("something").toMatch(/some/);
Expect("another thing").not.toMatch(/something/);
```
#### toBeDefined
Is it there or not? actual !== undefined
```typescript
Expect("something").toBeDefined();
Expect(undefined).not.toBeDefined();
```
#### toBeNull
Is it something or not? actual === null
```typescript
Expect(null).toBeNull();
Expect("something").not.toBeNull();
```
#### toBeTruthy
Is it trueish? actual == trueish
```typescript
Expect(1).toBeTruthy();
Expect(0).not.toBeTruthy();
```
#### toContain
Does the string contain another string or an array contain an item?
```typescript
Expect("something").toContain("thing");
Expect([1, 2, 3]).toContain(2);
Expect("another thing").not.toContain("something");
Expect([1, 2, 3]).not.toContain(4);
```
#### toBeGreaterThan
Which one's larger (hopefully the actual)
```typescript
Expect(2).toBeGreaterThan(1);
Expect(1).not.toBeGreaterThan(2);
```
#### toBeLessThan
For when you don't want things to get out of control, check it's not too big
```typescript
Expect(1).toBeLessThan(2);
Expect(2).not.toBeLessThan(1);
```
#### toThrow
Check whether a function throws an error
```typescript
Expect(() => throw new Error()).toThrow();
Expect(() => {}).not.toThrow();
```
#### toThrowError
Check whether a function throws a specific error with a given message
```typescript
Expect(() => throw new TypeError("things went wrong")).toThrowError(TypeError, "things went wrong");
Expect(() => throw new Error("some error we don't care about")).not.toThrow(TypeError, "super nasty error");
```
### Spying
When we want to check functions are called, this is simple first we need to turn it into a spy...
```typescript
import { SpyOn } from "alsatian";
let some = {
function: () => {}
};
SpyOn(some, "function");
```
... then check it's been called ...
```typescript
Expect(some.function).toHaveBeenCalled();
```
... or check it's been called with certain arguments ...
```typescript
Expect(some.function).toHaveBeenCalledWith(this, "and that");
```
... or any arguments ...
```typescript
// you can use the Any function to signify an argument can be anything or any specific type
Expect(some.function).toHaveBeenCalledWith(Any, Any(Number), Any(String));
```
... or a specific number of times ...
```typescript
Expect(some.function).toHaveBeenCalled().exactly(42).times;
Expect(some.function).toHaveBeenCalledWith("something").anythingBut(10).times;
Expect(some.function).toHaveBeenCalledWith(Any).lessThan(5).times;
Expect(some.function).toHaveBeenCalledWith(Any(Number), Any(Array)).greaterThan(2).times;
// Note that this functionality must not be used with the not operator
// e.g. the following throws an error
Expect(some.function).not.toHaveBeenCalled().lessThan(42).times;
// this should be written
Expect(some.function).toHaveBeenCalled().greaterThan(41).times;
```
... you can stub it out ...
```typescript
SpyOn(some, "function").andStub();
```
... you can make it call something else ...
```typescript
SpyOn(some, "function").andCall(() => {
console.log("I are called"); // make it do whatever you like
return "whatever you like"; // and also return stuff too!
});
```
... or make it return whatever you desire ...
```typescript
SpyOn(some, "function").andReturn(42);
```
... and even return it to how it started
```typescript
SpyOn(some, "function");
some.function.restore();
// OR
const spy = SpyOn(some, "function");
spy.restore();
```
#### Creating a spy from thin air
You may want to just create a fake spy property this is easy to do and has all the same functionality as a Spy created through ```SpyOn```
```typescript
import { FunctionSpy } from "alsatian";
const spy = new FunctionSpy();
```
#### Spying on a property
Similarly to spying on functions you can also spy on properties as below ...
```typescript
import { SpyOnProperty } from "alsatian";
class Test {
private _property: number = 42;
get property() {
return this._property;
}
set property(value: number) {
this._property = value;
}
}
const test = new Test();
SpyOnProperty(test, "property");
```
... then check it's been set ...
```typescript
const propertySpy = SpyOnProperty(test, "property");
// unlike function spies expect calls on property spies
// only works using the returned spy from SpyOnProperty
// and not the property itself
Expect(propertySpy).toHaveBeenSet();
```
... or check it's been set to a specific value ...
```typescript
Expect(propertySpy).toHaveBeenSetTo(42);
```
... add a fake getter ...
```typescript
SpyOnProperty(test, "property").andCallGetter(() => { return "something"; });
```
... or setter ...
```typescript
SpyOnProperty(test, "property").andCallSetter((value: any) => { doSomethingWith(value); });
```
... return a set value ...
```typescript
SpyOnProperty(test, "property").andReturnValue(42);
```
... and restore it to how it was before
```typescript
const properySpy = SpyOnProperty(test, "property");
properySpy.restore();
```
### Async Tests
You can also have asynchronous tests using the ```AsyncTest``` annotation,
```typescript
import { Expect, AsyncTest, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@AsyncTest()
public async asyncTest() {
const result = await somethingToHappen();
Expect(result).toBe(1);
}
}
```
If you can't use the async/await syntax then fear not you can use a promise!
```typescript
import { Expect, AsyncTest, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@AsyncTest()
public asyncTest() {
return new Promise((resolve, reject) => {
waitForSomethingToHappen((result: number) => {
Expect(result).toBe(1);
resolve();
});
});
}
}
```
Alsatian will fail an ```AsyncTest``` if it takes longer than 500 ms to execute. You can change this if you need to though using the ```Timeout``` decorators
```typescript
import { Expect, AsyncTest, Timeout, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@AsyncTest()
@Timeout(5000) // Alsatian will now wait 5 seconds before failing
public async asyncTest() {
const result = await somethingThatTakesAlmostFiveSeconds();
Expect(result).toBe(1);
}
}
```
### Ignoring Tests
You can stop tests from being run by using the ```IgnoreTest``` annotation
```typescript
import { Expect, Test, IgnoreTest, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Test()
@IgnoreTest()
public ignoredTest() {
Expect(1).toBe(1);
}
}
```
or you can stop all tests in a given fixture from running using the ```IgnoreTests``` annotation
```typescript
import { Expect, Test, IgnoreTests, TestFixture } from "alsatian";
@IgnoreTests()
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Test()
public thisTestWillNotBeRun() {
Expect(1).toBe(1);
}
@Test()
public neitherWillThisOne() {
Expect(1).toBe(1);
}
}
```
You can provide a reason to both of these, which will put it into the TAP output.
```typescript
import { Expect, Test, IgnoreTest, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Test()
@IgnoreTest("This test is useless, ignore for now.")
public ignoredTest() {
Expect(1).toBe(1);
}
}
```
### Focusing Tests
You can run a single test or select tests using the ```FocusTest``` annotation
```typescript
import { Expect, Test, FocusTest, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Test()
@FocusTest
public thisTestWillBeRun() {
Expect(1).toBe(1);
}
@Test()
public thisTestWillNotBeRun() {
Expect(1).toBe(1);
}
}
```
or you can run only tests in this fixture using the ```FocusTests``` annotation
```typescript
import { Expect, Test, FocusTests, TestFixture } from "alsatian";
@FocusTests
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Test()
public thisTestWillBeRun() {
Expect(1).toBe(1);
}
@Test()
public soWillThisTest() {
Expect(1).toBe(1);
}
}
```
### Setup
You can get a function to be run before every function in the fixture using the ```Setup``` decorators
```typescript
import { Expect, Test, Setup, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Setup
public thisFunctionWillBeRunBeforeAllTests() {
// do some setup work
}
@Test()
public exampleTest() {
Expect(1).toBe(1);
}
}
```
### Teardown
You can also run functions after every test has completed using the ```Teardown``` decorators
```typescript
import { Expect, Test, Teardown, TestFixture } from "alsatian";
@TestFixture("Example Test Fixture")
export class ExampleTestFixture {
@Teardown
public thisFunctionWillBeRunAfterAllTests() {
// do some teardown work
}
@Test()
public exampleTest() {
Expect(1).toBe(1);
}
}
```
### Extending Expect
Extending the Expect call in Alsatian is super simple as it's OO and extensible by default! All you need to do is extend...
```typescript
class MatcherExtension extends Matcher {
isSomething() {
if (this.actualValue !== "something") {
throw new MatchError("should have been something", "something", "not something");
}
// pass arguments into your test functions to keep your test code from being repetative
@TestCase(2, 2, 4)
@TestCase(2, 3, 5)
@TestCase(3, 3, 6)
@Test("addition tests")
public addTest(firstNumber: number, secondNumber: number, expectedSum: number) {
Expect(firstNumber + secondNumber).toBe(expectedSum);
}
}
```
Then if you want to you can wrap it in a function to add some neat fluent syntax
```typescript
// name it whatever your heart desires
export ExtendedExpect = (value: any) => new MatcherExtension(value);
```
Here's an explanation of some of the concepts that are useful here
## Why would I use Alsatian?
#### this.actualValue
The key question! Well Alsatian has a lot going for it here are just a few great things to note:
This is the value that is added into the Matcher constructor / Expect function i.e. the value under test
* All the awesome features you love from existing frameworks
* The [TestCase](https://github.com/alsatian-test/alsatian/wiki/test-structure#test-cases) decorator allows you to write smaller, DRY and more readable tests
* No globals!
* TAP support so you can use your favourite TAP reporter
* Great CI process, every pull request and push on every branch is scrutinised to ensure high quality
* 100% coverage all statements, lines, branches are covered in Alsatian tests
* Various services rate us very highly on lots of different factors, check out our badges
* Everything is documented in a friendly and simple way to help you get to the unit test setup of your dreams
* Being written in TypeScript it fits perfectly into your TypeScript but still compatible with JavaScript too!
* Active support - if you've got a question, a suggestion or found an issue let us know and we'll get back to you quickly
#### this.shouldMatch
Also it's lightning fast, watch it run all of it's unit tests in super quick time!
![Alsatian Test Run Video](https://github.com/alsatian-test/alsatian/raw/master/documentation/images/alsatian-test-run.gif)
This indicates whether the not opperator has been used
## Besides unit tests, what can I do with Alsatian
```typescript
Expect(something).toBe(nothing); // this.shouldMatch === true
Expect(something).not.toBe(nothing); // this.shouldMatch === false
```
So many awesome things!
* write end to end tests with [Selenium](https://github.com/alsatian-test/alsatian/wiki/using-alsatian-with-selenium)
* check your code coverage with [NYC](https://github.com/alsatian-test/alsatian/wiki/check-test-coverage-with-nyc)
* set up a wonderful CI process and give confidence in the quality of your product
* have the output look however you desire using [TAP reporters](https://github.com/alsatian-test/alsatian/wiki/using-alsatian-with-tap-reporters)
#### MatchError
## Support
Throwing this error will tell Alsatian that the test found something wrong (you can extend this too). It has three arguments, the actual value, the expected value and a message. A usage example can be found below.
If at any time things are unclear or you think there may be something going wrong feel free to [raise an issue](https://github.com/alsatian-test/alsatian/issues/new) and we'll be glad to get back to you with a solution quickly.
```typescript
throw new MatchError(
"expected nothing to be something, but it wasn't.", // an explanation of the issue
"something", // what the value was expected to be
"nothing" // what the value actually was
);
```
## Contributing
You may also set each value independently if you extend them (as the setters are protected)
We're always glad to have help out with Alsatian, check out the [guidelines](https://github.com/alsatian-test/alsatian/blob/master/CONTRIBUTING.md)
```typescript
export class ExtendedMatchError {
public constructor() {
super();
this.message = "expected nothing to be something, but it wasn't.";
this._expected = "something";
this._actual = "nothing";
}
}
```
## License
#### Example assertion function
```typescript
public toBeHexCode() {
// check whether the value provided in Expect() is a hex code or not
const isHexCode = /^#[A-F|0-9]{6}$/i.test(this.actualValue);
// if the value should have been a hex code and wasn't
// or should not have been and was
if (isHexCode !== this.shouldMatch) {
// output for Alsatian that it should have been a hex code
if (this.shouldMatch) {
throw new MatchError(
`expected {this.actualValue} to be a hex code but it wasn't.`,
"a hex code",
"not a hex code"
);
}
// output for Alsatian that it should not have been a hex code
else {
throw new MatchError(
`expected {this.actualValue} to not be a hex code but it wasn't.`,
"not a hex code",
"a hex code"
);
}
}
}
```
#### usage
Now you're ready to use your extended ```Expect```. This is super easy...
```typescript
import { ExtendedExpect as Expect } from "./your/extended-expect/location";
import { TestFixture, Test } from "alsatian";
@TestFixture("color tests")
export default class ColorTestFixture {
@Test("check hexcodes")
public checkHexcodes {
Expect("#00000").toBeHexCode();
}
}
```
Alsatian has been released under the [MIT license](https://github.com/alsatian-test/alsatian/blob/master/LICENSE)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc