// Type definitions for QUnit 1.10
// Project: http://qunitjs.com/
// Definitions by: Diullei Gomes <https://github.com/diullei>
// DefinitelyTyped: https://github.com/borisyankov/DefinitelyTyped


interface DoneCallbackObject {
	/**
	* The number of failed assertions
	*/
	failed: number;

	/**
	* The number of passed assertions
	*/
	passed: number;

	/**
	* The total number of assertions
	*/
	total: number;

	/**
	* The time in milliseconds it took tests to run from start to finish.
	*/
	runtime: number;
}

interface LogCallbackObject {
	/**
	* The boolean result of an assertion, true means passed, false means failed.
	*/
	result: boolean;

	/**
	* One side of a comparision assertion. Can be undefined when ok() is used.
	*/
	actual: Object;

	/**
	* One side of a comparision assertion. Can be undefined when ok() is used.
	*/
	expected: Object;

	/**
	* A string description provided by the assertion.
	*/
	message: string;

	/**
	* The associated stacktrace, either from an exception or pointing to the source 
	* of the assertion. Depends on browser support for providing stacktraces, so can be 
	* undefined.
	*/
	source: string;
}

interface ModuleStartCallbackObject {
	/**
	* Name of the next module to run
	*/
	name: string;
}

interface ModuleDoneCallbackObject {
	/**
	* Name of this module
	*/
	name: string;

	/**
	* The number of failed assertions
	*/
	failed: number;

	/**
	* The number of passed assertions
	*/
	passed: number;

	/**
	* The total number of assertions
	*/
	total: number;
}

interface TestDoneCallbackObject {
	/**
	* TName of the next test to run
	*/
	name: string;

	/**
	* Name of the current module
	*/
	module: string;

	/**
	* The number of failed assertions
	*/
	failed: number;

	/**
	* The number of passed assertions
	*/
	passed: number;

	/**
	* The total number of assertions
	*/
	total: number;

	/**
	* The total runtime, including setup and teardown
	*/
	duration: number;
}

interface TestStartCallbackObject {
	/**
	* Name of the next test to run
	*/
	name: string;

	/**
	* Name of the current module
	*/
	module: string;
}

interface Config {
	altertitle: boolean;
	autostart: boolean;
	current: Object;
	reorder: boolean;
	requireExpects: boolean;
	testTimeout: number;
	urlConfig: Array<URLConfigItem>;
	done: any;
}

interface URLConfigItem {
	id: string;
	label: string;
	tooltip: string;
}

interface LifecycleObject {
	/**
	* Runs before each test
	*/
	setup?: () => any;

	/**
	* Runs after each test
	*/
	teardown?: () => any;
}

interface QUnitAssert {
	/* ASSERT */
	assert: any;
	current_testEnvironment: any;
	jsDump: any;

	/**
	* A deep recursive comparison assertion, working on primitive types, arrays, objects, 
	* regular expressions, dates and functions.
	*
	* The deepEqual() assertion can be used just like equal() when comparing the value of 
	* objects, such that { key: value } is equal to { key: value }. For non-scalar values, 
	* identity will be disregarded by deepEqual.
	*
	* @param actual Object or Expression being tested
	* @param expected Known comparison value
	* @param message A short description of the assertion
	*/
	deepEqual(actual: any, expected: any, message?: string);

	/** 
	* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
	*
	* The equal assertion uses the simple comparison operator (==) to compare the actual 
	* and expected arguments. When they are equal, the assertion passes; otherwise, it fails. 
	* When it fails, both actual and expected values are displayed in the test result, 
	* in addition to a given message.
	* 
	* @param actual Expression being tested
	* @param expected Known comparison value
	* @param message A short description of the assertion
	*/
	equal(actual: any, expected: any, message?: string);

	/**
	* An inverted deep recursive comparison assertion, working on primitive types, 
	* arrays, objects, regular expressions, dates and functions.
	*
	* The notDeepEqual() assertion can be used just like equal() when comparing the 
	* value of objects, such that { key: value } is equal to { key: value }. For non-scalar 
	* values, identity will be disregarded by notDeepEqual.
	* 
	* @param actual Object or Expression being tested
	* @param expected Known comparison value
	* @param message A short description of the assertion
	*/
	notDeepEqual(actual: any, expected: any, message?: string);

	/**
	* A non-strict comparison assertion, checking for inequality.
	*
	* The notEqual assertion uses the simple inverted comparison operator (!=) to compare 
	* the actual and expected arguments. When they aren't equal, the assertion passes; 
	* otherwise, it fails. When it fails, both actual and expected values are displayed 
	* in the test result, in addition to a given message.
	* 
	* @param actual Expression being tested
	* @param expected Known comparison value
	* @param message A short description of the assertion
	*/
	notEqual(actual: any, expected: any, message?: string);

	notPropEqual(actual: any, expected: any, message?: string);

	propEqual(actual: any, expected: any, message?: string);

	/**
	* A non-strict comparison assertion, checking for inequality.
	*
	* The notStrictEqual assertion uses the strict inverted comparison operator (!==) 
	* to compare the actual and expected arguments. When they aren't equal, the assertion 
	* passes; otherwise, it fails. When it fails, both actual and expected values are 
	* displayed in the test result, in addition to a given message.
	* 
	* @param actual Expression being tested
	* @param expected Known comparison value
	* @param message A short description of the assertion
	*/
	notStrictEqual(actual: any, expected: any, message?: string);

	/**
	* A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue(). 
	* Passes if the first argument is truthy.
	*
	* The most basic assertion in QUnit, ok() requires just one argument. If the argument 
	* evaluates to true, the assertion passes; otherwise, it fails. If a second message 
	* argument is provided, it will be displayed in place of the result.
	* 
	* @param state Expression being tested
	* @param message A short description of the assertion
	*/
	ok(state: any, message?: string);

	/**
	* A strict type and value comparison assertion.
	*
	* The strictEqual() assertion provides the most rigid comparison of type and value with 
	* the strict equality operator (===)
	* 
	* @param actual Expression being tested
	* @param expected Known comparison value
	* @param message A short description of the assertion
	*/
	strictEqual(actual: any, expected: any, message?: string);

	/**
	* Assertion to test if a callback throws an exception when run.
	* 
	* When testing code that is expected to throw an exception based on a specific set of 
	* circumstances, use throws() to catch the error object for testing and comparison.
	* 
	* @param block Function to execute
	* @param expected Error Object to compare
	* @param message A short description of the assertion
	*/
	throws(block: () => any, expected: any, message?: string);

	/**
	* @param block Function to execute
	* @param message A short description of the assertion
	*/
	throws(block: () => any, message?: string);
}

interface QUnitStatic extends QUnitAssert{	
	/* ASYNC CONTROL */

	/**
	* Start running tests again after the testrunner was stopped. See stop().
	*
	* When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
	* 
	* @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
	*/
	start(decrement?: number);

	/**
	* Stop the testrunner to wait for async tests to run. Call start() to continue.
	*
	* When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
	*
	* On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
	*
	* @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
	*/
	stop(increment? : number);
	
	/* CALLBACKS */

	/**
	* Register a callback to fire whenever the test suite begins.
	*
	* QUnit.begin() is called once before running any tests. (a better would've been QUnit.start, 
	* but thats already in use elsewhere and can't be changed.)
	*
	* @param callback Callback to execute
	*/
	begin(callback: () => any);

	/**
	* Register a callback to fire whenever the test suite ends.
	*
	* @param callback Callback to execute.
	*/
	done(callback: (details: DoneCallbackObject) => any);

	/**
	* Register a callback to fire whenever an assertion completes.
	*
	* This is one of several callbacks QUnit provides. Its intended for integration scenarios like 
	* PhantomJS or Jenkins. The properties of the details argument are listed below as options.
	*
	* @param callback Callback to execute.
	*/
	log(callback: (details: LogCallbackObject) => any);

	/**
	* Register a callback to fire whenever a module ends.
	*
	* @param callback Callback to execute.
	*/
	moduleDone(callback: (details: ModuleDoneCallbackObject) => any);

	/**
	* Register a callback to fire whenever a module begins.
	*
	* @param callback Callback to execute.
	*/
	moduleStart(callback: (details: ModuleStartCallbackObject) => any);

	/**
	* Register a callback to fire whenever a test ends.
	*
	* @param callback Callback to execute.
	*/
	testDone(callback: (details: TestDoneCallbackObject) => any);

	/**
	* Register a callback to fire whenever a test begins.
	*
	* @param callback Callback to execute.
	*/
	testStart(callback: (details: TestStartCallbackObject) => any);
	
	/* CONFIGURATION */

	/**
	* QUnit has a bunch of internal configuration defaults, some of which are 
	* useful to override. Check the description for each option for details.
	*/
	config: Config;
	
	/* TEST */

	/**
	* Add an asynchronous test to run. The test must include a call to start().
	*
	* For testing asynchronous code, asyncTest will automatically stop the test runner 
	* and wait for your code to call start() to continue.
	*
	* @param name Title of unit being tested
	* @param expected Number of assertions in this test
	* @param test Function to close over assertions
	*/
	asyncTest(name: string, expected: number, test: () => any);

	/**
	* Add an asynchronous test to run. The test must include a call to start().
	*
	* For testing asynchronous code, asyncTest will automatically stop the test runner 
	* and wait for your code to call start() to continue.
	*
	* @param name Title of unit being tested
	* @param test Function to close over assertions
	*/
	asyncTest(name: string, test: () => any);

	/**
	* Specify how many assertions are expected to run within a test.
	*
	* To ensure that an explicit number of assertions are run within any test, use 
	* expect( number ) to register an expected count. If the number of assertions 
	* run does not match the expected count, the test will fail.
	*
	* @param amount Number of assertions in this test.
	*/
	expect(amount: number);

	/**
	* Group related tests under a single label.
	*
	* All tests that occur after a call to module() will be grouped into that module. 
	* The test names will all be preceded by the module name in the test results. 
	* You can then use that module name to select tests to run.
	*
	* @param name Label for this group of tests
	* @param lifecycle Callbacks to run before and after each test
	*/
	module(name: string, lifecycle?: LifecycleObject);

	/**
	* Add a test to run.
	*
	* When testing the most common, synchronous code, use test().
	* The assert argument to the callback contains all of QUnit's assertion methods. 
	* If you are avoiding using any of QUnit's globals, you can use the assert 
	* argument instead.
	* 
	* @param title Title of unit being tested
	* @param expected Number of assertions in this test
	* @param test Function to close over assertions
	*/
	test(title: string, expected: number, test: (assert: QUnitAssert) => any);

	/**
	* @param title Title of unit being tested
	* @param test Function to close over assertions
	*/
	test(title: string, test: (assert: QUnitAssert) => any);

	/**
	* https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
	*/
	equiv(a: any, b: any);

	// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
	raises: any;

	/**
	* https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L897
	*/
	push(result, actual, expected, message): any;

	/**
	* https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L839
	*/
	reset(): any;
}

/* ASSERT */

/**
* A deep recursive comparison assertion, working on primitive types, arrays, objects, 
* regular expressions, dates and functions.
*
* The deepEqual() assertion can be used just like equal() when comparing the value of 
* objects, such that { key: value } is equal to { key: value }. For non-scalar values, 
* identity will be disregarded by deepEqual.
*
* @param actual Object or Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function deepEqual(actual: any, expected: any, message?: string);

/** 
* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
*
* The equal assertion uses the simple comparison operator (==) to compare the actual 
* and expected arguments. When they are equal, the assertion passes; otherwise, it fails. 
* When it fails, both actual and expected values are displayed in the test result, 
* in addition to a given message.
* 
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function equal(actual: any, expected: any, message?: string);

/**
* An inverted deep recursive comparison assertion, working on primitive types, 
* arrays, objects, regular expressions, dates and functions.
*
* The notDeepEqual() assertion can be used just like equal() when comparing the 
* value of objects, such that { key: value } is equal to { key: value }. For non-scalar 
* values, identity will be disregarded by notDeepEqual.
* 
* @param actual Object or Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function notDeepEqual(actual: any, expected: any, message?: string);

/**
* A non-strict comparison assertion, checking for inequality.
*
* The notEqual assertion uses the simple inverted comparison operator (!=) to compare 
* the actual and expected arguments. When they aren't equal, the assertion passes; 
* otherwise, it fails. When it fails, both actual and expected values are displayed 
* in the test result, in addition to a given message.
* 
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function notEqual(actual: any, expected: any, message?: string);

/**
* A non-strict comparison assertion, checking for inequality.
*
* The notStrictEqual assertion uses the strict inverted comparison operator (!==) 
* to compare the actual and expected arguments. When they aren't equal, the assertion 
* passes; otherwise, it fails. When it fails, both actual and expected values are 
* displayed in the test result, in addition to a given message.
* 
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function notStrictEqual(actual: any, expected: any, message?: string);

/**
* A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue(). 
* Passes if the first argument is truthy.
*
* The most basic assertion in QUnit, ok() requires just one argument. If the argument 
* evaluates to true, the assertion passes; otherwise, it fails. If a second message 
* argument is provided, it will be displayed in place of the result.
* 
* @param state Expression being tested
* @param message A short description of the assertion
*/
declare function ok(state: any, message?: string);

/**
* A strict type and value comparison assertion.
*
* The strictEqual() assertion provides the most rigid comparison of type and value with 
* the strict equality operator (===)
* 
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function strictEqual(actual: any, expected: any, message?: string);

/**
* Assertion to test if a callback throws an exception when run.
* 
* When testing code that is expected to throw an exception based on a specific set of 
* circumstances, use throws() to catch the error object for testing and comparison.
* 
* @param block Function to execute
* @param expected Error Object to compare
* @param message A short description of the assertion
*/
declare function throws(block: () => any, expected: any, message?: string);

/**
* @param block Function to execute
* @param message A short description of the assertion
*/
declare function throws(block: () => any, message?: string);

/* ASYNC CONTROL */

/**
* Start running tests again after the testrunner was stopped. See stop().
*
* When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
* 
* @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
*/
declare function start(decrement?: number);

/**
* Stop the testrunner to wait for async tests to run. Call start() to continue.
*
* When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
*
* On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
*
* @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
*/
declare function stop(increment? : number);
	
/* CALLBACKS */

/**
* Register a callback to fire whenever the test suite begins.
*
* QUnit.begin() is called once before running any tests. (a better would've been QUnit.start, 
* but thats already in use elsewhere and can't be changed.)
*
* @param callback Callback to execute
*/
declare function begin(callback: () => any);

/**
* Register a callback to fire whenever the test suite ends.
*
* @param callback Callback to execute.
*/
declare function done(callback: (details: DoneCallbackObject) => any);

/**
* Register a callback to fire whenever an assertion completes.
*
* This is one of several callbacks QUnit provides. Its intended for integration scenarios like 
* PhantomJS or Jenkins. The properties of the details argument are listed below as options.
*
* @param callback Callback to execute.
*/
declare function log(callback: (details: LogCallbackObject) => any);

/**
* Register a callback to fire whenever a module ends.
*
* @param callback Callback to execute.
*/
declare function moduleDone(callback: (details: ModuleDoneCallbackObject) => any);

/**
* Register a callback to fire whenever a module begins.
*
* @param callback Callback to execute.
*/
declare function moduleStart(callback: (name: string) => any);

/**
* Register a callback to fire whenever a test ends.
*
* @param callback Callback to execute.
*/
declare function testDone(callback: (details: TestDoneCallbackObject) => any);

/**
* Register a callback to fire whenever a test begins.
*
* @param callback Callback to execute.
*/
declare function testStart(callback: (details: TestStartCallbackObject) => any);
	
/* TEST */

/**
* Add an asynchronous test to run. The test must include a call to start().
*
* For testing asynchronous code, asyncTest will automatically stop the test runner 
* and wait for your code to call start() to continue.
*
* @param name Title of unit being tested
* @param expected Number of assertions in this test
* @param test Function to close over assertions
*/
declare function asyncTest(name: string, expected?: any, test?: () => any);

/**
* Add an asynchronous test to run. The test must include a call to start().
*
* For testing asynchronous code, asyncTest will automatically stop the test runner 
* and wait for your code to call start() to continue.
*
* @param name Title of unit being tested
* @param test Function to close over assertions
*/
declare function asyncTest(name: string, test: () => any);

/**
* Specify how many assertions are expected to run within a test.
*
* To ensure that an explicit number of assertions are run within any test, use 
* expect( number ) to register an expected count. If the number of assertions 
* run does not match the expected count, the test will fail.
*
* @param amount Number of assertions in this test.
*/
declare function expect(amount: number);

// ** conflict with TypeScript module keyword. Must be used on QUnit namespace
//declare var module: (name: string, lifecycle?: LifecycleObject) => any;

/**
* Add a test to run.
*
* When testing the most common, synchronous code, use test().
* The assert argument to the callback contains all of QUnit's assertion methods. 
* If you are avoiding using any of QUnit's globals, you can use the assert 
* argument instead.
* 
* @param title Title of unit being tested
* @param expected Number of assertions in this test
* @param test Function to close over assertions
*/
declare function test(title: string, expected: number, test: (assert?: QUnitAssert) => any);

/**
* @param title Title of unit being tested
* @param test Function to close over assertions
*/
declare function test(title: string, test: (assert?: QUnitAssert) => any);

declare function notPropEqual(actual: any, expected: any, message?: string);

declare function propEqual(actual: any, expected: any, message?: string);

// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
declare function equiv(a: any, b: any);

// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
declare var raises: any;

/* QUNIT */
declare var QUnit: QUnitStatic;