jasmine-auto-spies
Important: RxJS 6 compatibility
For RxJS 6, please use version 2.x
and above.
What is it?
Creating spies has never been EASIER! 💪👏
If you need to create a spy from any class, just do:
const myServiceSpy = createSpyFromClass(MyService);
THAT'S IT!
If you're using TypeScript, you get EVEN MORE BENEFITS:
const myServiceSpy: Spy<MyService> = createSpyFromClass(MyService);
Now you can autocomplete AND have an auto spy for each method, returning Observable / Promise specific control methods.
What is it good for?
✅ Keep you tests DRY - no more repeated spy setup code, no need for separate spy files
✅ Type completion for both the original Class and the spy methods
✅ Automatic return type detection by using a simple decorator
Installation
npm install -D jasmine-auto-spies
Usage (JavaScript)
import { createSpyFromClass } from 'jasmine-auto-spies';
import { MyService } from './my-service';
import { MyComponent } from './my-component';
describe('MyComponent', ()=>{
let myServiceSpy;
let componentUnderTest;
beforeEach(()=>{
myServiceSpy = createSpyFromClass(MyService);
componentUnderTest = new MyComponent(myServiceSpy);
});
it('should get data on init', ()=>{
const fakeData = [{fake: 'data'}];
myServiceSpy.getData.and.returnWith(fakeData);
componentUnderTest.init();
expect(myServiceSpy.getData).toHaveBeenCalled();
expect(componentUnderTest.compData).toEqual(fakeData);
});
});
export class MyComponent{
constructor(myService){
this.myService = myService;
}
init(){
this.compData = this.myService.getData();
}
}
export class MyService{
getData{
return [
{ ...someRealData... }
]
}
}
Usage (TypeScript)
TypeScript Setup
Set these 2 properties in your tsconfig.json
-
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
}
}
1. Spying on regular sync methods
import { Spy, createSpyFromClass } from 'jasmine-auto-spies';
import { MyService } from './my-service';
let myServiceSpy: Spy<MyService>;
beforeEach( ()=> {
myServiceSpy = createSpyFromClass( MyService );
});
it('should Do something' ()=> {
myServiceSpy.getName.and.returnValue('Fake Name');
... (the rest of the test) ...
});
class MyService{
getName(): string{
return 'Bonnie';
}
}
2. Spy on a Promise
returning method
First, annotate the method with @AsyncSpyable
-
import { AsyncSpyable } from 'jasmine-auto-spies';
export class MyService{
@AsyncSpyable()
getItems(): Promise<any> {
return Promise.resolve( itemsList );
}
}
Now you can use the resolveWith
or rejectWith
methods -
import { Spy, createSpyFromClass } from 'jasmine-auto-spies';
let myServiceSpy: Spy<MyService>;
beforeEach( ()=> {
myServiceSpy = createSpyFromClass( MyService )
});
it( ()=>{
myServiceSpy.getItems.and.resolveWith( fakeItemsList );
myServiceSpy.getItems.and.rejectWith( fakeError );
});
3. Spy on a Observable
returning method
First, annotate your Observable returning method with @AsyncSpyable
-
import { AsyncSpyable } from 'jasmine-auto-spies';
export class MyService{
@AsyncSpyable()
getProducts(): Observable<any> {
return Observable.of( productsList );
}
}
Now you can use the nextWith
or nextWithError
methods -
import { Spy, createSpyFromClass } from 'jasmine-auto-spies';
let myServiceSpy: Spy<MyService>;
beforeEach( ()=> {
myServiceSpy = createSpyFromClass( MyService )
});
it( ()=>{
myServiceSpy.getProducts.and.nextWith( fakeProductsList);
myServiceSpy.getProducts.and.nextWithError( fakeError );
});
Manual Setup
If you need to manually configure async methods by names you could pass them as arrays of strings -
let spy = createSpyFromClass(
MyClass,
['promiseMethod1', 'promiseMethod2'],
['observableMethod1', 'observableMethod2']
);