spyOn method in constructor with jasmine - unit-testing

I want to spyOn a promise and fake that promise in my unit test but the problem is that if I run first the contructor that the problem that he first run the promise and then run the Spyon.
But when i first run the spyOn and then the constructor it gives a error that storage is undefined.
Does someone know how to fix this?
Spec file:
describe('Settings Service', () => {
beforeEach(() => {
settingsService = new SettingsService(); // This gives a error beceause it runs the promise
spyOn(settingsService.storage, 'get').and.callFake((key: String): Promise<string> => {
return new Promise((resolve, reject) => { resolve('url'); });
});
});
constructor:
constructor() {
this.storage = new Storage(LocalStorage);
this.storage.get('url').then(data => {
this.setLink(data);
});
}
UPDATE:
I tried also this:
let injector: any = ReflectiveInjector.resolveAndCreate([SettingsService]);
settingsService = injector.get(SettingsService);
spyOn(settingsService.storage, 'get').and.callFake((key: String): Promise<string> => {
return new Promise((resolve, reject) => { resolve('https://secure.info/pascal'); });
});

The problem you have is that you are instantiating Storage within the constructor, so you have no access to it from the outside. That means that you cannot mock it.
Setting spyOn before calling settingsService = new SettingsService(); doesn't work either because the field storage has not been created yet.
You have two ways to solve this:
Mocking the service $httpBackend using the following code. Take a look at this post as an example
beforeEach(inject(function($injector) {
service = $injector.get('carService');
$httpBackend = $injector.get('$httpBackend');
$httpBackend.when('GET', "/api/cars/types").respond(["Toyota", "Honda", "Tesla"]);
}));
This way you can mock the promise you get when calling this.storage.get('url') and test the behaviour.
Making Storage a service and injecting it mocked: If you use this approach you could moke Storage and therefore mock the behaviour of this.storage.get('url'). The code of your class `` would look like this
static $inject = ['Storage'];
constructor(storage: Storage) {
this.storage = storage;
this.storage.get('url').then(data => {
this.setLink(data);
});
}
But this way depends on how do you define and use Storage so generally the first way will be better

Related

redux-observable unit test epci with dependencies

I have an epic with the following signature (note the dependency)
export const incrementalSearchEpic = (action$, store, { incrementalSearchService }) => {
// eslint-disable-next-line max-len
return action$.ofType('SEARCH_STORES').mergeMap((action) =>
incrementalSearchService.performIncrementalSearch(action)
);
};
Now I need to unit test this and this is my unit testing code
beforeEach(() => {
epicMiddleWare = createEpicMiddleware(incrementalSearchEpic,
{
dependencies: {
incrementalSearchService: IncrementalSearchServiceMock
}
});
const mockStore = configureMockStore([epicMiddleWare]);
const getState = {}; // initial state of the store
store = mockStore(getState);
});
// eslint-disable-next-line max-len
it('calls the incrementalSearchService->performIncrementalSearch with the parameters when called', () => {
//dispatch the incremental search action
const searchStore = {
type: 'SEARCH_STORES',
SearchText: 'Aldi'
};
store.dispatch(searchStore);
expect(store.getActions()).toEqual([
searchStore
]);
});
However when I run the code I get the following error
TypeError: Cannot read property 'performIncrementalSearch' of undefined
Seems like the dependency does not get passed in properly.
I just realized: if redux-observable wasn't injecting the provided dependencies object you'd actually get Cannot read property 'incrementalSearchService' of undefined not performIncrementalSearch because redux-observable does not inject an object by default--it's not erroring because it is indeed passing your object.
Instead, the likely problem is that your import or definition of IncrementalSearchServiceMock is actually undefined. Perhaps a wrong named import or similar.
If you can't immediately see why, pause your debugger at the beginning of beforeEach and confirm the value of IncrementalSearchServiceMock is not undefined.

Mocking an inner require statement in Typescript constructor

I know this is kind of a weird question, but I would like to mock an inner require(); statement in a constructor. This is my test file:
import { PiControl } from "../pi";
describe("PiControl", () => {
beforeEach(() => {
this.piControl = new PiControl();
});
it("Should initialise the control and call the board ready event.", () => {
expect(true).toBe(true);
});
});
As you can see below, I'm instantiating the class PiControl and when I run my test and make an instance of the PiControl.
export class PiControl extends BaseControl {
public board: any;
constructor() {
super();
// No idea if this can be mocked, but I would like to.
const Raspi = require("raspi-io");
const five = require("johnny-five");
const board = new five.Board({
io: new Raspi({ enableSoftPwm: true }),
});
this.board = board;
}
public loadControl(): void {
this.board.on("ready", this.setupMotors);
}
}
As you can see below, that is what the test outputs. It will call the original library (which is supposed to run on a Raspberry PI) and tries to run it on my development machine.
Question: is there a way to workaround this issue?
For what it's worth, I'm testing the whole application using Jest (almost out-of-the-box config).

Angular2 - Call function from a tested component

I'm currently writing unit tests for Angular2 with Karma and Jasmine, but I'm pretty new in the unit testing and I'm facing some difficulties. When it comes to testing hardcoded properties or properties that don't involve async functions, it's all okay, but I need to be able to call the component's functions in order for some variables to get their values. What I'm doing is the following:
My component:
export class LoginComponent implements OnInit {
formLoginId: string;
loginUrl: string;
email: string;
password: string;
constructor(private googleAuthService: GoogleAuthService,
private authService: AuthenticationService,
private validationService: ValidationService,
private router: Router,
private titleService: Title) {
this.titleService.setTitle("Login");
this.formLoginId = "#form-login";
}
ngOnInit() {
this.googleAuthService.getLink((response) => {
this.loginUrl= response.json().url;
});
}
login() {
if (this.validationService.isValid(this.formLoginId)) {
this.authService.login(this.email, this.password);
}
}
Now I want to write a unit test which can check if the loginUrl has taken any value. My test is bellow:
describe('Login Component', ()=> {
let component:LoginComponent;
let fixture:any;
beforeEach(async(()=> {
TestBed.configureTestingModule({
//declarations,imports and providers
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
}); /some-other-tests/
it('should have login url', fakeAsync(()=> {
component.ngOnInit();
tick(1000);
expect(component.loginUrl).toBeDefined();
}));
});
But it seems that its not working. I'm still getting undefined for the mentioned variable. How can I call a method from a component and check the variables after its result?
Thanks!
In this case, you need to mock the GoogleAuthService to return with some information, as otherwise that getLink never resolves.
You can specify a mock provider for the GoogleAuthService and have it return an observable that's already resolved.

Mocking ngrx/store

This is in regards to the Angular 2 official release. I know that unit testing has changed drastically between beta, RC, and the official release.
What's a good way to mock #ngrx/store in a unit test when it's used as a parameter in a constructor? It's not as simple as mocking a service.
For example, if I wanted to mock a service, then I could do something like this:
let serviceStub = { }; // not a true mocked service, just a stub, right?
let de: DebugElement;
let el: HTMLElement;
let nativeEl: Element;
let comp: Typeahead;
let fixture: ComponentFixture<Typeahead>;
describe('Component:Typeahead', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [Typeahead],
providers: [
{provide: TypeaheadService, useValue: serviceStub} // provides the service that is being "mocked"
]
}).compileComponents();
fixture = TestBed.createComponent(Typeahead);
nativeEl = fixture.nativeElement;
comp = fixture.componentInstance;
de = fixture.debugElement;
});
});
And this works.
For ngrx/store, however, it does not (if you substitute Store in for TypeaheadService). I'm thinking you have to write a mock class that extends Store, and then provide that to the component that is being tested, but I'm not sure why that is the case (if that is even the case).
I'm just confused as how to mock ngrx/store in my unit tests and couldn't find any documentation on their site or github. Maybe I overlooked it.
Thank you for posting the question and suggesting a potential solution!
The way I've mocked it is, to use the actual actions to set an initial state i.e. a mocked state before each test. Here's an example
beforeEach(inject([Store], (store: Store<ApplicationState>) => {
const someFakeState = {
counter: 9,
counterFilter: 'A_FAKE_COUNTER_FILTER'
};
store.dispatch(new myActionToSetSomeData(someFakeState));
}));
Inside your it() block you should now be able to check that the component is displaying a count of 9 and a filtering by 'A_FAKE_COUNTER_FILTER'.
You can of course set the state inside your it block, rather than beforeEach, as long as its before the component is instantiated.
You can use forRoot (>= v4) or provideStore ( <= v3) to provide the data to the StoreModule and the rest is done for you:
1 - Import it:
import { StoreModule } from '#ngrx/store';
2 - Create a mock data:
/*
* Mock data
*/
const PAINTS = [];
3 - Import it in you test:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ StoreModule.forRoot(PAINTS) ]
})
}))
In previous versions (before v4), you should use provideStore(PAINTS) instead of forRoot(PAINTS). See the the changelog here
Yes, you do have to mock ngrx/store, but not only Store. Store expects three arguments; one of type Observable, and two of type Observer, which is an interface. So, I tried two things. Passing in null values to the StoreMock super() constructor, but that failed at my assertion. My other solution was to implement the Observer interface with a mock class (Observable in this case). This way I could pass defined values into the super StoreMock constructor.
This is just an illustrative example. The ObservableMock doesn't actually mock any functionality that I'm trying to test in my application. It's serving as an enabler so that Store can be injected as a provider into the Component I'm trying to test.
Since Observer is an interface, you have to implement its function declarations in the mock: next, error, and complete.
class ObservableMock implements Observer<any> {
closed?: boolean = false; // inherited from Observer
nextVal: any = ''; // variable I made up
constructor() {}
next = (value: any): void => { this.nextVal = value; };
error = (err: any): void => { console.error(err); };
complete = (): void => { this.closed = true; }
}
let actionReducer$: ObservableMock = new ObservableMock();
let action$: ObservableMock = new ObservableMock();
let obs$: Observable<any> = new Observable<any>();
class StoreMock extends Store<any> {
constructor() {
super(action$, actionReducer$, obs$);
}
}
And now you can add Store as a provider in your Component's test module.
describe('Component:Typeahead', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [Typeahead],
providers: [
{provide: Store, useClass: StoreMock} // NOTICE useClass instead of useValue
]
}).compileComponents();
});
});
I am sure there are other ways to do it. So if anyone has any other answers, please post them!

Attempted to wrap sendRequest which is already wrapped

I'm writing unit tests using Jasmine for my Backbone cache and am trying to mock up a function response using Sinon.js. For different tests, I expect different things to happen so I am creating a mock before each test and deleting it after, then filling in the expects behavior within the test itself. However, I'm getting an error and the tests are failing.
Here's my spec with just the relevant tests (other tests aren't using mock):
describe("mysite.core.Cache.XFooInfo", function() {
var fnMock;
beforeEach(function() {
fnMock = sinon.mock(fn);
});
afterEach(function() {
delete fnMock;
});
it("should make a request after function fooCreated called", function() {
fnMock.expects("sendRequest").once().withExactArgs("ModuleFoo", "getFoo", ["1000"]);
events.trigger("fooCreated", [{Args:[test.data.XFooInfo]}]);
fnMock.verify();
});
});
describe("mysite.core.Cache.XFooBarInfo", function() {
var fnMock;
beforeEach(function() {
fnMock = sinon.mock(fn);
});
afterEach(function() {
delete fnMock;
});
it("should make a request after function booUpdated called", function() {
var booCopy = $.extend(true, {}, test.data.XBooInfo);
booCopy[0].Args[0].FooID = "12345";
fnMock.expects("sendRequest").once().withExactArgs("ModuleFoo", "getFoo", ["12345"]);
events.trigger("booUpdated", booCopy);
fnMock.verify();
});
});
The first test works fine and passes. The second test, however, gives me this error:
TypeError: Attempted to wrap sendRequest which is already wrapped
at Object.wrapMethod (https://localhost:8443/mysite/web/tests/libs/sinon-1.7.1.js:528:23)
at Object.expects (https://localhost:8443/mysite/web/tests/libs/sinon-1.7.1.js:2092:27)
at null.<anonymous> (https://localhost:8443/mysite/web/shasta-cList-tests/spec/CacheSpec.js:909:15)
at jasmine.Block.execute (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:1024:15)
at jasmine.Queue.next_ (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:2025:31)
at jasmine.Queue.start (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:1978:8)
at jasmine.Spec.execute (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:2305:14)
at jasmine.Queue.next_ (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:2025:31)
at jasmine.Queue.start (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:1978:8)
at jasmine.Suite.execute (https://localhost:8443/mysite/web/tests/libs/jasmine-1.2.0.rc3/jasmine.js:2450:14)
I can't find anything in the Sinon.js docs to tell me what I'm doing wrong. I know verify also does a restore on all the functions it mocks and I thought that it was enough to allow me to write a new expects behavior for the same function, but apparently I was wrong.
What is the right way to do this?
Ok, so after spending 2 hours on this problem last Friday with no luck, I figured it out twenty min after posting this question. Adding var fn.sendRequest = function(module, fnName, args) {}; to the beforeEach function fixed all the failing tests.
this one works too, less to type:
var fn.sendRequest = function () { };