Allow other expected values to be nested in jasmine.objectContaining for TypeScript 3.1+ (#43204)

* [jasmine] Fix unit tests for jasmine.objectContaining to use $ExpectError instead of commments

* [jasmine] Fix type definitions for jasmine.objectContaining when using TypeScript 3.1+
This commit is contained in:
coyoteecd 2020-03-23 17:31:47 +02:00 committed by GitHub
parent 4c9daf7346
commit cda398260e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 25 deletions

View File

@ -1042,6 +1042,9 @@ describe("jasmine.objectContaining", () => {
a: number;
b: number;
bar: string;
nested: {
child: string;
};
}
var foo: fooType;
@ -1049,24 +1052,57 @@ describe("jasmine.objectContaining", () => {
foo = {
a: 1,
b: 2,
bar: "baz"
bar: "baz",
nested: {
child: 'child-baz'
}
};
});
it("matches objects with the expect key/value pairs", () => {
// not explictly providing the type on objectContaining only guards against
// missmatching types on know properties
it("matches objects with the correct type for known properties", () => {
// not explicitly providing the type on objectContaining only guards against
// mismatching types on known properties
// this does not cause an error as the compiler cannot infer the type completely
expect(foo).not.toEqual(jasmine.objectContaining({
a: 37,
foo: 2, // <-- this does not cause an error as the compiler cannot infer the type completely
// b: '123', <-- this would cause an error as `b` defined as number in fooType
foo: 2,
}));
// explictly providing the type on objectContaining makes the guard more precise
// Contrary to the test in v2/jasmine-tests.ts, this does not cause an error
// even though `b` is defined as number in fooType.
//
// This is because the type definition of jasmine.Expected<T> matches the return type of jasmine.objectContaining(),
// which is jasmine.ObjectContaining<{ a: number; b: string; }>
//
// Not sure how to fix this without breaking backwards compatibility in type definitions, so I'll let it be for the moment
expect(foo).not.toEqual(jasmine.objectContaining({
a: 37,
b: '123',
}));
});
it("matches objects with the exact property names when providing a generic type", () => {
// explicitly providing the type on objectContaining makes the guard more precise
// as misspelled properties are detected as well
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
bar: '',
// foo: 1, <-- this would cause an error as `foo` is not defined in fooType
foo: 1, // $ExpectError
}));
});
it("matches objects with jasmine matchers as property values when providing a generic type", () => {
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
b: jasmine.any(Number),
bar: jasmine.stringMatching('ba'),
}));
});
it("matches objects with jasmine matchers as nested property values when providing a generic type", () => {
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
nested: jasmine.objectContaining({
child: jasmine.stringMatching('child')
})
}));
});

View File

@ -266,7 +266,7 @@ declare namespace jasmine {
function arrayContaining<T>(sample: ArrayLike<T>): ArrayContaining<T>;
function arrayWithExactContents<T>(sample: ArrayLike<T>): ArrayContaining<T>;
function objectContaining<T>(sample: Partial<T>): ObjectContaining<T>;
function objectContaining<T>(sample: {[K in keyof T]?: ExpectedRecursive<T[K]>}): ObjectContaining<T>;
function setDefaultSpyStrategy<Fn extends Func = Func>(and: SpyAnd<Fn>): void;
function createSpy<Fn extends Func>(name?: string, originalFn?: Fn): Spy<Fn>;
@ -311,7 +311,7 @@ declare namespace jasmine {
new?(sample: ArrayLike<T>): ArrayLike<T>;
}
interface ObjectContaining<T> extends AsymmetricMatcher<any> {
interface ObjectContaining<T> extends AsymmetricMatcher<T> {
new?(sample: {[K in keyof T]?: any}): {[K in keyof T]?: any};
jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean;

View File

@ -1042,6 +1042,9 @@ describe("jasmine.objectContaining", () => {
a: number;
b: number;
bar: string;
nested: {
child: string;
};
}
var foo: fooType;
@ -1049,24 +1052,57 @@ describe("jasmine.objectContaining", () => {
foo = {
a: 1,
b: 2,
bar: "baz"
bar: "baz",
nested: {
child: 'child-baz'
},
};
});
it("matches objects with the expect key/value pairs", () => {
// not explictly providing the type on objectContaining only guards against
// missmatching types on know properties
it("matches objects with the correct type for known properties", () => {
// not explicitly providing the type on objectContaining only guards against
// mismatching types on known properties
// this does not cause an error as the compiler cannot infer the type completely
expect(foo).not.toEqual(jasmine.objectContaining({
a: 37,
foo: 2, // <-- this does not cause an error as the compiler cannot infer the type completely
// b: '123', <-- this would cause an error as `b` defined as number in fooType
foo: 2,
}));
// explictly providing the type on objectContaining makes the guard more precise
// Contrary to the test in ../v2/jasmine-tests.ts, this does not cause an error
// even though `b` is defined as number in fooType.
//
// This is because the type definition of jasmine.Expected<T> matches the return type of jasmine.objectContaining(),
// which is jasmine.ObjectContaining<{ a: number; b: string; }>
//
// Not sure how to fix this without breaking backwards compatibility in type definitions, so I'll let it be for the moment
expect(foo).not.toEqual(jasmine.objectContaining({
a: 37,
b: '123',
}));
});
it("matches objects with the exact property names when providing a generic type", () => {
// explicitly providing the type on objectContaining makes the guard more precise
// as misspelled properties are detected as well
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
bar: '',
// foo: 1, <-- this would cause an error as `foo` is not defined in fooType
foo: 1, // $ExpectError
}));
});
it("matches objects with jasmine matchers as property values when providing a generic type", () => {
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
b: jasmine.any(Number),
bar: jasmine.stringMatching('ba'),
}));
});
it("matches objects with jasmine matchers as nested property values when providing a generic type", () => {
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
nested: jasmine.objectContaining({
child: jasmine.stringMatching('child')
})
}));
});

View File

@ -758,20 +758,30 @@ describe("jasmine.objectContaining", () => {
};
});
it("matches objects with the expect key/value pairs", () => {
// not explictly providing the type on objectContaining only guards against
// missmatching types on know properties
it("matches objects with the correct type for known properties", () => {
// not explicitly providing the type on objectContaining only guards against
// mismatching types on known properties
// this does not cause an error as the compiler cannot infer the type completely
expect(foo).not.toEqual(jasmine.objectContaining({
a: 37,
foo: 2, // <-- this does not cause an error as the compiler cannot infer the type completely
// b: '123', <-- this would cause an error as `b` defined as number in fooType
foo: 2,
}));
// explictly providing the type on objectContaining makes the guard more precise
// this causes an error as `b` defined as number in fooType
// $ExpectError
expect(foo).not.toEqual(jasmine.objectContaining({
a: 37,
b: '123',
}));
});
it("matches objects with the exact property names when providing a generic type", () => {
// explicitly providing the type on objectContaining makes the guard more precise
// as misspelled properties are detected as well
expect(foo).not.toEqual(jasmine.objectContaining<fooType>({
bar: '',
// foo: 1, <-- this would cause an error as `foo` is not defined in fooType
foo: 1, // $ExpectError
}));
});