Programming

Introducing TypeSpec

TypeSpec Browser OuputHaving completed the MVP roadmap, TypeSpec is now available to use.

TypeSpec is a BDD framework for TypeScript designed to work with separate specifications written in the Given-When-Then style. It works in the browser (real or ghost), and on Node.

You can grab it from NuGet:

PM> Install-Package TypeSpec 

You can grap it from NPM:

npm install typespec-bdd

If you are familiar with BDD from frameworks such as SpecFlow, Cucumber, or similar – you’ll find a familiar set of tools that you can apply straight to TypeScript.

  • Features, Scenarios, and Scenario Outlines
  • Scenario tagging
  • Given, When, Then style specifications (in their own file)
  • Step definitions, and comprehensive step definition hinting for missing steps

Here is a feature taken from the TypeSpec test suite:

Feature: Scenario Outline
       In order to make features less verbose
       As a BDD enthusiast
       I want to use scenario outlines with tables of examples

@passing
Scenario Outline: Basic Example with Calculator
       Given I am using a calculator
       And I enter "<Number 1>" into the calculator
       And I enter "<Number 2>" into the calculator
       When I press the total button
       Then the result should be "<Total>" on the screen

Examples:
    | Number 1 | Number 2 | Total |
    | 1        | 1        | 2     |
    | 1        | 2        | 3     |
    | 2        | 3        | 5     |
    | 8        | 3        | 11    |
    | 9        | 8        | 17    |

And here is the full set of steps that covers this feature (and quite a few others). You should be able to spot a few features in here, from the test context that allows you to share data between test classes, to the simple expressions used to match conditions in the test, to the assertions that ship with TypeSpec.

import { Assert, given, when, then } from './TypeSpec/TypeSpec';

export interface CalculatorTestContext {
	done: () => void; // Standard TypeSpec aync done method.
	calculator: Calculator;
}

export class CalculatorSteps {
	@given(/^I am using a calculator$/i)
	usingACalculator(context: CalculatorTestContext) {
		context.calculator = new Calculator();
	}

	@given(/^I have entered (\"\d+\") into the calculator$/i)
	passingArguments(context: CalculatorTestContext, num: number) {
		calculator.add(num);
	}

	@when(/^I press the total button$/gi)
	pressTotal() {
	}

	@then(/^the result should be (\"\d+\") on the screen$/i)
	resultShouldBe(context: CalculatorTestContext, expected: number) {
		var actual = context.calculator.getTotal();
		Assert.areIdentical(expected, actual);
	}
}

The context is entirely dynamic, but by supplying an interface for it, you can get the compiler to catch mistakes for you.

The decorators allow your step definitions to be automatically collected. This means you can run your tests by simply pointing out where the specifications are located (you can pass in as many specification files as you like).

import { AutoRunner } from './Scripts/TypeSpec/TypeSpec';

import './CalculatorSteps';

AutoRunner.run(
    '/Specifications/Basic.txt'
);

Grab TypeSpec from NuGet or NPM or check out TypeSpec on GitHub, fork it, use it, raise issues (preferably with acceptance criteria in Given-When-Then syntax).