diff --git a/expect/expect-tests.ts b/expect/expect-tests.ts
new file mode 100644
index 000000000..a0d2bf792
--- /dev/null
+++ b/expect/expect-tests.ts
@@ -0,0 +1,695 @@
+///
+///
+
+import expect,
+ {Expectation, Extension, Spy, createSpy, isSpy, assert, spyOn, extend, restoreSpies}
+ from 'expect';
+
+describe('chaining assertions', function () {
+ it('should allow chaining for array-like applications', function () {
+ expect([ 1, 2, 'foo', 3 ])
+ .toExist()
+ .toBeAn(Array)
+ .toInclude('foo')
+ .toExclude('bar')
+ })
+
+ it('should allow chaining for number checking', function () {
+ expect(3.14)
+ .toExist()
+ .toBeLessThan(4.2)
+ .toBeGreaterThan(3.0)
+ })
+})
+describe('createSpy', function () {
+ describe('when given a function', function () {
+ it('returns a spy function', function () {
+ const spy = createSpy(function () {})
+ expect(spy).toBeA(Function)
+ })
+ })
+})
+
+describe('A spy', function () {
+ let targetContext:any, targetArguments:any;
+ const target = {
+ method: function () {
+ targetContext = this
+ targetArguments = Array.prototype.slice.call(arguments, 0)
+ }
+ }
+
+ let spy:any;
+
+ it('is a spy', function () {
+ expect(isSpy(spy)).toBe(true)
+ })
+
+ it('has a destroy method', function () {
+ expect(spy.destroy).toBeA(Function)
+ })
+
+ it('has a restore method', function () {
+ expect(spy.restore).toBeA(Function)
+ })
+
+ it('knows how many times it has been called', function () {
+ spy()
+ spy()
+ expect(spy.calls.length).toEqual(2)
+ })
+
+ it('knows the arguments it was called with', function () {
+ spy(1, 2, 3)
+ expect(spy).toHaveBeenCalledWith(1, 2, 3)
+ })
+
+ describe('that calls some other function', function () {
+ let otherContext:any, otherArguments:any;
+ function otherFn() {
+ otherContext = this
+ otherArguments = Array.prototype.slice.call(arguments, 0)
+ }
+
+ beforeEach(function () {
+ spy.andCall(otherFn)
+ otherContext = otherArguments = null
+ })
+
+ it('calls that function', function () {
+ spy()
+ expect(otherContext).toNotBe(null)
+ })
+
+ it('uses the correct context', function () {
+ const context = {}
+ spy.call(context)
+ expect(otherContext).toBe(context)
+ })
+
+ it('passes the arguments through', function () {
+ spy(1, 2, 3)
+ expect(otherArguments).toEqual([ 1, 2, 3 ])
+ })
+ })
+
+ describe('that calls through', function () {
+ beforeEach(function () {
+ spy.andCallThrough()
+ })
+
+ it('calls the original function', function () {
+ spy()
+ expect(targetContext).toNotBe(null)
+ })
+
+ it('uses the correct context', function () {
+ const context = {}
+ spy.call(context)
+ expect(targetContext).toBe(context)
+ })
+
+ it('passes the arguments through', function () {
+ spy(1, 2, 3)
+ expect(targetArguments).toEqual([ 1, 2, 3 ])
+ })
+ })
+
+ describe('with a thrown value', function () {
+ beforeEach(function () {
+ spy.andThrow('hello')
+ })
+
+ it('throws the correct value', function () {
+ expect(spy).toThrow('hello')
+ })
+ })
+
+ describe('with a return value', function () {
+ beforeEach(function () {
+ spy.andReturn('hello')
+ })
+
+ it('returns the correct value', function () {
+ expect(spy()).toEqual('hello')
+ })
+ })
+})
+describe('expect.extend', function () {
+ const ColorAssertions:Extension = {
+ toBeAColor() {
+ assert(
+ this.actual.match(/^#[a-fA-F0-9]{6}$/),
+ 'expected %s to be an HTML color',
+ this.actual
+ )
+ }
+ }
+
+ let assertSpy:Spy;
+ beforeEach(function () {
+ extend(ColorAssertions)
+ assertSpy = spyOn(expect, 'assert')
+ })
+
+ afterEach(function () {
+ assertSpy.restore()
+ })
+
+ it('works', function () {
+ interface ColorExpectation extends Expectation {
+ toBeAColor():Expectation;
+ }
+ (expect('#ff00ff')).toBeAColor()
+ expect(assertSpy).toHaveBeenCalled()
+ })
+})
+
+describe('restoreSpies', function () {
+ describe('with one spy', function () {
+ const original = function () {}
+ const target = { method: original }
+
+ beforeEach(function () {
+ spyOn(target, 'method')
+ })
+
+ it('works with spyOn()', function () {
+ expect(target.method).toNotEqual(original)
+ restoreSpies()
+ expect(target.method).toEqual(original)
+ })
+
+ it('is idempotent', function () {
+ expect(target.method).toNotEqual(original)
+ restoreSpies()
+ restoreSpies()
+ expect(target.method).toEqual(original)
+ })
+
+ it('can work even on createSpy()', function () {
+ createSpy(original)
+ restoreSpies()
+ })
+ })
+
+ describe('with multiple spies', function () {
+ const originals = [ function () {}, function () {} ]
+ const targets = [
+ { method: originals[0] },
+ { method: originals[1] }
+ ]
+
+ it('still works', function () {
+ spyOn(targets[0], 'method')
+ spyOn(targets[1], 'method')
+
+ expect(targets[0].method).toNotEqual(originals[0])
+ expect(targets[1].method).toNotEqual(originals[1])
+
+ restoreSpies()
+
+ expect(targets[0].method).toEqual(originals[0])
+ expect(targets[1].method).toEqual(originals[1])
+ })
+ })
+})
+
+describe('A function that was spied on', function () {
+ const video = {
+ play: function () {}
+ }
+
+ let spy:Spy;
+ beforeEach(function () {
+ spy = spyOn(video, 'play')
+ })
+
+ it('tracks the number of calls', function () {
+ expect(spy.calls.length).toEqual(1)
+ })
+
+ it('tracks the context that was used', function () {
+ expect(spy.calls[0].context).toBe(video)
+ })
+
+ it('tracks the arguments that were used', function () {
+ expect(spy.calls[0].arguments).toEqual([ 'some', 'args' ])
+ })
+
+ it('was called', function () {
+ expect(spy).toHaveBeenCalled()
+ })
+
+ it('was called with the correct args', function () {
+ expect(spy).toHaveBeenCalledWith('some', 'args')
+ })
+
+ it('can be restored', function () {
+ expect(video.play).toEqual(spy)
+ spy.restore()
+ expect(video.play).toNotEqual(spy)
+ })
+})
+
+describe('A function that was spied on but not called', function () {
+ const video = {
+ play: function () {}
+ }
+
+ let spy:Spy;
+ beforeEach(function () {
+ spy = spyOn(video, 'play')
+ })
+
+ it('number of calls to be zero', function () {
+ expect(spy.calls.length).toEqual(0)
+ })
+
+ it('was not called', function () {
+ expect(spy).toNotHaveBeenCalled()
+ })
+})
+
+describe('toBeA', function () {
+ it('requires the value to be a function or string', function () {
+ expect(function () {
+ expect('actual').toBeA(4)
+ }).toThrow(/must be a function or a string/)
+ })
+
+ it('does not throw when the actual value is an instanceof the constructor', function () {
+ expect(function () {
+ expect(new Expectation('foo')).toBeA(Expectation)
+ }).toNotThrow()
+ })
+
+ it('throws when the actual value is not an instanceof the constructor', function () {
+ expect(function () {
+ expect('actual').toBeA(Expectation)
+ }).toThrow(/to be/)
+ })
+
+ it('does not throw when the expected value is the typeof the actual value', function () {
+ expect(function () {
+ expect(4).toBeA('number')
+ expect(NaN).toBeA('number') // hahaha
+ }).toNotThrow()
+ })
+
+ it('throws when the expected value is not the typeof the actual value', function () {
+ expect(function () {
+ expect('actual').toBeA('number')
+ }).toThrow(/to be/)
+ })
+
+ it('does not throw when the actual value is an array', function () {
+ expect(function () {
+ expect([]).toBeAn('array')
+ }).toNotThrow()
+ })
+
+ it('throws when the actual value is not an array', function () {
+ expect(function () {
+ expect('actual').toBeAn('array')
+ }).toThrow(/to be/)
+ })
+})
+
+describe('toBeGreaterThan', function () {
+ it('does not throw when the actual value is greater than the expected value', function () {
+ expect(function () {
+ expect(3).toBeGreaterThan(2)
+ }).toNotThrow()
+ })
+
+ it('throws when the actual value is not greater than the expected value', function () {
+ expect(function () {
+ expect(2).toBeGreaterThan(3)
+ }).toThrow(/to be greater than/)
+ })
+})
+
+
+describe('toBeLessThan', function () {
+ it('does not throw when the actual value is less than the expected value', function () {
+ expect(function () {
+ expect(2).toBeLessThan(3)
+ }).toNotThrow()
+ })
+
+ it('throws when the actual value is not less than the expected value', function () {
+ expect(function () {
+ expect(3).toBeLessThan(2)
+ }).toThrow(/to be less than/)
+ })
+})
+
+describe('toBeTruthy', function () {
+ it('does not throw on truthy actual values', function () {
+ expect(function () {
+ expect(1).toBeTruthy()
+ expect({ hello: 'world' }).toBeTruthy()
+ expect([ 1, 2, 3 ]).toBeTruthy()
+ }).toNotThrow()
+ })
+
+ it('throws on falsy actual values', function () {
+ expect(function () {
+ expect(0).toBeTruthy()
+ }).toThrow()
+
+ expect(function () {
+ expect(null).toBeTruthy()
+ }).toThrow()
+
+ expect(function () {
+ expect(undefined).toBeTruthy()
+ }).toThrow()
+ })
+})
+
+describe('toBeFalsy', function () {
+ it('throws on truthy values', function () {
+ expect(function () {
+ expect(42).toBeFalsy()
+ }).toThrow()
+
+ expect(function () {
+ expect({ foo: 'bar' }).toBeFalsy()
+ }).toThrow()
+
+ expect(function () {
+ expect([]).toBeFalsy()
+ }).toThrow()
+ })
+
+ it('does not throw with falsy actual values', function () {
+ expect(function () {
+ expect(0).toBeFalsy()
+ expect(null).toBeFalsy()
+ expect(undefined).toBeFalsy()
+ }).toNotThrow()
+ })
+})
+
+describe('toEqual', function () {
+ it('works', function () {
+ expect(function () {
+ expect('actual').toEqual('expected')
+ }).toThrow(/Expected 'actual' to equal 'expected'/)
+ })
+
+ it('works with objects that have the same keys in different order', function () {
+ const a = { a: 'a', b: 'b', c: 'c' }
+ const b = { b: 'b', c: 'c', a: 'a' }
+ expect(a).toEqual(b)
+ })
+
+ it('shows diff', function () {
+ try {
+ expect('actual').toEqual('expected')
+ } catch (err) {
+ expect(err.actual).toEqual('actual')
+ expect(err.expected).toEqual('expected')
+ expect(err.showDiff).toEqual(true)
+ }
+ })
+})
+
+describe('toExclude', function () {
+ it('requires the actual value to be an array or string', function () {
+ expect(function () {
+ expect(1).toExclude(2)
+ }).toThrow(/must be an array or a string/)
+ })
+
+ it('does not throw when an array does not contain the expected value', function () {
+ expect(function () {
+ expect([ 1, 2, 3 ]).toExclude(4)
+ }).toNotThrow()
+ })
+
+ it('throws when an array contains the expected value', function () {
+ expect(function () {
+ expect([ 1, 2, 3 ]).toExclude(2)
+ }).toThrow(/to exclude/)
+ })
+
+ it('does not throw when an array does not contain the expected value', function () {
+ expect(function () {
+ expect('hello world').toExclude('goodbye')
+ }).toNotThrow()
+ })
+
+ it('throws when a string contains the expected value', function () {
+ expect(function () {
+ expect('hello world').toExclude('hello')
+ }).toThrow(/to exclude/)
+ })
+})
+
+describe('toExist', function () {
+ it('does not throw on truthy actual values', function () {
+ expect(function () {
+ expect(1).toExist()
+ expect({ 'hello': 'world' }).toExist()
+ expect([ 1, 2, 3 ]).toExist()
+ }).toNotThrow()
+ })
+
+ it('throws on falsy actual values', function () {
+ expect(function () {
+ expect(0).toExist()
+ }).toThrow()
+
+ expect(function () {
+ expect(null).toExist()
+ }).toThrow()
+
+ expect(function () {
+ expect(undefined).toExist()
+ }).toThrow()
+ })
+})
+
+describe('toNotExist', function () {
+ it('throws on truthy values', function () {
+ expect(function () {
+ expect(42).toNotExist()
+ }).toThrow()
+
+ expect(function () {
+ expect({ foo: 'bar' }).toNotExist()
+ }).toThrow()
+
+ expect(function () {
+ expect([]).toNotExist()
+ }).toThrow()
+ })
+
+ it('does not throw with falsy actual values', function () {
+ expect(function () {
+ expect(0).toNotExist()
+ expect(null).toNotExist()
+ expect(undefined).toNotExist()
+ }).toNotThrow()
+ })
+})
+
+describe('toInclude', function () {
+ it('requires the actual value to be an array or string', function () {
+ expect(function () {
+ expect(1).toInclude(2)
+ }).toThrow(/must be an array or a string/)
+ })
+
+ it('does not throw when an array contains an expected integer', function () {
+ expect(function () {
+ expect([ 1, 2, 3 ]).toInclude(2)
+ expect([ { a: 1 }, { c: 2 } ]).toInclude({ c: 2 })
+ }).toNotThrow()
+ })
+
+ it('does not throw when an array contains an expected object', function () {
+ expect(function () {
+ expect([ { a: 1 }, { c: 2 } ]).toInclude({ c: 2 })
+ }).toNotThrow()
+ })
+
+ it('throws when an array does not contain an expected integer', function () {
+ expect(function () {
+ expect([ 1, 2, 3 ]).toInclude(4)
+ }).toThrow(/to include/)
+ })
+
+ it('throws when an array does not contain an expected object', function () {
+ expect(function () {
+ expect([ { a: 1 }, { c: 2 } ]).toInclude({ a: 2 })
+ }).toThrow(/to include/)
+ })
+
+ it('does not throw when a string contains the expected value', function () {
+ expect(function () {
+ expect('hello world').toInclude('world')
+ }).toNotThrow()
+ })
+
+ it('throws when a string does not contain the expected value', function () {
+ expect(function () {
+ expect('hello world').toInclude('goodbye')
+ }).toThrow(/to include/)
+ })
+})
+
+describe('toMatch', function () {
+ it('requires the pattern to be a RegExp', function () {
+ expect(function () {
+ expect('actual').toMatch('expected')
+ }).toThrow(/must be a RegExp/)
+ })
+
+ it('does not throw when the actual value matches the pattern', function () {
+ expect(function () {
+ expect('actual').toMatch(/^actual$/)
+ }).toNotThrow()
+ })
+
+ it('throws when the actual value does not match the pattern', function () {
+ expect(function () {
+ expect('actual').toMatch(/nope/)
+ }).toThrow(/to match/)
+ })
+})
+
+describe('toNotMatch', function () {
+ it('requires the pattern to be a RegExp', function () {
+ expect(function () {
+ expect('actual').toNotMatch('expected')
+ }).toThrow(/must be a RegExp/)
+ })
+
+ it('does not throw when the actual value does not match the pattern', function () {
+ expect(function () {
+ expect('actual').toNotMatch(/nope/)
+ }).toNotThrow()
+ })
+
+ it('throws when the actual value matches the pattern', function () {
+ expect(function () {
+ expect('actual').toNotMatch(/^actual$/)
+ }).toThrow(/to not match/)
+ })
+})
+
+describe('toNotEqual', function () {
+ it('works with arrays of objects', function () {
+ const a = [
+ {
+ id: 0,
+ text: 'Array Object 0',
+ boo: false
+ },
+ {
+ id: 1,
+ text: 'Array Object 1',
+ boo: false
+ }
+ ]
+
+ const b = [
+ {
+ id: 0,
+ text: 'Array Object 0',
+ boo: true // value of boo is changed to true here
+ },
+ {
+ id: 1,
+ text: 'Array Object 1',
+ boo: false
+ }
+ ]
+
+ expect(a).toNotEqual(b)
+ })
+
+ if (typeof Map !== 'undefined') {
+ it('works with Map', function () {
+ const a = new Map()
+ a.set('key', 'value')
+
+ const b = new Map()
+ b.set('key', 'another value')
+
+ expect(a).toNotEqual(b)
+ })
+ }
+
+ if (typeof Set !== 'undefined') {
+ it('works with Set', function () {
+ const a = new Set()
+ a.add('a')
+
+ const b = new Set()
+ b.add('b')
+
+ expect(a).toNotEqual(b)
+ })
+ }
+})
+
+describe('withArgs', function () {
+ const fn = function (arg1:any, arg2:any) {
+ if (arg1 === 'first' && typeof arg2 === 'undefined') {
+ throw new Error('first arg found')
+ }
+ if (arg1 === 'first' && arg2 === 'second') {
+ throw new Error('both args found')
+ }
+ }
+
+ it('invokes actual function with args', function () {
+ expect(function () {
+ expect(fn).withArgs('first').toThrow(/first arg found/)
+ }).toNotThrow()
+ })
+
+ it('can be chained', function () {
+ expect(function () {
+ expect(fn).withArgs('first').withArgs('second').toThrow(/both args found/)
+ }).toNotThrow()
+ })
+
+ it('throws when actual is not a function', function () {
+ expect(function () {
+ expect('not a function').withArgs('first')
+ }).toThrow(/must be a function/)
+ })
+})
+
+describe('withContext', function () {
+ const context = {
+ check: true
+ }
+ const fn = function (arg:any) {
+ if (this.check && typeof arg === 'undefined') {
+ throw new Error('context found')
+ }
+ if (this.check && arg === 'good') {
+ throw new Error('context and args found')
+ }
+ }
+
+ it('calls function with context', function () {
+ expect(function () {
+ expect(fn).withContext(context).toThrow(/context found/)
+ }).toNotThrow()
+ })
+
+ it('calls function with context and args', function () {
+ expect(function () {
+ expect(fn).withContext(context).withArgs('good').toThrow(/context and args found/)
+ }).toNotThrow()
+ })
+
+})
diff --git a/expect/expect-tests.ts.tscparams b/expect/expect-tests.ts.tscparams
new file mode 100644
index 000000000..a0f279051
--- /dev/null
+++ b/expect/expect-tests.ts.tscparams
@@ -0,0 +1 @@
+--noImplicitAny --target es6
diff --git a/expect/expect.d.ts b/expect/expect.d.ts
new file mode 100644
index 000000000..8d3cdc0d8
--- /dev/null
+++ b/expect/expect.d.ts
@@ -0,0 +1,88 @@
+// Type definitions for Expect v1.13.4
+// Project: https://github.com/mjackson/expect
+// Definitions by: Justin Reidy
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare module "expect" {
+ export class Expectation {
+ constructor(actual:any);
+ toExist(message?:string):Expectation;
+ toBeTruthy(message?:string):Expectation;
+ toNotExist(message?:string):Expectation;
+ toBeFalsy(message?:string):Expectation;
+ toBe(value:any, message?:string):Expectation;
+ toNotBe(value:any, message?:string):Expectation;
+ toEqual(value:any, message?:string):Expectation;
+ toNotEqual(value:any, message?:string):Expectation;
+ toThrow(value?:any, message?:string):Expectation;
+ toNotThrow(value?:any, message?:string):Expectation;
+ toBeA(value:any, message?:string):Expectation;
+ toBeAn(value:any, message?:string):Expectation;
+ toNotBeA(value:any, message?:string):Expectation;
+ toNotBeAn(value:any, message?:string):Expectation;
+ toMatch(value:any, message?:string):Expectation;
+ toNotMatch(value:any, message?:string):Expectation;
+ toBeLessThan(value:any, message?:string):Expectation;
+ toBeFewerThan(value:any, message?:string):Expectation;
+ toBeGreaterThan(value:any, message?:string):Expectation;
+ toBeMoreThan(value:any, message?:string):Expectation;
+ toInclude(value:any, compareValues?:any, message?:string):Expectation;
+ toContain(value:any, compareValues?:any, message?:string):Expectation;
+ toExclude(value:any, compareValues?:any, message?:string):Expectation;
+ toNotContain(value:any, compareValues?:any, message?:string):Expectation;
+ toHaveBeenCalled(message?:string):Expectation;
+ toHaveBeenCalledWith(...args:Array):Expectation;
+ toNotHaveBeenCalled(message?:string):Expectation;
+ withContext(context:any):Expectation;
+ withArgs(...args:Array):Expectation;
+ }
+
+ export interface Extension {
+ [name:string]:(args?:Array) => void;
+ }
+
+ export interface Call {
+ context: Spy;
+ arguments: Array;
+ }
+
+ export interface Spy {
+ __isSpy:Boolean;
+ calls:Array;
+ andCall(fn:Function):Spy;
+ andCallThrough():Spy;
+ andThrow(object:Object):Spy;
+ andReturn(value:any):Spy;
+ getLastCall():Call;
+ restore():void;
+ destroy():void;
+ }
+
+ function expectFn(actual:any):Expectation;
+
+ export module expect {
+ export function createSpy(fn?:Function, restore?:Function):Spy;
+ export function spyOn(object:Object, methodName:string):Spy;
+ export function isSpy(object:any):Boolean;
+ export function restoreSpies():void;
+ export function assert(condition:any, messageFormat:string, ...extraArgs:Array):void;
+ export function extend(extension:Extension):void;
+ }
+
+ import createSpy = expect.createSpy;
+ import spyOn = expect.spyOn;
+ import isSpy = expect.isSpy;
+ import restoreSpies = expect.restoreSpies;
+ import assert = expect.assert;
+ import extend = expect.extend;
+
+ export default expectFn;
+ export {
+ createSpy,
+ spyOn,
+ isSpy,
+ restoreSpies,
+ assert,
+ extend
+ }
+}