diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 39dbe3d2f..290a3c8ca 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -154,6 +154,7 @@ All definitions files include a header with the author and editors, so at some p * [Jasmine-data_driven_tests](https://github.com/gburghardt/jasmine-data_driven_tests) (by [Anthony MacKinnon](https://github.com/AnthonyMacKinnon)) * [Jasmine-jQuery](https://github.com/velesin/jasmine-jquery) (by [Gregor Stamac](https://github.com/gstamac)) * [jDataView](https://github.com/jDataView/jDataView) (by [Ingvar Stepanyan](https://github.com/RReverser)) +* [Jest](http://facebook.github.io/jest/) (by [Joshua Smith](https://github.com/Josh211ua)) * [JointJS](http://www.jointjs.com/) (by [Aidan Reel](http://github.com/areel)) * [jQRangeSlider](http://ghusse.github.com/jQRangeSlider) (by [Dániel Tar](https://github.com/qcz)) * [jQuery](http://jquery.com/) (from TypeScript samples) diff --git a/jest/jest-tests.ts b/jest/jest-tests.ts new file mode 100644 index 000000000..764daf142 --- /dev/null +++ b/jest/jest-tests.ts @@ -0,0 +1,123 @@ +/// + +// Tests based on the Jest website +jest.dontMock('../sum'); + +describe('sum', function() { + it('adds 1 + 2 to equal 3', function() { + var sum: (a: number, b: number) => number = require('../sum'); + expect(sum(1, 2)).toBe(3); + }); +}); + +describe('fetchCurrentUser', function() { + it('calls the callback when $.ajax requests are finished', function() { + var $ = require('jquery'); + var fetchCurrentUser = require('../fetchCurrentUser'); + + // Create a mock function for our callback + var callback = jest.genMockFunction(); + fetchCurrentUser(callback); + + // Now we emulate the process by which `$.ajax` would execute its own + // callback + $.ajax.mock.calls[0 /*first call*/][0 /*first argument*/].success({ + firstName: 'Bobby', + lastName: '");DROP TABLE Users;--' + }); + + // And finally we assert that this emulated call by `$.ajax` incurred a + // call back into the mock function we provided as a callback + expect(callback.mock.calls[0/*first call*/][0/*first arg*/]).toEqual({ + loggedIn: true, + fullName: 'Bobby ");DROP TABLE Users;--' + }); + }); +}); + +jest.dontMock('../displayUser.js') +jest.dontMock('jquery'); + +describe('displayUser', function() { + it('displays a user after a click', function() { + // Set up our document body + document.body.innerHTML = + '
' + + ' ' + + '
'; + + var displayUser = require('../displayUser'); + var $ = require('jquery'); + var fetchCurrentUser = require('../fetchCurrentUser'); + + // Tell the fetchCurrentUser mock function to automatically invoke + // its callback with some data + fetchCurrentUser.mockImplementation(function(cb: Function) { + cb({ + loggedIn: true, + fullName: 'Johnny Cash' + }); + }); + + // Use jquery to emulate a click on our button + $('#button').click(); + + // Assert that the fetchCurrentUser function was called, and that the + // #username span's innter text was updated as we'd it expect. + expect(fetchCurrentUser).toBeCalled(); + expect($('#username').text()).toEqual('Johnny Cash - Logged In'); + }); +}); + +jest.dontMock('../CheckboxWithLabel.js'); +describe('CheckboxWithLabel', function() { + it('changes the text after click', function() { + var React = require('react/addons'); + var CheckboxWithLabel = require('../CheckboxWithLabel.js'); + var TestUtils = React.addons.TestUtils; + + // Render a checkbox with label in the document + var checkbox = TestUtils.renderIntoDocument( + CheckboxWithLabel({ + labelOn: "On", + labelOff: "Off" + }) + ); + + // Verify that it's Off by default + var label = TestUtils.findRenderedDOMComponentWithTag( + checkbox, 'label'); + expect(label.getDOMNode().textContent).toEqual('Off'); + + // Simulate a click and verify that it is now On + var input = TestUtils.findRenderedDOMComponentWithTag( + checkbox, 'input'); + TestUtils.Simulate.change(input); + expect(label.getDOMNode().textContent).toEqual('On'); + }); +}); + +function testInstances() { + var mockFn = jest.genMockFunction(); + var a = new mockFn(); + var b = new mockFn(); + + mockFn.mock.instances[0] === a; // true + mockFn.mock.instances[1] === b; // true +} + +function testMockImplementation() { + var mockFn = jest.genMockFunction().mockImplementation(function (scalar:number):number { + return 42 + scalar; + }); + + var a = mockFn(0); + var b = mockFn(1); + + a === 42; // true + b === 43; // true + + mockFn.mock.calls[0][0] === 0; // true + mockFn.mock.calls[1][0] === 1; // true +} \ No newline at end of file diff --git a/jest/jest.d.ts b/jest/jest.d.ts new file mode 100644 index 000000000..52d09f99e --- /dev/null +++ b/jest/jest.d.ts @@ -0,0 +1,79 @@ +// Type definitions for Jest 0.1.18 +// Project: http://facebook.github.io/jest/ +// Definitions by: Asana +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare function afterEach(fn: jest.EmptyFunction): void; +declare function beforeEach(fn: jest.EmptyFunction): void; +declare function describe(name: string, fn: jest.EmptyFunction): void; +declare var it: jest.It; +declare function pit(name: string, fn: jest.EmptyFunction): void; +declare var require: jest.Require; +declare function xdescribe(name: string, fn: jest.EmptyFunction): void; +declare function xit(name: string, fn: jest.EmptyFunction): void; + +declare function expect(actual: any): jest.Matchers; + +declare module jest { + function autoMockOff(): void; + function autoMockOn(): void; + function clearAllTimers(): void; + function dontMock(moduleName: string): void; + function genMockFromModule(moduleName: string): Mock; + function genMockFunction(): Mock; + function genMockFn(): Mock; + function mock(moduleName: string): void; + function runAllTicks(): void; + function runAllTimers(): void; + function runOnlyPendingTimers(): void; + function setMock(moduleName: string, moduleExports: T): void; + + interface EmptyFunction { + (): void; + } + + interface Matchers { + not: Matchers; + toThrow(expected?: any): boolean; + toBe(expected: any): boolean; + toEqual(expected: any): boolean; + toBeFalsy(): boolean; + toBeTruthy(): boolean; + toBeNull(): boolean; + toBeUndefined(): boolean; + toMatch(expected: RegExp): boolean; + toContain(expected: string): boolean; + toBeCloseTo(expected: number, delta: number): boolean; + toBeGreaterThen(expected: number): boolean; + toBeLessThen(expected: number): boolean; + toBeCalled(): boolean; + toBeCalledWith(...args: any[]): boolean; + lastCalledWith(...args: any[]): boolean; + } + + interface It { + (name: string, fn: EmptyFunction): void; + only(name: string, fn: EmptyFunction): void; + } + + interface Require { + (moduleName: string): any; + requireActual(moduleName: string): any; + } + + interface Mock { + new(): T; + mock: MockContext; + mockClear(): void; + mockImplementation(fn: Function): Mock; + mockImpl(fn: Function): Mock; + mockReturnThis(): Mock; + mockReturnValue(value: any): Mock; + mockReturnValueOnce(value: any): Mock; + } + + interface MockContext { + calls: any[][]; + instances: T[]; + } +} \ No newline at end of file