I use a http-stubs during an development of application prototype with ember-cli.
What I want is to to reuse that stubs in the test environment, but can't figure out how because of looks like ember-cli use a fixture adapter for the test environment.
There was a PR to allow the use of the HTTP Mocks during testing, which sounds like what you are describing, but it was determined that this is not a good way to test your application.
From the issue discussing including the mocks, this comment stated:
...We can to an agreement that mocks are useful for development but are an anti-pattern in testing. We decided that instead of spending time making mocks working in ember test --server we are going to show how to do proper mocking in testing using Pretender.
Stefan showed me an example of mocking with Pretender and the test code is much more readable than having mock server with responses hidden away in the ./server configuration. I'm going to spend some time this weekend looking at what can be scavenged from related PR...
An example from stefanpenner on how to set up pretender for testing was included in the original issue and can be found here.
An example test from that example looks like this:
test('searching', () => {
server.get('/jobs', json(200, {
jobs: [
job({ title: 'UI Engineer' }),
job({ location: 'Palo Alto', title: 'UI Engineer' }),
job({ location: 'Palo Alto', title: 'Backend Engineer'}),
]
}));
server.get('/companies', json(200, {
companies: []
}));
return visit('/').then(() => {
equal(numberOfJobs(), 3, 'expected 3 jobs');
fillIn($('#search-field'), 'UI').then(() => {
equal(numberOfJobs(), 2, 'expected 2 jobs');
});
fillIn($('#search-field'), 'ASDFASDF').then(() => {
equal(numberOfJobs(), 0, 'expected 0 jobs');
});
fillIn($('#search-field'), 'Palo alto').then(() => {
equal(numberOfJobs(), 2, 'expected 2 jobs');
});
return fillIn($('#search-field'), '').then(() => {
equal(numberOfJobs(), 3, 'expected 3 jobs');
});
});
});
Related
I am using the BsModalRef for showing modals and sending data using the content property. So we have some like this :
this.followerService.getFollowers(this.bsModalRef.content.channelId).subscribe((followers) => {
this.followerList = followers;
this.followerList.forEach((follower) => {
follower.avatarLink = this.setUserImage(follower.userId);
this.followerEmails.push(follower.email);
});
});
We are setting the channelId in content of bsModalRef (this.bsModalRef.content.channelId). It is working fine. Now i am writing a unit test for this. Problem is i am not able to mock it. I have tried overriding, spy etc but nothing seems to work. I am using the approach mentioned in this link. One alternative is to use TestBed but i am not much aware of its use. Can anyone please help me finding any approach by which this can be achieved ?
I recently had to do something similar and Mocking the method call worked. The tricky part is injecting the BsModalService in both the test suite and the component.
describe('MyFollowerService', () => {
configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [...],
providers: [...]
}).compileComponents();
});
// inject the service
beforeEach(() => {
bsModalService = getTestBed().get(BsModalService);
}
it('test', () => {
// Mock the method call
bsModalService.show = (): BsModalRef => {
return {hide: null, content: {channelId: 123}, setClass: null};
};
// Do the test that calls the modal
});
});
As long as you're calling bsModal as follows this approach will work
let bsModalRef = this.modalService.show(MyChannelModalComponent));
Finally, here are some links that have more indepth coverage about setting up the tests with TestBed.
https://chariotsolutions.com/blog/post/testing-angular-2-0-x-services-http-jasmine-karma/
http://angulartestingquickstart.com/
https://angular.io/guide/testing
is there a way to stub a function using jest API?
I'm used to working with sinon stub, where I can write unit-tests with stubs for any function call coming out of my tested unit-
http://sinonjs.org/releases/v1.17.7/stubs/
for example-
sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]);
With jest you should use jest.spyOn:
jest
.spyOn(jQuery, "ajax")
.mockImplementation(({ success }) => success([ 1, 2, 3 ]));
Full example:
const spy = jest.fn();
const payload = [1, 2, 3];
jest
.spyOn(jQuery, "ajax")
.mockImplementation(({ success }) => success(payload));
jQuery.ajax({
url: "https://example.api",
success: data => spy(data)
});
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(payload);
You can try live example on codesandbox: https://codesandbox.io/s/018x609krw?expanddevtools=1&module=%2Findex.test.js&view=editor
Jest provides jest.fn(), which has some basic mocking and stubbing functionality.
If you're experienced and comfortable with sinon you could still create Jest-based tests which use sinon test doubles. However you'll lose the convenience of built in Jest matchers such as expect(myStubFunction).toHaveBeenCalled().
Doing following two thing, got it working for me.
Adding __esModule:true fixed this issue for me.
jest.mock('module',()=>({ __esModule: true, default: jest.fn() }));
Moving the mocking part before the describe. (Just after the imports.)
//moving it to before the describe ->
jest.mock(...); describe('', ...);
Hope this helps somebody.
I was able to sub out jquery entirely by using mockReturnValue and jquery's $.Deferred. This allowed me to manually resolve my ajax calls and then the rest of the function would continue (and any chaining of .done() or .success() etc would execute.
Example:
const deferred = new $.Deferred();
$.ajax = jest.fn().mockReturnValue(deferred);
myClass.executeAjaxFunction();
const return_val = 7;
deferred.resolve(return_val)
Then if I have a function like
$.ajax({
type: 'GET',
url: '/myurl'
}).done((val) => {
window.property = val;
});
The following test will pass
it('should set my property correctly', () => {
expect(window.property).toBe(7);
});
Of course- you can skip the deferred part of this answer if you are trying to stub a non-jquery function. I came across this question that dealt with ajax and came up with this solution as a way to test a function that executes actions after an ajax call is complete using Jest.
Got a couple of problems with my unit testing with Jasmine. First one:
I need to test this in a Component called CaseList:
gotoDetail(case: Case){
this._router.navigate(['CaseDetail', {"id": case.id}]);
}
All my attempts at the tests give the error is this._router is undefined, well that's because I haven't defined it in my test, as I can't figure out how! I haven't even come up with any good attempts at the tests, as I have no idea how to proceed. So that's why I haven't posted any attempt here...
Edit: The part in the router-test which is related to to the problem above, but I test all the routing in a separate file! This test works!
it('Should navigate to Case Detail List', (done) => {
router.navigate(['CaseDetail', {id: 'test'}]).then(() => {
expect(location.path()).toEqual('/casedetail/test');
done();
}).catch(e => done.fail(e));
});
Second tests from a Detail Component (where user is navigated after choosing case) :
addStep(){
this.case.getSteps().push(new Step());
}
I also have a remove method I need to test:
removeStep(step: Step){
this.case.removeStep(step);
}
Constructor for this component:
constructor(public _routeParams: RouteParams, public _service: Service) {
this.case = _service.getById(_routeParams.get('id'));
}
So the test I tried doing for the add-method:
it('passes new step to case-class', () => {
spyOn(case, 'addStep')
.and.returnValue(Observable.of({complete: true}))
caseDetail.addStep();
expect(case.addStep).toHaveBeenCalledWith(step);
});
So these methods call the methods that are in a separate class called "Case".
The error I'm getting when testing these are that case is null. I guess the routing and service messes it up, as in the same Component I have a other "identical" methods, and testing those works fine. But they belong to a different class.
Method in same component, referring to a "Step"-class:
addFeedback(step: Step){
step.addFeedback(new Feedback());
}
The testing works perfectly:
it('passes feedback value to Step class', () => {
spyOn(step, 'addFeedback')
.and.returnValue(Observable.of({complete: true}))
caseDetail.addFeedback(step);
expect(step.addFeedback).toHaveBeenCalledWith(feedback);
})
So obviously in testing the component I should have everything defined that is needed, since the testing of the feedback method works. I just need to define the "case" object somehow, so that it doesn't complain about it being null.
Well hopefully you get my problem at hand and hopefully you can help! :)
For your test cases to work, you will have to add router and case as a provider before the test.
Routing Example:
import {RootRouter} from 'angular2/src/router/router';
import {Location, RouteParams, Router, RouteRegistry, ROUTER_PRIMARY_COMPONENT} from 'angular2/router';
import {SpyLocation} from 'angular2/src/mock/location_mock';
import {provide} from 'angular2/core';
describe('Router', () => {
let location, router;
beforeEachProviders(() => [
RouteRegistry,
provide(Location, {useClass: SpyLocation}),
provide(Router, {useClass: RootRouter}),
provide(ROUTER_PRIMARY_COMPONENT, {useValue: App}),
]);
beforeEach(inject([Router, Location], (_router, _location) => {
router = _router;
location = _location;
}));
it('Should be able to navigate to Home', done => {
router.navigate(['Index']).then(() => {
expect(location.path()).toBe('');
done();
}).catch(e => done.fail(e));
});
});
Case Provider:
import {Case} from '../case';
beforeEachProviders(() => [
provide(case, Case)
]);
Scenario
I am in the process of writing a number of jasmine tests for a Durandal based app that I am in the process of writing. The Durandal documentation suggests that the way to write tests is like
ViewModel
define([
'knockout',
'plugins/router',
'services/unitofwork',
'services/logger',
'services/errorhandler',
'services/config'
],
function (ko, router, unitofwork, logger, errorhandler, config) {
var uow = unitofwork.create();
var searchTerm = ko.observable();
var results = ko.observableArray([]);
var search = function () {
uow.myySearch(searchTerm).then(function (data) {
results(data);
logger.log(data.length + ' records found', '', 'myViewModel', true);
});
};
var vm = {
search : search,
searchTerm : searchTerm,
results : results
};
});
Test
define(['viewmodels/myViewModel'], function (myViewModel) {
describe('Stuff im testing', function(){
it('returns true', function () {
expect(true).toBe(true);
});
});
});
and for most of my tests this works great.
Problem
How do I mock/stub/fake a module that has been passed into ViewModel. For instance the UnitOfWork module so that it always returns a standard set of data.
For unit testing check out https://github.com/iammerrick/Squire.js/ a dependency mocker for requirejs. Another technique using require context is described in How can I mock dependencies for unit testing in RequireJS?.
For integration testing you might look into something like http://saucelabs.com (selenium based).
For some grunt tasks that helps setting up unit tests in phantomjs|browser see https://github.com/RainerAtSpirit/HTMLStarterKitPro (Disclaimer: I'm the maintainer of the repo). I'd love to see some mockup integration, so send a pull request if you feel inclined.
Check this out
https://github.com/danyg/jasmine-durandal
this is a library that I'm working on, in a few days will have the ability to test widgets too.
I'm trying to do a Jasmine test of ember-data (using the current master) using the DS.FixtureAdapter. I've tried dozens of variations on the below code (with and without trying to create an Application namespace). I've also gone into the ember-data source to try and see what's going on, as well as referenced the tests in ember-data itself as an example.
I've also tried variations of Person.find(1), using Ember.run blocks and Jasmine wait()'s.
Whatever I try, store.find(Person, 'test') returns a result but attempting to get one of the attributes results in null (test assertion fails). What is it I'm not seeing? Thanks for any help!
describe "a test", ->
store = null
Person = null
beforeEach ->
store = DS.Store.create
revision: 11
adapter: 'DS.FixtureAdapter'
Person = DS.Model.extend
firstName: DS.attr('string')
lastName: DS.attr('string')
age: DS.attr('number')
it "works or does it", ->
Person.FIXTURES = [{
id: 'test'
firstName: 'Kyle'
lastName: 'Stevens'
age: 30
}]
kyle = store.find(Person, 'test')
expect(Em.get(kyle, 'firstName')).toEqual('Kyle')
Whatever I try, store.find(Person, 'test') returns a result but attempting to get one of the attributes results in null (test assertion fails). What is it I'm not seeing? Thanks for any help!
This is a timing issue. When you call store.find() it runs query asynchronously and returns a model promise. That means the query is still running (or scheduled to run) when control returns to your test, resulting in a failed expectation.
This is what we love about ember, it means your app can treat kyle as if the data were present and trust that values will be updated automagically via bindings when the data becomes available.
Of course all this magic is not so great when it is preventing your test from passing. Here are some alternative approaches:
1) Register a didLoad callback
kyle = store.find(Person, 'test');
kyle.on('didLoad', function() {
console.log('should = kyle: ', Em.get(kyle, 'firstName'));
});
2) Instead of didLoad could use more blackbox testing approach and just verify that the name is set propertly within 100 ms of having called find - of course this can lead to brittle tests
Ember.run.later(this, function() {
console.log('should = kyle: ', Em.get(kyle, 'firstName'));
console.log('should = kim: ', Em.get(App.kim, 'firstName'));
}, 100);
I believe that in a jasmine test you could wrap your setup code in a runs() method and use waitsFor to verify that the value has been set as expected:
waitsFor(function() {
return Em.get(kyle, 'firstName') == 'Kyle';
}, "x to be set to 5", 100);
See this JSBIN for working (non-jasmine) example:
http://jsbin.com/apurac/4/edit
See this post for tips on async testing with jasmine: http://blog.caplin.com/2012/01/17/testing-asynchronous-javascript-with-jasmine/
Also, be sure to set Ember.testing = true for all of your tests. See this SO post for detail: Is it recommended to set Ember.testing = true for unit tests?