Jasmine React Spy not being called? - reactjs

I am new to jasmine testing in react and this is driving me crazy.
I am trying to test a simple button click below. But the spy isn't working.
it('fires the clearTags handler', function() {
var handler = jasmine.createSpy();
var element = ReactTest.renderIntoDocument(
React.createElement(SomeComponent));
spyOn(element,'clearTags')
var clearTagsLink = ReactTest.findRenderedDOMComponentWithClass(element, 'clear-tags-link');
ReactTest.Simulate.click(clearTagsLink);
expect(handler).toHaveBeenCalled();
});
I am getting the error Expected spy unknown to have been called. Any ideas? I have tried using .and.callThrough() but that didn't work either.

Spy's are typically placed on method calls. Any sort of method call within the method being spied on, will not be executed by Jasmine unless you attach and.callThrough like you have done. However you're attaching a spy to a variable and not a method within the React library, which it appears you want to do.
If I'm correct, I would think you would want to setup your spy like so;
spyOn(React, 'createElement');
expect(React.createElement).toHaveBeenCalled();
For a more robust test you would probably want to use the jasmine toHaveBeenCalledWith("passing in parameters") you expected it to be called with.

Related

AngularJS 1.5 calling a method from another in component's controller

I am using angularJS 1.5 component in my application. sample code of component's controller as bellow:
function testController()
{
var vm = this;
activate(); // this will be called on first load on component.
vm.testMethod = function ()
{
return "test Method";
}
function activate()
{
console.log(vm.testMethod());
}
when I execute this I am getting error
TypeError: vm.testMethod is not a function.
I know I can create a local function to controller not appending vm., however, in my need, I have a vm.testMethod() used in template to get return some text, which is working properly. e.g.
--template code
{{$ctrl.testMethod()}} // This works properly and display 'test Method' on page.
Due to some reason, I am trying to call vm.testMethod() inside another method e.g. activate(), however getting an error mentioned above?
May I know if am missing anything or trying something which is not possible.
Your issues does not have anything to do with Angular :-)
Your activate function is hoisted because it is a function declaration. That why you can call it "before your wrote it". BUT, vm.testMethod is a function expression and won't get hoisted.
Here is a super simple example that shows the issue your having:
var vm = {};
console.log(vm.hello);
vm.hello = function () {};
console.log(vm.hello);
I would recommend you to read this article for a better understanding of how expressions and declarations work in JavaScript. Also, in order to prevent this from happening again you should follow this advice from John Papa:
Always write function declarations at the bottom of your controller and assign them at the top when you defined your vm variable.

Can Protractor Jasmine adaptation properly wait for protractor.promise.defer().promise?

First of all, hats off to the Protractor team and community for coming up with such a library for a tough problem to implement such as E2E testing.
I have a wrapper JS Class around an ElementFinder since I wanted to add extra utility methods to inspect the ElementFinder further. When I return an instance of such class objects I return it with:
function myFunc(){
var myElement = element(by.binding('plan.name'));
var deferred = protractor.promise.defer();
var myWrapper = new myElementWrapper(myElement);
deferred.fulfill(myWrapper);
return deferred.promise;
}
Later on I expect the value in Jasmine 2.1 using:
var val=myFunc();
expect(val).not.toBeNull();
According to the official documentation by Protractor queen,#juliemr , the expect is supposed to wait until the promise is resolved. It seems to be breezing by without stopping.
Looking at the instance of promise my code has generated I see that it's of type:goog.scope.promise.Promise. In the Protractor code I've noticed it's using: webdriver.promise.isPromise(res).
I've also tried wrapping the call with flow.execute without success and would like to avoid using series of chained .then calls since it makes the test less readable.
Will that properly wait to resolve my promise above before moving on with the test flow?
If not what is the proper way to create promise object to be properly inspected by Protractor's flavor of expect?
I'm running using the new and shiny Protractor 2.0 release.
You create a deferred then immediately fulfill the deferred and return the promise for it (which is just a complicated way of returning the myWrapper object directly).
Promises are used to represent a value that you don't have yet. I don't see anything in your example that isn't immediately available, so its not clear why you need a promise.
I think you want something like this:
function myFunc() {
var myElement = element(by.binding('plan.name'));
return new myElementWrapper(myElement);
}
Your myElementWrapper should look like a promise if you want to pass it to expect, though (if you extend the existing ElementFinder that should be sufficient).

Angular, sinon stub not performing correctly

I am trying to mock a rootscope for a unit (karma/jasmine) test here, and it doesn't seem to be working. I'm not sure why and could use some help. Here it is :
Declaring it up top :
var mockRootScope = sinon.stub();
Inside the before each :
angularMocks.module(function($provide) {
$provide.value('$rootScope', mockRootScope);
});
Then inside the unit test itself
mockRootScope.returns({
$id: 1
});
console.log(mockRootScope.$id);
the log is coming back undefined. if I log mockRootScope it tells me it's a stub (which is good), but I can't seem to figure out why it isn't returning correct values. Thanks!
Stubs are functions; hence the terminology returns. If you try the following, it will do as you expect:
console.log(mockRootScope().$id) // Should print $id

End-to-End testing with Jasmine

I am trying to perform some end-to-end tests of an application written with AngularJS. Currently, I have the following tests setup in e2e.tests.js:
describe('MyApp', function() {
beforeEach(function() {
browser().navigateTo('../index.html');
});
it('should be true', function() {
expect(true).toBe(true);
});
});
Oddly, this basic test fails. The test itself runs. However the results are:
203ms browser navigate to '../index.html'
5ms expect undefined toBe true
http://localhost:81/tests/e2e.tests.js:10:9
expected true but was undefined
Considering "true" is hard-coded, I would expect it to pass this test. I have no idea how true can be undefined. What am I missing?
The thing about Angular's E2E test framework is that looks like Jasmine, but it is not Jasmine. The E2E test code is actually all asynchronous, but it is written in a clever way so that the calls look normal. Most of the calls create asynchronous tasks and Future objects that are tested later. The Future object is kind of like a promise, but it's a little different. It has a value property that it sets when it's ready, and then it calls a done function to move to the next step. In E2E tests, the expect function takes Future objects, not values. You're seeing undefined because expect is testing against future.value, which in this case is true.value, which is undefined.
Try using one of the available selectors that return futures and then test the result. Something like this:
expect(element("html").text()).toMatch("Our App");
The Future objects are not well documented, but you should be able to create a Future manually like this:
var trueFuture = angular.scenario.Future(
"a true value", // name that is displayed in the results
function(callback) { // "behavior" function
callback(null, true); // supposed to call callback with (error, result)
});
expect(trueFuture).toEqual(true);
If you look in the ng-scenario source code, you can see the place where the matcher tests future.value in the angular.scenario.matcher function.
I too have faced the similar problem and here's what I found.
You must be using ng-scenario as your framework with jasmine in config file.
The fact is that expect function in ng-scenario doesn't take any var value or Boolean value. It only takes functions like
expect(browser().location().path()).toContain('some/string')
or some other ng-scenario function like
expect(element('some element').html()).toContain('some String');
Any variable value or Boolean in expect function is undefined.
If you want to use Boolean(true/false) or you want your test to be passed then you have to remove 'ng-scenario' from your framework section of config file.
Try It with only jasmine!

Why it calls the original method?

I am writing a jasmine spec against my backbone app. However, I got stuck with this problem. Not sure why my spy function doesn't get invoked. I want to make sure when the model is changed, it should call #render.
Here is my backbone view:
class App.Views.Main extends Backbone.View
initialize: () ->
#model.on("change", #render, this)
render: () ->
console.log('rendering')
return
Here is my jasmine spec:
it "should render when change is triggered", ->
renderSpy = sinon.spy(#view, 'render')
#view.model.trigger('change')
expect(renderSpy.called).toBeTruthy()
Another thing that confuses me is that when this spec runs, it actually invokes the original method. The console log is always displayed. Anyone could help me?
Updated:
As answered below by Leonardo, I make changes with the following changes:
it "should render when reset is triggered", ->
renderSpy = sinon.spy(App.Views.Main.prototype, 'render')
#view.model.trigger('change')
expect(#renderSpy.called).toBeTruthy()
renderSpy.restore()
It works, but the problem is that it invokes the original method. I just wonder why?
I think this is the same that is happenning here:
https://stackoverflow.com/a/9012788/603175
Basically, you need to create the spy before you execute the constructor that executes the event listening, which binds the function to 'this' context.

Resources