问题
I'm using jasmine on an angular2 project and having some trouble writing a custom matcher for a test. I want to be able to compare two relatively complex objects. I found this article which claims to solve the issue but it simply results in a typescript error stating that it doesn't recognize the new method on jasmine's Matchers
object. The relevant code is this:
declare module jasmine {
interface Matchers {
toBeNumeric(): void;
}
}
Another article gives a similar, but slightly different solution that gives the same error.
declare namespace jasmine {
interface Matchers {
toHaveText(expected: string): boolean;
}
}
I tried this
let m: jasmine.Matchers = expect(someSpy.someMethod).toHaveBeenCalled();
and got this error:
Type 'jasmine.Matchers' is not assignable to type 'jasmine.Matchers'. Two different types with this name exist, but they are unrelated.
That seems to indicate that the declare namespace jasmine
statement is creating a new jasmine
namespace rather than extending the existing one.
So how can I create my own matcher that typescript will be happy with?
回答1:
Daf's answer mostly worked for me I just noticed an issue with his sample code and the way he named his files. I also happened upon another unrelated issue. Hence a new answer.
- For some reason my app does not like it when the interface file has the same name as the matcher file. e.g foo.ts and foo.d.ts. For my app it needed to be foo.ts and foo-interface.d.ts or something like it.
- Also don't import interfaces from foo.ts into foo-interface.d.ts it also does not seem to like this.
Sample custom matcher here: - https://github.com/vespertilian/wallaby-angular-node-yarn-workspaces/tree/master/api/src/test-helpers Sample specs here: - https://github.com/vespertilian/wallaby-angular-node-yarn-workspaces/blob/master/api/src/hello/hello.spec.ts
Matcher - custom-matchers.ts
import MatchersUtil = jasmine.MatchersUtil;
import CustomMatcherFactories = jasmine.CustomMatcherFactories;
import CustomEqualityTester = jasmine.CustomEqualityTester;
import CustomMatcher = jasmine.CustomMatcher;
import CustomMatcherResult = jasmine.CustomMatcherResult;
export const SomeCustomMatchers: CustomMatcherFactories = {
toReallyEqual: function (util: MatchersUtil, customEqualityTester: CustomEqualityTester[]): CustomMatcher {
return {
compare: function (actual: any, expected: any): CustomMatcherResult {
if(actual === expected) {
return {
pass: true,
message: `Actual equals expected`
}
} else {
return {
pass: false,
message: `Actual does not equal expected`
}
}
}
}
}
};
Interface file - matcher-types.d.ts - cannot be the same name as your matcher file
declare namespace jasmine {
interface Matchers<T> {
toReallyEqual(expected: any, expectationFailOutput?: any): boolean;
}
}
Custom matcher test
describe('Hello', () => {
beforeEach(() => {
jasmine.addMatchers(SomeCustomMatchers)
});
it('should allow custom matchers', () => {
expect('foo').toReallyEqual('foo');
expect('bar').not.toReallyEqual('test');
})
});
回答2:
Basically, your second example ("declare namespace") is the way to go, with your logic for the matchers somewhere else, of course.
You're welcome to take a look at https://github.com/fluffynuts/polymer-ts-scratch/tree/5eb799f7c8d144dd8239ab2d2bcc72821327cb24/src/specs/test-utils/jasmine-matchers where I have written some Jasmine matchers and typings to go along with them -- though technically I wrote the actual matchers in Javascript and just named the logic files .ts to placate my build process.
You will need to install @types/jasmine
-- and keep it current.
Just bear in mind that different versions of @types/jasmine
may break things; specifically, the commit linked above was when Jasmine types introduced the Matchers
type having a type parameter (ie, Matchers<T>
) which broke all my .d.ts files.
来源:https://stackoverflow.com/questions/42956195/create-custom-jasmine-matcher-using-typescript