[jasmine] Support custom async matchers (#42850)

* Add types for custom async matchers

* Add self to owners
This commit is contained in:
Andrew Casey
2020-03-05 11:03:23 -08:00
committed by GitHub
parent bf3b94190d
commit 1c9e1cbfbb
4 changed files with 132 additions and 6 deletions

View File

@@ -14,6 +14,7 @@
// Stephen Farrar <https://github.com/stephenfarrar>
// Alex Povar <https://github.com/zvirja>
// Dominik Ehrenberg <https://github.com/djungowski>
// Chives <https://github.com/chivesrs>
// 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
@@ -140,7 +141,7 @@ declare function expect(): jasmine.NothingMatcher;
* @checkReturnValue see https://tsetse.info/check-return-value
* @param actual - Actual computed value to test expectations against.
*/
declare function expectAsync<T, U>(actual: PromiseLike<T>): jasmine.AsyncMatchers<T, U>;
declare function expectAsync<T, U>(actual: T|PromiseLike<T>): jasmine.AsyncMatchers<T, U>;
/**
* Explicitly mark a spec as failed.
@@ -278,7 +279,7 @@ declare namespace jasmine {
function addCustomEqualityTester(equalityTester: CustomEqualityTester): void;
function addMatchers(matchers: CustomMatcherFactories): void;
function addAsyncMatchers(matchers: CustomMatcherFactories): void;
function addAsyncMatchers(matchers: CustomAsyncMatcherFactories): void;
function stringMatching(str: string | RegExp): AsymmetricMatcher<string>;
@@ -346,10 +347,23 @@ declare namespace jasmine {
negativeCompare?(actual: any, ...expected: any[]): CustomMatcherResult;
}
interface CustomAsyncMatcher {
compare<T>(actual: T, expected: T, ...args: any[]): Promise<CustomMatcherResult>;
compare(actual: any, ...expected: any[]): Promise<CustomMatcherResult>;
negativeCompare?<T>(actual: T, expected: T, ...args: any[]): Promise<CustomMatcherResult>;
negativeCompare?(actual: any, ...expected: any[]): Promise<CustomMatcherResult>;
}
type CustomMatcherFactory = (util: MatchersUtil, customEqualityTesters: ReadonlyArray<CustomEqualityTester>) => CustomMatcher;
type CustomAsyncMatcherFactory = (util: MatchersUtil, customEqualityTesters: ReadonlyArray<CustomEqualityTester>) => CustomAsyncMatcher;
interface CustomMatcherFactories {
[index: string]: CustomMatcherFactory;
[name: string]: CustomMatcherFactory;
}
interface CustomAsyncMatcherFactories {
[name: string]: CustomAsyncMatcherFactory;
}
interface CustomMatcherResult {

View File

@@ -1357,6 +1357,10 @@ declare namespace jasmine {
toBeGoofy(expected?: Expected<T>): boolean;
toBeWithinRange(expected?: Expected<T>, floor?: number, ceiling?: number): boolean;
}
interface AsyncMatchers<T, U> {
toBeEight(): Promise<void>;
}
}
describe("Custom matcher: 'toBeGoofy'", () => {
@@ -1405,6 +1409,51 @@ describe("Custom matcher: 'toBeGoofy'", () => {
});
});
describe("Custom async matcher: 'toBeEight'", () => {
beforeEach(() => {
jasmine.addAsyncMatchers({
toBeEight: () => {
return {
// tslint:disable-next-line:no-any
compare: async (input: any) => {
return {
pass: input === 8,
message: `${JSON.stringify(input)} is not 8`,
};
},
};
},
});
// $ExpectError
jasmine.addAsyncMatchers({
toBeBadlyTyped: () => {
return {
compare: () => {
return {
pass: true,
message: 'I am not an async function / not returning promise!',
};
},
};
},
});
});
it("works in positive case", async () => {
await expectAsync(8).toBeEight();
});
it("works in negative case", async () => {
await expectAsync("seven").not.toBeEight();
});
it("fails correctly", async () => {
// This compiles, but the test fails at runtime (as {} isn't 8).
await expectAsync({}).toBeEight();
});
});
describe('better typed spys', () => {
describe('a typed spy', () => {
const spy = jasmine.createSpy('spy', (num: number, str: string) => {

View File

@@ -13,6 +13,7 @@
// Stephen Farrar <https://github.com/stephenfarrar>
// Alex Povar <https://github.com/zvirja>
// Dominik Ehrenberg <https://github.com/djungowski>
// Chives <https://github.com/chivesrs>
// For ddescribe / iit use : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts
/**
@@ -137,7 +138,7 @@ declare function expect(): jasmine.NothingMatcher;
* @checkReturnValue see https://tsetse.info/check-return-value
* @param actual - Actual computed value to test expectations against.
*/
declare function expectAsync<T, U>(actual: Promise<T>): jasmine.AsyncMatchers<T, U>;
declare function expectAsync<T, U>(actual: T|Promise<T>): jasmine.AsyncMatchers<T, U>;
/**
* Explicitly mark a spec as failed.
@@ -281,7 +282,7 @@ declare namespace jasmine {
function addCustomEqualityTester(equalityTester: CustomEqualityTester): void;
function addMatchers(matchers: CustomMatcherFactories): void;
function addAsyncMatchers(matchers: CustomMatcherFactories): void;
function addAsyncMatchers(matchers: CustomAsyncMatcherFactories): void;
function stringMatching(str: string | RegExp): AsymmetricMatcher<string>;
@@ -349,10 +350,23 @@ declare namespace jasmine {
negativeCompare?(actual: any, ...expected: any[]): CustomMatcherResult;
}
interface CustomAsyncMatcher {
compare<T>(actual: T, expected: T, ...args: any[]): Promise<CustomMatcherResult>;
compare(actual: any, ...expected: any[]): Promise<CustomMatcherResult>;
negativeCompare?<T>(actual: T, expected: T, ...args: any[]): Promise<CustomMatcherResult>;
negativeCompare?(actual: any, ...expected: any[]): Promise<CustomMatcherResult>;
}
type CustomMatcherFactory = (util: MatchersUtil, customEqualityTesters: ReadonlyArray<CustomEqualityTester>) => CustomMatcher;
type CustomAsyncMatcherFactory = (util: MatchersUtil, customEqualityTesters: ReadonlyArray<CustomEqualityTester>) => CustomAsyncMatcher;
interface CustomMatcherFactories {
[index: string]: CustomMatcherFactory;
[name: string]: CustomMatcherFactory;
}
interface CustomAsyncMatcherFactories {
[name: string]: CustomAsyncMatcherFactory;
}
interface CustomMatcherResult {

View File

@@ -1326,6 +1326,10 @@ declare namespace jasmine {
toBeGoofy(expected?: Expected<T>): boolean;
toBeWithinRange(expected?: Expected<T>, floor?: number, ceiling?: number): boolean;
}
interface AsyncMatchers<T, U> {
toBeEight(): Promise<void>;
}
}
describe("Custom matcher: 'toBeGoofy'", () => {
@@ -1374,6 +1378,51 @@ describe("Custom matcher: 'toBeGoofy'", () => {
});
});
describe("Custom async matcher: 'toBeEight'", () => {
beforeEach(() => {
jasmine.addAsyncMatchers({
toBeEight: () => {
return {
// tslint:disable-next-line:no-any
compare: async (input: any) => {
return {
pass: input === 8,
message: `${JSON.stringify(input)} is not 8`,
};
},
};
},
});
jasmine.addAsyncMatchers({
// $ExpectError
toBeBadlyTyped: () => {
return {
compare: () => {
return {
pass: true,
message: 'I am not an async function / not returning promise!',
};
},
};
},
});
});
it("works in positive case", async () => {
await expectAsync(8).toBeEight();
});
it("works in negative case", async () => {
await expectAsync("seven").not.toBeEight();
});
it("fails correctly", async () => {
// This compiles, but the test fails at runtime (as {} isn't 8).
await expectAsync({}).toBeEight();
});
});
describe('better typed spys', () => {
describe('a typed spy', () => {
const spy = jasmine.createSpy('spy', (num: number, str: string) => {