Skip to content

[jasmine] Improve various library types #38412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 105 additions & 40 deletions types/jasmine/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@
// Moshe Kolodny <https://github.com/kolodny>
// Stephen Farrar <https://github.com/stephenfarrar>
// Mochamad Arfin <https://github.com/ndunks>
// Alex Povar <https://github.com/zvirja>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// For ddescribe / iit use : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts

type ImplementationCallback = (() => PromiseLike<any>) | (() => void) | ((done: DoneFn) => void);
/**
* @deprecated Use {@link jasmine.ImplementationCallback} instead.
*/
type ImplementationCallback = jasmine.ImplementationCallback;

/**
* Create a group of specs (often called a suite).
Expand Down Expand Up @@ -48,23 +52,23 @@ declare function xdescribe(description: string, specDefinitions: () => void): vo
* @param assertion Function that contains the code of your test. If not provided the test will be pending.
* @param timeout Custom timeout for an async spec.
*/
declare function it(expectation: string, assertion?: ImplementationCallback, timeout?: number): void;
declare function it(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;

/**
* A focused `it`. If suites or specs are focused, only those that are focused will be executed.
* @param expectation Textual description of what this spec is checking
* @param assertion Function that contains the code of your test. If not provided the test will be pending.
* @param timeout Custom timeout for an async spec.
*/
declare function fit(expectation: string, assertion?: ImplementationCallback, timeout?: number): void;
declare function fit(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;

/**
* A temporarily disabled `it`. The spec will report as pending and will not be executed.
* @param expectation Textual description of what this spec is checking
* @param assertion Function that contains the code of your test. If not provided the test will be pending.
* @param timeout Custom timeout for an async spec.
*/
declare function xit(expectation: string, assertion?: ImplementationCallback, timeout?: number): void;
declare function xit(expectation: string, assertion?: jasmine.ImplementationCallback, timeout?: number): void;

/**
* Mark a spec as pending, expectation results will be ignored.
Expand All @@ -78,30 +82,30 @@ declare function pending(reason?: string): void;
* @param action Function that contains the code to setup your specs.
* @param timeout Custom timeout for an async beforeEach.
*/
declare function beforeEach(action: ImplementationCallback, timeout?: number): void;
declare function beforeEach(action: jasmine.ImplementationCallback, timeout?: number): void;

/**
* Run some shared teardown after each of the specs in the describe in which it is called.
* @param action Function that contains the code to teardown your specs.
* @param timeout Custom timeout for an async afterEach.
*/
declare function afterEach(action: ImplementationCallback, timeout?: number): void;
declare function afterEach(action: jasmine.ImplementationCallback, timeout?: number): void;

/**
* Run some shared setup once before all of the specs in the describe are run.
* Note: Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
* @param action Function that contains the code to setup your specs.
* @param timeout Custom timeout for an async beforeAll.
*/
declare function beforeAll(action: ImplementationCallback, timeout?: number): void;
declare function beforeAll(action: jasmine.ImplementationCallback, timeout?: number): void;

/**
* Run some shared teardown once before all of the specs in the describe are run.
* Note: Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
* @param action Function that contains the code to teardown your specs.
* @param timeout Custom timeout for an async afterAll
*/
declare function afterAll(action: ImplementationCallback, timeout?: number): void;
declare function afterAll(action: jasmine.ImplementationCallback, timeout?: number): void;

/**
* Create an expectation for a spec.
Expand Down Expand Up @@ -174,55 +178,69 @@ declare function spyOnProperty<T>(object: T, property: keyof T, accessType?: 'ge
* Installs spies on all writable and configurable properties of an object.
* @param object The object upon which to install the `Spy`s.
*/
declare function spyOnAllFunctions(object: object): jasmine.Spy;
declare function spyOnAllFunctions<T>(object: T): jasmine.SpyObj<T>;

declare function runs(asyncMethod: Function): void;
declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void;
declare function waits(timeout?: number): void;

declare namespace jasmine {
type ExpectedRecursive<T> = T | ObjectContaining<T> | AsymmetricMatcher | {
type Func = (...args: any[]) => any;

// Use trick with prototype to allow abstract classes.
// More info: https://stackoverflow.com/a/38642922/2009373
type Constructor = Function & { prototype: any };

type ImplementationCallback = (() => PromiseLike<any>) | ((done: DoneFn) => void);

type ExpectedRecursive<T> = T | ObjectContaining<T> | AsymmetricMatcher<any> | {
[K in keyof T]: ExpectedRecursive<T[K]> | Any;
};
type Expected<T> = T | ObjectContaining<T> | AsymmetricMatcher | Any | Spy | {
type Expected<T> = T | ObjectContaining<T> | AsymmetricMatcher<any> | Any | Spy | {
[K in keyof T]: ExpectedRecursive<T[K]>;
};
type SpyObjMethodNames<T = undefined> =
T extends undefined ?
(ReadonlyArray<string> | {[methodName: string]: any}) :
(ReadonlyArray<keyof T> | {[P in keyof T]?: ReturnType<T[P] extends (...args: any[]) => any ? T[P] : any>});
(ReadonlyArray<string> | { [methodName: string]: any }) :
(ReadonlyArray<keyof T> | { [P in keyof T]?: T[P] extends Func ? ReturnType<T[P]> : any });

function clock(): Clock;

var matchersUtil: MatchersUtil;

function any(aclass: any): Any;
/**
* That will succeed if the actual value being compared is an instance of the specified class/constructor.
*/
function any(aclass: Constructor | Symbol): AsymmetricMatcher<any>;

function anything(): Any;
/**
* That will succeed if the actual value being compared is not `null` and not `undefined`.
*/
function anything(): AsymmetricMatcher<any>;

/**
* That will succeed if the actual value being compared is `true` or anything truthy.
* @since 3.1.0
*/
function truthy(): Truthy;
function truthy(): AsymmetricMatcher<any>;

/**
* That will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
* @since 3.1.0
*/
function falsy(): Falsy;
function falsy(): AsymmetricMatcher<any>;

/**
* That will succeed if the actual value being compared is empty.
* @since 3.1.0
*/
function empty(): Empty;
function empty(): AsymmetricMatcher<any>;

/**
* That will succeed if the actual value being compared is not empty.
* @since 3.1.0
*/
function notEmpty(): NotEmpty;
function notEmpty(): AsymmetricMatcher<any>;

function arrayContaining<T>(sample: ArrayLike<T>): ArrayContaining<T>;
function arrayWithExactContents<T>(sample: ArrayLike<T>): ArrayContaining<T>;
Expand All @@ -233,7 +251,7 @@ declare namespace jasmine {
function createSpyObj<T>(baseName: string, methodNames: SpyObjMethodNames<T>): SpyObj<T>;

function createSpyObj(methodNames: SpyObjMethodNames): any;
function createSpyObj<T>(methodNames: SpyObjMethodNames): SpyObj<T>;
function createSpyObj<T>(methodNames: SpyObjMethodNames<T>): SpyObj<T>;

function pp(value: any): string;

Expand All @@ -243,39 +261,34 @@ declare namespace jasmine {

function addMatchers(matchers: CustomMatcherFactories): void;

function stringMatching(str: string | RegExp): Any;
function stringMatching(str: string | RegExp): AsymmetricMatcher<string>;

function formatErrorMsg(domain: string, usage: string): (msg: string) => string;

interface Any {
interface Any extends AsymmetricMatcher<any> {
(...params: any[]): any; // jasmine.Any can also be a function
new (expectedClass: any): any;

jasmineMatches(other: any): boolean;
jasmineToString(): string;
}

interface AsymmetricMatcher<T extends string = string> {
asymmetricMatch(other: any): boolean;
jasmineToString?(): T;
}

interface Truthy extends AsymmetricMatcher<'<jasmine.truthy>'> { }
interface Falsy extends AsymmetricMatcher<'<jasmine.falsy>'> { }
interface Empty extends AsymmetricMatcher<'<jasmine.empty>'> { }
interface NotEmpty extends AsymmetricMatcher<'<jasmine.notEmpty>'> { }
interface AsymmetricMatcher<TValue> {
asymmetricMatch(other: TValue, customTesters: ReadonlyArray<CustomEqualityTester>): boolean;
jasmineToString?(): string;
}

// taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains()
interface ArrayLike<T> {
length: number;
[n: number]: T;
}

interface ArrayContaining<T> extends AsymmetricMatcher {
interface ArrayContaining<T> extends AsymmetricMatcher<any> {
new?(sample: ArrayLike<T>): ArrayLike<T>;
}

interface ObjectContaining<T> {
interface ObjectContaining<T> extends AsymmetricMatcher<any> {
new?(sample: {[K in keyof T]?: any}): {[K in keyof T]?: any};

jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean;
Expand Down Expand Up @@ -492,19 +505,33 @@ declare namespace jasmine {
message(): any;

/**
* Expect the actual value to be `===` to the expected value.
*
* @param expected the actual value to be === to the expected value.
* @param expected - The expected value to compare against.
* @param expectationFailOutput
* @example
* expect(thing).toBe(realThing);
*/
toBe(expected: Expected<T>, expectationFailOutput?: any): boolean;

/**
*
* @param expected the actual value to be equal to the expected, using deep equality comparison.
* Expect the actual value to be equal to the expected, using deep equality comparison.
* @param expected - Expected value.
* @param expectationFailOutput
* @example
* expect(bigObject).toEqual({ "foo": ['bar', 'baz'] });
*/
toEqual(expected: Expected<T>, expectationFailOutput?: any): boolean;

/**
* Expect the actual value to match a regular expression.
* @param expected - Value to look for in the string.
* @example
* expect("my string").toMatch(/string$/);
* expect("other string").toMatch("her");
*/
toMatch(expected: string | RegExp, expectationFailOutput?: any): boolean;

toBeDefined(expectationFailOutput?: any): boolean;
toBeUndefined(expectationFailOutput?: any): boolean;
toBeNull(expectationFailOutput?: any): boolean;
Expand All @@ -527,23 +554,61 @@ declare namespace jasmine {
toThrowMatching(predicate: (thrown: any) => boolean): boolean;
toBeNegativeInfinity(expectationFailOutput?: any): boolean;
toBePositiveInfinity(expectationFailOutput?: any): boolean;
toHaveClass(expected: any, expectationFailOutput?: any): boolean;

/**
* Expect the actual value to be a DOM element that has the expected class.
* @since 3.0.0
* @param expected - The class name to test for.
* @example
* var el = document.createElement('div');
* el.className = 'foo bar baz';
* expect(el).toHaveClass('bar');
*/
toHaveClass(expected: string, expectationFailOutput?: any): boolean;

/**
* Add some context for an expect.
* @param message - Additional context to show when the matcher fails
*/
withContext(message: string): Matchers<T>;

/**
* Invert the matcher following this expect.
*/
not: Matchers<T>;

Any: Any;
}

interface ArrayLikeMatchers<T> extends Matchers<ArrayLike<T>> {
/**
* Expect the actual value to be `===` to the expected value.
*
* @param expected - The expected value to compare against.
* @param expectationFailOutput
* @example
* expect(thing).toBe(realThing);
*/
toBe(expected: Expected<ArrayLike<T>> | ArrayContaining<T>, expectationFailOutput?: any): boolean;

/**
* Expect the actual value to be equal to the expected, using deep equality comparison.
* @param expected - Expected value.
* @param expectationFailOutput
* @example
* expect(bigObject).toEqual({ "foo": ['bar', 'baz'] });
*/
toEqual(expected: Expected<ArrayLike<T>> | ArrayContaining<T>, expectationFailOutput?: any): boolean;

toContain(expected: Expected<T>, expectationFailOutput?: any): boolean;

/**
* Add some context for an expect.
* @param message - Additional context to show when the matcher fails.
*/
withContext(message: string): ArrayLikeMatchers<T>;

/**
* Invert the matcher following this expect.
*/
not: ArrayLikeMatchers<T>;
}

Expand Down Expand Up @@ -745,7 +810,7 @@ declare namespace jasmine {
}

type SpyObj<T> = T & {
[k in keyof T]: T[k] extends Function ? T[k] & Spy : T[k];
[K in keyof T]: T[K] extends Function ? T[K] & Spy : T[K];
};

interface SpyAnd {
Expand Down
Loading