- Version
2.x
and above requires RxJS 6.0 and above. - Version
3.x
and above requires TypeScript 2.8 and above.
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.
β 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
npm install -D jasmine-auto-spies
// my-spec.js
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);
});
});
// my-component.js
export class MyComponent{
constructor(myService){
this.myService = myService;
}
init(){
this.compData = this.myService.getData();
}
}
// my-service.js
export class MyService{
getData{
return [
{ ...someRealData... }
]
}
}
Set these 2 properties in your tsconfig.json
-
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
}
}
// my-spec.ts
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) ...
});
// my-service.ts
class MyService{
getName(): string{
return 'Bonnie';
}
}
First, annotate the method with @AsyncSpyable
-
import { AsyncSpyable } from 'jasmine-auto-spies';
export class MyService{
@AsyncSpyable() // <-- MUST ADD THIS
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 );
// OR
myServiceSpy.getItems.and.rejectWith( fakeError );
});
First, annotate your Observable returning method with @AsyncSpyable
-
import { AsyncSpyable } from 'jasmine-auto-spies';
export class MyService{
@AsyncSpyable() // <-- MUST ADD THIS
getProducts(): Observable<any> {
return Observable.of( productsList );
}
}
Now you can use the nextWith
or throwWith
and other methods -
import { Spy, createSpyFromClass } from 'jasmine-auto-spies';
let myServiceSpy: Spy<MyService>;
beforeEach( ()=> {
myServiceSpy = createSpyFromClass( MyService )
});
it( ()=>{
myServiceSpy.getProducts.and.nextWith( fakeProductsList );
// OR
myServiceSpy.getProducts.and.nextOneTimeWith( fakeProductsList ); // emits one value and completes
// OR
myServiceSpy.getProducts.and.throwWith( fakeError );
// OR
myServiceSpy.getProducts.and.complete();
});
You can setup the expected arguments ahead of time
by using calledWith
like so:
myServiceSpy.getProducts.calledWith(1).returnValue(true)
is equal to:
myServiceSpy.getProducts.and.returnValue(true)
expect(myServiceSpy.getProducts).toHaveBeenCalledWith(1);
You can also use it with async method:
myServiceSpy.getProducts.calledWith(1).resolveWith(true)
// OR
myServiceSpy.getProducts.calledWith(1).nextWith(true)
// OR ANY OTHER ASYNC CONFIGURATION METHOD...
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']
);