diff --git a/types/jasmine/index.d.ts b/types/jasmine/index.d.ts index 40706dec76..9feeda7b59 100644 --- a/types/jasmine/index.d.ts +++ b/types/jasmine/index.d.ts @@ -14,11 +14,15 @@ // Moshe Kolodny // Stephen Farrar // Mochamad Arfin +// Alex Povar // 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) | (() => void) | ((done: DoneFn) => void); +/** + * @deprecated Use {@link jasmine.ImplementationCallback} instead. + */ +type ImplementationCallback = jasmine.ImplementationCallback; /** * Create a group of specs (often called a suite). @@ -48,7 +52,7 @@ 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. @@ -56,7 +60,7 @@ declare function it(expectation: string, assertion?: ImplementationCallback, tim * @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. @@ -64,7 +68,7 @@ declare function fit(expectation: string, assertion?: ImplementationCallback, ti * @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. @@ -78,14 +82,14 @@ 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. @@ -93,7 +97,7 @@ declare function afterEach(action: ImplementationCallback, timeout?: number): vo * @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. @@ -101,7 +105,7 @@ declare function beforeAll(action: ImplementationCallback, timeout?: number): vo * @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. @@ -174,55 +178,69 @@ declare function spyOnProperty(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(object: T): jasmine.SpyObj; 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 | ObjectContaining | 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) | ((done: DoneFn) => void); + + type ExpectedRecursive = T | ObjectContaining | AsymmetricMatcher | { [K in keyof T]: ExpectedRecursive | Any; }; - type Expected = T | ObjectContaining | AsymmetricMatcher | Any | Spy | { + type Expected = T | ObjectContaining | AsymmetricMatcher | Any | Spy | { [K in keyof T]: ExpectedRecursive; }; type SpyObjMethodNames = T extends undefined ? - (ReadonlyArray | {[methodName: string]: any}) : - (ReadonlyArray | {[P in keyof T]?: ReturnType any ? T[P] : any>}); + (ReadonlyArray | { [methodName: string]: any }) : + (ReadonlyArray | { [P in keyof T]?: T[P] extends Func ? ReturnType : 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; - function anything(): Any; + /** + * That will succeed if the actual value being compared is not `null` and not `undefined`. + */ + function anything(): AsymmetricMatcher; /** * That will succeed if the actual value being compared is `true` or anything truthy. * @since 3.1.0 */ - function truthy(): Truthy; + function truthy(): AsymmetricMatcher; /** * 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; /** * That will succeed if the actual value being compared is empty. * @since 3.1.0 */ - function empty(): Empty; + function empty(): AsymmetricMatcher; /** * That will succeed if the actual value being compared is not empty. * @since 3.1.0 */ - function notEmpty(): NotEmpty; + function notEmpty(): AsymmetricMatcher; function arrayContaining(sample: ArrayLike): ArrayContaining; function arrayWithExactContents(sample: ArrayLike): ArrayContaining; @@ -233,7 +251,7 @@ declare namespace jasmine { function createSpyObj(baseName: string, methodNames: SpyObjMethodNames): SpyObj; function createSpyObj(methodNames: SpyObjMethodNames): any; - function createSpyObj(methodNames: SpyObjMethodNames): SpyObj; + function createSpyObj(methodNames: SpyObjMethodNames): SpyObj; function pp(value: any): string; @@ -243,11 +261,11 @@ declare namespace jasmine { function addMatchers(matchers: CustomMatcherFactories): void; - function stringMatching(str: string | RegExp): Any; + function stringMatching(str: string | RegExp): AsymmetricMatcher; function formatErrorMsg(domain: string, usage: string): (msg: string) => string; - interface Any { + interface Any extends AsymmetricMatcher { (...params: any[]): any; // jasmine.Any can also be a function new (expectedClass: any): any; @@ -255,15 +273,10 @@ declare namespace jasmine { jasmineToString(): string; } - interface AsymmetricMatcher { - asymmetricMatch(other: any): boolean; - jasmineToString?(): T; - } - - interface Truthy extends AsymmetricMatcher<''> { } - interface Falsy extends AsymmetricMatcher<''> { } - interface Empty extends AsymmetricMatcher<''> { } - interface NotEmpty extends AsymmetricMatcher<''> { } + interface AsymmetricMatcher { + asymmetricMatch(other: TValue, customTesters: ReadonlyArray): boolean; + jasmineToString?(): string; + } // taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains() interface ArrayLike { @@ -271,11 +284,11 @@ declare namespace jasmine { [n: number]: T; } - interface ArrayContaining extends AsymmetricMatcher { + interface ArrayContaining extends AsymmetricMatcher { new?(sample: ArrayLike): ArrayLike; } - interface ObjectContaining { + interface ObjectContaining extends AsymmetricMatcher { new?(sample: {[K in keyof T]?: any}): {[K in keyof T]?: any}; jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean; @@ -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, 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, 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; @@ -527,7 +554,17 @@ 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. @@ -535,15 +572,43 @@ declare namespace jasmine { */ withContext(message: string): Matchers; + /** + * Invert the matcher following this expect. + */ not: Matchers; - - Any: Any; } interface ArrayLikeMatchers extends Matchers> { + /** + * 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> | ArrayContaining, 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> | ArrayContaining, expectationFailOutput?: any): boolean; + toContain(expected: Expected, expectationFailOutput?: any): boolean; + + /** + * Add some context for an expect. + * @param message - Additional context to show when the matcher fails. + */ + withContext(message: string): ArrayLikeMatchers; + + /** + * Invert the matcher following this expect. + */ not: ArrayLikeMatchers; } @@ -745,7 +810,7 @@ declare namespace jasmine { } type SpyObj = 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 { diff --git a/types/jasmine/jasmine-tests.ts b/types/jasmine/jasmine-tests.ts index c6220c548f..165b479c95 100644 --- a/types/jasmine/jasmine-tests.ts +++ b/types/jasmine/jasmine-tests.ts @@ -15,23 +15,29 @@ describe("A suite is just a function", () => { }); }); -describe("The 'toBe' matcher compares with ===", () => { - it("and has a positive case", () => { - expect(true).toBe(true); - }); - - it("and can have a negative case", () => { - expect(false).not.toBe(true); - }); -}); - describe("Included matchers:", () => { - it("The 'toBe' matcher compares with ===", () => { - const a = 12; - const b = a; + describe('toBe', () => { + it("and has a positive case", () => { + expect(true).toBe(true); + }); - expect(a).toBe(b); - expect(a).not.toBe(24); + it("and can have a negative case", () => { + expect(false).not.toBe(true); + }); + + it("the 'toBe' matcher compares with ===", () => { + const a = 12; + const b = a; + + expect(a).toBe(b); + expect(a).not.toBe(24); + }); + + it('should allow to accept any union type', () => { + const value: number | string = null as any; + + expect(value).toBe(12); + }); }); describe("The 'toEqual' matcher", () => { @@ -176,8 +182,10 @@ describe("Included matchers:", () => { it("async matchers", async () => { const badness = new Error("badness"); await expectAsync(Promise.resolve()).toBeResolved(); + await expectAsync(Promise.resolve()).toBeResolved("good job"); await expectAsync(Promise.resolve(true)).toBeResolvedTo(true); await expectAsync(Promise.reject(badness)).toBeRejected(); + await expectAsync(Promise.reject(badness)).toBeRejected("bad mojo"); await expectAsync(Promise.reject(badness)).toBeRejectedWith(badness); await expectAsync(Promise.resolve()).withContext("additional info").toBeResolved(); }); @@ -209,7 +217,9 @@ describe("toBePositiveInfinity", () => { }); describe("toHaveClass", () => { - expect("").toHaveClass(Array); + const element: HTMLElement = null!; + expect(element).toHaveClass("some-class"); + expect(element).toHaveClass(Element); // $ExpectError }); describe("A spec", () => { @@ -396,22 +406,19 @@ describe("A spy, when configured to call through", () => { }); describe("A spy, when configured to fake a return value", () => { - var foo: any, bar: any, fetchedBar: any; - - beforeEach(() => { - foo = { - setBar: (value: any) => { - bar = value; - }, - getBar: () => { - return bar; - } - }; + var bar: number; + const foo = { + setBar: (value: number) => { + bar = value; + }, + getBar: () => { + return bar; + } + }; + it("verifies return value type", () => { spyOn(foo, "getBar").and.returnValue(745); - - foo.setBar(123); - fetchedBar = foo.getBar(); + spyOn(foo, "getBar").and.returnValue("42"); // Is an error with TS 3.1+ typings. }); it("tracks that the spy was called", () => { @@ -423,6 +430,8 @@ describe("A spy, when configured to fake a return value", () => { }); it("when called returns the requested value", () => { + const fetchedBar = foo.getBar(); + expect(fetchedBar).toEqual(745); }); }); @@ -720,6 +729,29 @@ describe("A spy, when created manually", () => { }); }); +describe("Spy for generic method", () => { + interface Test { + method(): Array>; + } + + interface Box { + value: T; + } + + it("should allow to configure generic method", () => { + const spy = jasmine.createSpyObj('test', ['method']); + + spy.method.and.returnValue([{ value: 1 }, { value: 2 }]); + }); + + it("should allow to configure generic method with non-named spy", () => { + const spy = jasmine.createSpyObj(['method']); + jasmine.createSpyObj(['methodUnknown']); // $ExpectError + + spy.method.and.returnValue([{ value: 1 }, { value: 2 }]); + }); +}); + describe("Multiple spies, when created manually", () => { class Tape { private rewindTo: number; @@ -770,6 +802,12 @@ describe("Multiple spies, when created manually", () => { it("tracks all the arguments of its calls", () => { expect(tape.rewind).toHaveBeenCalledWith(0); + expect(tape.rewind).toHaveBeenCalledWith('42'); // Is an error with TS 3.1+ typings. + expect(tape.rewind).toHaveBeenCalledWith(jasmine.anything()); + expect(tape.rewind).toHaveBeenCalledWith(jasmine.falsy()); + expect(tape.rewind).not.toHaveBeenCalledWith(1); + expect(tape.rewind).not.toHaveBeenCalledWith('42'); // Is an error with TS 3.1+ typings. + expect(tape.rewind).not.toHaveBeenCalledWith(jasmine.truthy()); }); it("read isPlaying property", () => { @@ -784,13 +822,19 @@ describe("multiple spies, when created with spyOnAllFunctions", () => { y: (a: number) => a, }; - spyOnAllFunctions(obj); + const spy = spyOnAllFunctions(obj); + + spy.x.and.returnValue(42); + spy.y.and.returnValue(24); + spy.z; // $ExpectError obj.x(0); obj.y(1); expect(obj.x).toHaveBeenCalled(); expect(obj.y).toHaveBeenCalledWith(1); + expect(spy.y).toHaveBeenCalledWith(1); + expect(spy.y).toHaveBeenCalledWith("one"); // Is an error with TS 3.1+ typings. }); }); @@ -804,6 +848,9 @@ describe("jasmine.any", () => { it("matches any value", () => { expect({}).toEqual(jasmine.any(Object)); expect(12).toEqual(jasmine.any(Number)); + expect(42).toEqual(jasmine.any(42)); // $ExpectError + expect({}).toEqual(jasmine.any({})); // $ExpectError + expect(() => null).toEqual(jasmine.any(Function)); }); it("matches any function", () => { @@ -817,7 +864,7 @@ describe("jasmine.any", () => { fn2: (param1: number) => param1, }; - const expected: Test = { + const expected = { fn1: jasmine.any(Function), fn2: jasmine.any(Function), }; @@ -825,6 +872,29 @@ describe("jasmine.any", () => { expect(a).toEqual(expected); }); + it("matches custom types", () => { + class Test { } + + const obj = new Test(); + + expect(obj).toEqual(jasmine.any(Test)); + }); + + it("matches base abstract class", () => { + abstract class TestClassBase { } + class TestClass extends TestClassBase { } + const obj = new TestClass(); + + expect(obj).toEqual(jasmine.any(TestClass)); + expect(obj).toEqual(jasmine.any(TestClassBase)); + }); + + it("matches symbols", () => { + const sym = Symbol('test symbol'); + + expect(sym).toEqual(jasmine.any(sym)); + }); + describe("when used with a spy", () => { it("is useful for comparing arguments", () => { const foo = jasmine.createSpy('foo'); @@ -834,6 +904,15 @@ describe("jasmine.any", () => { expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function)); }); + + it("is useful for comparing arguments for typed spy", () => { + const foo = jasmine.createSpy('foo'); + foo(12, () => { + return true; + }); + + expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function)); + }); }); }); @@ -949,6 +1028,15 @@ describe("jasmine.arrayContaining", () => { expect(foo).not.toBe(jasmine.arrayContaining([6])); }); + it("matches read-only array", () => { + const bar: ReadonlyArray = [1, 2, 3, 4]; + + expect(bar).toEqual(jasmine.arrayContaining([3, 1])); + expect(bar).not.toEqual(jasmine.arrayContaining([6])); + + expect(bar).toBe(jasmine.arrayContaining([3, 1])); + }); + describe("when used with a spy", () => { it("is useful when comparing arguments", () => { const callback = jasmine.createSpy('callback'); @@ -1206,6 +1294,75 @@ describe("Custom matcher: 'toBeGoofy'", () => { }); }); +describe('better typed spys', () => { + describe('a typed spy', () => { + const spy = jasmine.createSpy('spy', (num: number, str: string) => { + return `${num} and ${str}`; + }); + it('has a typed returnValue', () => { + // $ExpectType (val: any) => Spy + spy.and.returnValue; + }); + it('has a typed calls property', () => { + spy.calls.first().args; // $ExpectType any[] + spy.calls.first().returnValue; // $ExpectType any + }); + it('has a typed callFake', () => { + // $ExpectType (fn: Function) => Spy + spy.and.callFake; + }); + }); + describe('spyOn', () => { + it('only works on methods', () => { + const foo = { + method() { + return 'baz'; + }, + value: 'value', + }; + const spy = spyOn(foo, 'method'); + const spy2 = spyOn(foo, 'value'); // Is an error with TS 3.1+ typings. + + // $ExpectType any + spy.calls.first().returnValue; + }); + it('works on constructors', () => { + class MyClass { + constructor(readonly foo: string) {} + } + const namespace = { MyClass }; + const spy = spyOn(namespace, 'MyClass'); + spy.and.returnValue({foo: 'test'}); + spy.and.returnValue({}); // Is an error with TS 3.1+ typings. + spy.and.returnValue({foo: 123}); // Is an error with TS 3.1+ typings. + }); + it('can allows overriding the generic', () => { + class Base { + service() {} + } + class Super extends Base { + service2() {} + } + spyOn(new Super(), 'service'); + spyOn(new Super(), 'service2'); // $ExpectError + }); + }); + describe('createSpyObj', () => { + it('returns the correct spy types', () => { + const foo = { + method() { + return 'baz'; + }, + value: 'value', + }; + const spyObj = jasmine.createSpyObj('foo', ['method']); + + // $ExpectType (val: any) => Spy + spyObj.method.and.returnValue; + }); + }); +}); + // test based on http://jasmine.github.io/2.5/custom_reporter.html var myReporter: jasmine.CustomReporter = { jasmineStarted: (suiteInfo: jasmine.SuiteInfo) => { @@ -1318,46 +1475,73 @@ describe("createSpyObj", function() { }); describe('Static Matcher Test', function() { - it('Falsy', () => { - expect({ value: null }).toEqual( - jasmine.objectContaining({ - value: jasmine.falsy(), - }) - ); - }); - it('Truthy', () => { - expect({ value: null }).toEqual( - jasmine.objectContaining({ - value: jasmine.truthy(), - }) - ); - }); - it('Empty', () => { - expect({ value: null }).toEqual( - jasmine.objectContaining({ - value: jasmine.empty(), - }) - ); - }); - it('NotEmpty', () => { - expect({ value: null }).toEqual( - jasmine.objectContaining({ - value: jasmine.notEmpty(), - }) - ); - }); - it('Partial should OK', () => { - expect({ value: null, label: 'abcd' }).toEqual( - jasmine.objectContaining({ - value: jasmine.anything(), - }) - ); - expect({ value: null }).toEqual( + it('Falsy', () => { + expect({ value: null }).toEqual( jasmine.objectContaining({ - value: 'any value should ok', + value: jasmine.falsy(), }) ); - }); + }); + it('Truthy', () => { + expect({ value: null }).toEqual( + jasmine.objectContaining({ + value: jasmine.truthy(), + }) + ); + }); + it('Empty', () => { + expect({ value: null }).toEqual( + jasmine.objectContaining({ + value: jasmine.empty(), + }) + ); + }); + it('NotEmpty', () => { + expect({ value: null }).toEqual( + jasmine.objectContaining({ + value: jasmine.notEmpty(), + }) + ); + }); + it('Partial should OK', () => { + expect({ value: null, label: 'abcd' }).toEqual( + jasmine.objectContaining({ + value: jasmine.anything(), + }) + ); + expect({ value: null }).toEqual( + jasmine.objectContaining({ + value: 'any value should ok', + }) + ); + }); +}); + +describe("User scenarios", () => { + describe("https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34080", () => { + interface Test { + f(): string; + f(x: any): number; + } + + it("has a way to opt out of inferred function types", () => { + const spyObject: jasmine.SpyObj = jasmine.createSpyObj("spyObject", ["f"]); + spyObject.f.and.returnValue("a string - working"); + + const spy2 = jasmine.createSpyObj(['f']); + spy2.f.and.returnValue("can return string" as any); + }); + + it("should be possible to opt out for spyOn", () => { + const obj: Test = null!; + + const spy1: jasmine.Spy = spyOn(obj, "f"); + spy1.and.returnValue("can return string"); + + const spy2 = spyOn(obj, "f"); + spy2.and.returnValue("can return string" as any); + }); + }); }); (() => { diff --git a/types/jasmine/ts3.1/index.d.ts b/types/jasmine/ts3.1/index.d.ts index e5f6799418..34757496e0 100644 --- a/types/jasmine/ts3.1/index.d.ts +++ b/types/jasmine/ts3.1/index.d.ts @@ -12,10 +12,13 @@ // Moshe Kolodny // Stephen Farrar // Mochamad Arfin +// Alex Povar // For ddescribe / iit use : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts -type ImplementationCallback = (() => Promise) | ((done: DoneFn) => void); -type InferableFunction = (...args: any[]) => any; +/** + * @deprecated Use {@link jasmine.ImplementationCallback} instead. + */ +type ImplementationCallback = jasmine.ImplementationCallback; /** * Create a group of specs (often called a suite). @@ -45,7 +48,7 @@ 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. @@ -53,7 +56,7 @@ declare function it(expectation: string, assertion?: ImplementationCallback, tim * @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. @@ -61,7 +64,7 @@ declare function fit(expectation: string, assertion?: ImplementationCallback, ti * @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. @@ -75,14 +78,14 @@ 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. @@ -90,7 +93,7 @@ declare function afterEach(action: ImplementationCallback, timeout?: number): vo * @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. @@ -98,14 +101,14 @@ declare function beforeAll(action: ImplementationCallback, timeout?: number): vo * @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. * @checkReturnValue see https://tsetse.info/check-return-value * @param spy */ -declare function expect(spy: Function): jasmine.Matchers; +declare function expect(spy: T | jasmine.Spy): jasmine.FunctionMatchers; /** * Create an expectation for a spec. @@ -160,9 +163,9 @@ interface DoneFn extends Function { declare function spyOn( object: T, method: T[K] extends Function ? K : never, ): jasmine.Spy< - T[K] extends InferableFunction ? T[K] : - T[K] extends {new (...args: infer A): infer V} ? (...args: A) => V : - T[K] extends Function ? InferableFunction : never + T[K] extends jasmine.Func ? T[K] : + T[K] extends { new (...args: infer A): infer V } ? (...args: A) => V : + never >; /** @@ -177,72 +180,80 @@ declare function spyOnProperty(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(object: T): jasmine.SpyObj; 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 | ObjectContaining | 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) | ((done: DoneFn) => void); + + type ExpectedRecursive = T | ObjectContaining | AsymmetricMatcher | { [K in keyof T]: ExpectedRecursive | Any; }; - type Expected = T | ObjectContaining | AsymmetricMatcher | Any | Spy | { + type Expected = T | ObjectContaining | AsymmetricMatcher | Any | Spy | { [K in keyof T]: ExpectedRecursive; }; type SpyObjMethodNames = T extends undefined ? - (ReadonlyArray | {[methodName: string]: any}) : - (ReadonlyArray | {[P in keyof T]?: ReturnType}); - - type AnyMethods = { - [K in { - [K in keyof T]: T[K] extends Function ? K : never - }[keyof T]]: InferableFunction - }; + (ReadonlyArray | { [methodName: string]: any }) : + (ReadonlyArray | { [P in keyof T]?: T[P] extends Func ? ReturnType : 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; - function anything(): Any; + /** + * That will succeed if the actual value being compared is not `null` and not `undefined`. + */ + function anything(): AsymmetricMatcher; /** * That will succeed if the actual value being compared is `true` or anything truthy. * @since 3.1.0 */ - function truthy(): Truthy; + function truthy(): AsymmetricMatcher; /** * 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; /** * That will succeed if the actual value being compared is empty. * @since 3.1.0 */ - function empty(): Empty; + function empty(): AsymmetricMatcher; /** * That will succeed if the actual value being compared is not empty. * @since 3.1.0 */ - function notEmpty(): NotEmpty; + function notEmpty(): AsymmetricMatcher; function arrayContaining(sample: ArrayLike): ArrayContaining; function arrayWithExactContents(sample: ArrayLike): ArrayContaining; function objectContaining(sample: Partial): ObjectContaining; - function createSpy(name?: string, originalFn?: Fun): Spy; + function createSpy(name?: string, originalFn?: Fn): Spy; function createSpyObj(baseName: string, methodNames: SpyObjMethodNames): any; function createSpyObj(baseName: string, methodNames: SpyObjMethodNames): SpyObj; function createSpyObj(methodNames: SpyObjMethodNames): any; - function createSpyObj(methodNames: SpyObjMethodNames): SpyObj; + function createSpyObj(methodNames: SpyObjMethodNames): SpyObj; function pp(value: any): string; @@ -252,11 +263,11 @@ declare namespace jasmine { function addMatchers(matchers: CustomMatcherFactories): void; - function stringMatching(str: string | RegExp): Any; + function stringMatching(str: string | RegExp): AsymmetricMatcher; function formatErrorMsg(domain: string, usage: string): (msg: string) => string; - interface Any { + interface Any extends AsymmetricMatcher { (...params: any[]): any; // jasmine.Any can also be a function new (expectedClass: any): any; @@ -264,27 +275,22 @@ declare namespace jasmine { jasmineToString(): string; } - interface AsymmetricMatcher { - asymmetricMatch(other: any): boolean; - jasmineToString?(): T; + interface AsymmetricMatcher { + asymmetricMatch(other: TValue, customTesters: ReadonlyArray): boolean; + jasmineToString?(): string; } - interface Truthy extends AsymmetricMatcher<''> { } - interface Falsy extends AsymmetricMatcher<''> { } - interface Empty extends AsymmetricMatcher<''> { } - interface NotEmpty extends AsymmetricMatcher<''> { } - // taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains() interface ArrayLike { length: number; [n: number]: T; } - interface ArrayContaining extends AsymmetricMatcher { + interface ArrayContaining extends AsymmetricMatcher { new?(sample: ArrayLike): ArrayLike; } - interface ObjectContaining { + interface ObjectContaining extends AsymmetricMatcher { new?(sample: {[K in keyof T]?: any}): {[K in keyof T]?: any}; jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean; @@ -501,19 +507,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, 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, 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; @@ -521,7 +541,7 @@ declare namespace jasmine { toBeTruthy(expectationFailOutput?: any): boolean; toBeFalsy(expectationFailOutput?: any): boolean; toHaveBeenCalled(): boolean; - toHaveBeenCalledBefore(expected: Spy): boolean; + toHaveBeenCalledBefore(expected: Func): boolean; toHaveBeenCalledWith(...params: any[]): boolean; toHaveBeenCalledTimes(expected: number): boolean; toContain(expected: any, expectationFailOutput?: any): boolean; @@ -536,7 +556,17 @@ 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. @@ -544,18 +574,66 @@ declare namespace jasmine { */ withContext(message: string): Matchers; + /** + * Invert the matcher following this expect. + */ not: Matchers; - - Any: Any; } interface ArrayLikeMatchers extends Matchers> { + /** + * 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> | ArrayContaining, 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> | ArrayContaining, expectationFailOutput?: any): boolean; + toContain(expected: Expected, expectationFailOutput?: any): boolean; + + /** + * Add some context for an expect. + * @param message - Additional context to show when the matcher fails. + */ + withContext(message: string): ArrayLikeMatchers; + + /** + * Invert the matcher following this expect. + */ not: ArrayLikeMatchers; } + type MatchableArgs = Fn extends (...args: infer P) => any ? { [K in keyof P]: P[K] | AsymmetricMatcher } : never; + + interface FunctionMatchers extends Matchers { + toHaveBeenCalled(): boolean; + toHaveBeenCalledBefore(expected: Func): boolean; + toHaveBeenCalledTimes(expected: number): boolean; + toHaveBeenCalledWith(...params: MatchableArgs): boolean; + + /** + * Add some context for an expect. + * @param message - Additional context to show when the matcher fails. + */ + withContext(message: string): FunctionMatchers; + + /** + * Invert the matcher following this expect. + */ + not: FunctionMatchers; + } + interface NothingMatcher { nothing(): void; } @@ -745,61 +823,67 @@ declare namespace jasmine { execute(): void; } - interface Spy { - (...params: any[]): any; + interface Spy { + (...params: Parameters): ReturnType; and: SpyAnd; calls: Calls; - withArgs(...args: any[]): Spy; + withArgs(...args: Parameters): Spy; } type SpyObj = T & { - [k in keyof T]: T[k] extends InferableFunction ? T[k] & Spy : T[k]; + [K in keyof T]: T[K] extends Func ? T[K] & Spy : T[K]; }; - interface SpyAnd { + /** + * It's like SpyObj, but doesn't verify argument/return types for functions. + * Useful if TS cannot correctly infer type for complex objects. + */ + type NonTypedSpyObj = SpyObj<{ [K in keyof T]: T[K] extends Func ? Func : T[K] }>; + + interface SpyAnd { identity: string; /** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */ - callThrough(): Spy; + callThrough(): Spy; /** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */ - returnValue(val: ReturnType): Spy; + returnValue(val: ReturnType): Spy; /** By chaining the spy with and.returnValues, all calls to the function will return specific values in order until it reaches the end of the return values list. */ - returnValues(...values: Array>): Spy; + returnValues(...values: Array>): Spy; /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */ - callFake(fn: Fun): Spy; + callFake(fn: Fn): Spy; /** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */ throwError(msg: string): Spy; /** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */ stub(): Spy; } - interface Calls { + interface Calls { /** By chaining the spy with calls.any(), will return false if the spy has not been called at all, and then true once at least one call happens. */ any(): boolean; /** By chaining the spy with calls.count(), will return the number of times the spy was called */ count(): number; /** By chaining the spy with calls.argsFor(), will return the arguments passed to call number index */ - argsFor(index: number): Parameters; + argsFor(index: number): Parameters; /** By chaining the spy with calls.allArgs(), will return the arguments to all calls */ - allArgs(): Array>; + allArgs(): ReadonlyArray>; /** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls */ - all(): Array>; + all(): ReadonlyArray>; /** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call */ - mostRecent(): CallInfo; + mostRecent(): CallInfo; /** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call */ - first(): CallInfo; + first(): CallInfo; /** By chaining the spy with calls.reset(), will clears all tracking for a spy */ reset(): void; } - interface CallInfo { + interface CallInfo { /** The context (the this) for the call */ object: any; /** All arguments passed to the call */ - args: Parameters; + args: Parameters; /** The return value of the call */ - returnValue: ReturnType; + returnValue: ReturnType; } interface Util { diff --git a/types/jasmine/ts3.1/jasmine-tests.ts b/types/jasmine/ts3.1/jasmine-tests.ts index 90f5a53bd8..e84072b0eb 100644 --- a/types/jasmine/ts3.1/jasmine-tests.ts +++ b/types/jasmine/ts3.1/jasmine-tests.ts @@ -15,23 +15,29 @@ describe("A suite is just a function", () => { }); }); -describe("The 'toBe' matcher compares with ===", () => { - it("and has a positive case", () => { - expect(true).toBe(true); - }); - - it("and can have a negative case", () => { - expect(false).not.toBe(true); - }); -}); - describe("Included matchers:", () => { - it("The 'toBe' matcher compares with ===", () => { - const a = 12; - const b = a; + describe('toBe', () => { + it("and has a positive case", () => { + expect(true).toBe(true); + }); - expect(a).toBe(b); - expect(a).not.toBe(24); + it("and can have a negative case", () => { + expect(false).not.toBe(true); + }); + + it("the 'toBe' matcher compares with ===", () => { + const a = 12; + const b = a; + + expect(a).toBe(b); + expect(a).not.toBe(24); + }); + + it('should allow to accept any union type', () => { + const value: number | string = null as any; + + expect(value).toBe(12); + }); }); describe("The 'toEqual' matcher", () => { @@ -211,7 +217,9 @@ describe("toBePositiveInfinity", () => { }); describe("toHaveClass", () => { - expect("").toHaveClass(Array); + const element: HTMLElement = null!; + expect(element).toHaveClass("some-class"); + expect(element).toHaveClass(Element); // $ExpectError }); describe("A spec", () => { @@ -398,22 +406,19 @@ describe("A spy, when configured to call through", () => { }); describe("A spy, when configured to fake a return value", () => { - var foo: any, bar: any, fetchedBar: any; - - beforeEach(() => { - foo = { - setBar: (value: any) => { - bar = value; - }, - getBar: () => { - return bar; - } - }; + var bar: number; + const foo = { + setBar: (value: number) => { + bar = value; + }, + getBar: () => { + return bar; + } + }; + it("verifies return value type", () => { spyOn(foo, "getBar").and.returnValue(745); - - foo.setBar(123); - fetchedBar = foo.getBar(); + spyOn(foo, "getBar").and.returnValue("42"); // $ExpectError }); it("tracks that the spy was called", () => { @@ -425,6 +430,8 @@ describe("A spy, when configured to fake a return value", () => { }); it("when called returns the requested value", () => { + const fetchedBar = foo.getBar(); + expect(fetchedBar).toEqual(745); }); }); @@ -722,6 +729,29 @@ describe("A spy, when created manually", () => { }); }); +describe("Spy for generic method", () => { + interface Test { + method(): Array>; + } + + interface Box { + value: T; + } + + it("should allow to configure generic method", () => { + const spy = jasmine.createSpyObj('test', ['method']); + + spy.method.and.returnValue([{ value: 1 }, { value: 2 }]); + }); + + it("should allow to configure generic method with non-named spy", () => { + const spy = jasmine.createSpyObj(['method']); + jasmine.createSpyObj(['methodUnknown']); // $ExpectError + + spy.method.and.returnValue([{ value: 1 }, { value: 2 }]); + }); +}); + describe("Multiple spies, when created manually", () => { class Tape { private rewindTo: number; @@ -772,6 +802,12 @@ describe("Multiple spies, when created manually", () => { it("tracks all the arguments of its calls", () => { expect(tape.rewind).toHaveBeenCalledWith(0); + expect(tape.rewind).toHaveBeenCalledWith('42'); // $ExpectError + expect(tape.rewind).toHaveBeenCalledWith(jasmine.anything()); + expect(tape.rewind).toHaveBeenCalledWith(jasmine.falsy()); + expect(tape.rewind).not.toHaveBeenCalledWith(1); + expect(tape.rewind).not.toHaveBeenCalledWith('42'); // $ExpectError + expect(tape.rewind).not.toHaveBeenCalledWith(jasmine.truthy()); }); it("read isPlaying property", () => { @@ -786,13 +822,19 @@ describe("multiple spies, when created with spyOnAllFunctions", () => { y: (a: number) => a, }; - spyOnAllFunctions(obj); + const spy = spyOnAllFunctions(obj); + + spy.x.and.returnValue(42); + spy.y.and.returnValue(24); + spy.z; // $ExpectError obj.x(0); obj.y(1); expect(obj.x).toHaveBeenCalled(); expect(obj.y).toHaveBeenCalledWith(1); + expect(spy.y).toHaveBeenCalledWith(1); + expect(spy.y).toHaveBeenCalledWith("one"); // $ExpectError }); }); @@ -806,6 +848,9 @@ describe("jasmine.any", () => { it("matches any value", () => { expect({}).toEqual(jasmine.any(Object)); expect(12).toEqual(jasmine.any(Number)); + expect(42).toEqual(jasmine.any(42)); // $ExpectError + expect({}).toEqual(jasmine.any({})); // $ExpectError + expect(() => null).toEqual(jasmine.any(Function)); }); it("matches any function", () => { @@ -819,7 +864,7 @@ describe("jasmine.any", () => { fn2: (param1: number) => param1, }; - const expected: Test = { + const expected = { fn1: jasmine.any(Function), fn2: jasmine.any(Function), }; @@ -827,6 +872,29 @@ describe("jasmine.any", () => { expect(a).toEqual(expected); }); + it("matches custom types", () => { + class Test { } + + const obj = new Test(); + + expect(obj).toEqual(jasmine.any(Test)); + }); + + it("matches base abstract class", () => { + abstract class TestClassBase { } + class TestClass extends TestClassBase { } + const obj = new TestClass(); + + expect(obj).toEqual(jasmine.any(TestClass)); + expect(obj).toEqual(jasmine.any(TestClassBase)); + }); + + it("matches symbols", () => { + const sym = Symbol('test symbol'); + + expect(sym).toEqual(jasmine.any(sym)); + }); + describe("when used with a spy", () => { it("is useful for comparing arguments", () => { const foo = jasmine.createSpy('foo'); @@ -836,6 +904,15 @@ describe("jasmine.any", () => { expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function)); }); + + it("is useful for comparing arguments for typed spy", () => { + const foo = jasmine.createSpy<(num: number, fn: () => boolean) => void>('foo'); + foo(12, () => { + return true; + }); + + expect(foo).toHaveBeenCalledWith(jasmine.any(Number), jasmine.any(Function)); + }); }); }); @@ -920,7 +997,7 @@ describe("jasmine.objectContaining", () => { describe("when used with a spy", () => { it("is useful for comparing arguments", () => { - const callback = jasmine.createSpy('callback'); + const callback = jasmine.createSpy<(arg: { bar: string }) => void>('callback'); callback({ bar: "baz" @@ -951,9 +1028,18 @@ describe("jasmine.arrayContaining", () => { expect(foo).not.toBe(jasmine.arrayContaining([6])); }); + it("matches read-only array", () => { + const bar: ReadonlyArray = [1, 2, 3, 4]; + + expect(bar).toEqual(jasmine.arrayContaining([3, 1])); + expect(bar).not.toEqual(jasmine.arrayContaining([6])); + + expect(bar).toBe(jasmine.arrayContaining([3, 1])); + }); + describe("when used with a spy", () => { it("is useful when comparing arguments", () => { - const callback = jasmine.createSpy('callback'); + const callback = jasmine.createSpy<(numbers: number[]) => void>('callback'); callback([1, 2, 3, 4]); @@ -980,7 +1066,7 @@ describe("jasmine.arrayWithExactContents", () => { describe("when used with a spy", () => { it("is useful when comparing arguments", () => { - const callback = jasmine.createSpy('callback'); + const callback = jasmine.createSpy<(arg: number[]) => void>('callback'); callback([1, 2, 3, 4]); @@ -1274,16 +1360,6 @@ describe('better typed spys', () => { // $ExpectType (val: string) => Spy<() => string> spyObj.method.and.returnValue; }); - - it('has a way to opt out of inferred function types', () => { - interface I { - f(): string; - f(x: any): number; - } - - const spyObject = jasmine.createSpyObj>("spyObject", ["f"]); - spyObject.f.and.returnValue("a string - working"); - }); }); }); @@ -1439,7 +1515,34 @@ describe('Static Matcher Test', function() { }) ); }); - }); +}); + +describe("User scenarios", () => { + describe("https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34080", () => { + interface Test { + f(): string; + f(x: any): number; + } + + it("has a way to opt out of inferred function types", () => { + const spyObject: jasmine.NonTypedSpyObj = jasmine.createSpyObj("spyObject", ["f"]); + spyObject.f.and.returnValue("a string - working"); + + const spy2 = jasmine.createSpyObj(['f']); + spy2.f.and.returnValue("can return string" as any); + }); + + it("should be possible to opt out for spyOn", () => { + const obj: Test = null!; + + const spy1: jasmine.Spy = spyOn(obj, "f"); + spy1.and.returnValue("can return string"); + + const spy2 = spyOn(obj, "f"); + spy2.and.returnValue("can return string" as any); + }); + }); +}); (() => { // from boot.js diff --git a/types/jasminewd2/index.d.ts b/types/jasminewd2/index.d.ts index 7e75d87991..de136639f5 100644 --- a/types/jasminewd2/index.d.ts +++ b/types/jasminewd2/index.d.ts @@ -5,7 +5,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.8 -/// +/// declare function it(expectation: string, assertion?: (done: DoneFn) => Promise, timeout?: number): void; declare function fit(expectation: string, assertion?: (done: DoneFn) => Promise, timeout?: number): void; diff --git a/types/saywhen/saywhen-tests.ts b/types/saywhen/saywhen-tests.ts index 6bbb0c1aaf..890f60d0f8 100644 --- a/types/saywhen/saywhen-tests.ts +++ b/types/saywhen/saywhen-tests.ts @@ -18,5 +18,5 @@ type Top = typeof top; declare function expectMatcherProxyTop(x: (arg: Top) => boolean): void; expectMatcherProxyTop(when.captor()); -when.captor(jasmine.any(Number)); // $ExpectType MatcherProxy +when.captor(jasmine.any(Number)); // $ExpectType MatcherProxy> when.noConflict(); // $ExpectType void