End-to-End testing with Jasmine - angularjs

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!

Related

How to test actions in Flux/React?

I'm trying to figure out how to test actions in flux. Stores are simple enough with the provided example, but there seems to be nothing out there for the actions/data/api layer.
In my particular app, I need to pre-process something before posting it to my server. Based on the advice in this post, I decided to implement the async stuff in my actions. What I can't figure out is how to test this preprocessing.
For example in MissionActions.js:
addMissionFromBank: function(bankMission) {
var mission = new Mission({game: GameStore.getGame().resource_uri, order: Constants.MISSION_ORDER_BASE_INT}).convertBankMission(bankMission);
var order = MissionSort.calcOrderBySortMethod(mission, MissionStore.getMissions(), GameStore.getGame().sort_method);
mission['order'] = order;
AppDataController.addMissionFromBank(mission);
},
In this function, I'm converting a stock mission (bankMission) into a regular mission and saving it to a game with the correct order key. Then I'm posting this new regular mission to my server, the callback of which is handled in my MissionStore.
Since this conversion code is important, I want to write a test for it but can't figure out how to do it since there seems to only be examples for testing stores and React components. Any suggestions?
Are you using the flux dispatcher or requiring AppDataController?
Jest will automatically mock modules that you bring in via browserify's require. If you are importing AppDataController via require, then your test might look like this:
jest.dontMock('MissionAction.js') // or path/to/MissionAction.js
describe('#addMissionFromBank', function(){
beforeEach(function(){
MissionAction.addMissionFromBank(exampleMission);
});
it('calls AppDataController.addMissionFromBank', function(){
expect(AppDataController.addMissionFromBank).toBeCalled());
});
});
you want to call the non-mocked method that youre testing and check that the mock is called. to check if its been called at all use
#toBeCalled()
or if you want to check that its called with a specific value (for instance, check that its called with whatever mission evaluates to) use
#toBeCalledWith(value)
You could mock/spyOn AppDataController, and check that it receives a correct mission object. Something like this in jasmine, I'm not sure if it is the same in jest:
spyOn(AppDataController, 'addMissionFromBank');
MissionActions.addMissionFromBank(someBankMission);
expect(AppDataController.addMissionFromBank).toHaveBeenCalledWith(expectedMission);

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

Dealing synchronously in Protractor tests

I'm trying to write what I think is a fairly simple test in protractor, but it would seem that the minute you try to do anything synchronously, Protractor makes life hard for you! Normally, dealing with locator functions (that return a promise) are not an issue, since any expect statement will automatically resolve any promise statement passed to it before testing the assertion. However, what I'm trying to do involves resolving these locator promises before the expect statement so that I can conditionally execute some test logic. Consider (pseudocode):
// Imagine I have a number of possible elements on the page
// and I wish to know which are on the page before continuing with a test.
forEach(elementImLookingFor){
if (elementImLookingFor.isPresent) {
// record the fact that the element is (or isnt) present
}
}
// Now do something for the elements that were not found
However, in my above example, the 'isPresent' call returns a promise, so can't actually be called in that way. Calling it as a promise (i.e. with a then) means that my forEach block exits before I've recorded if the element is present on the page or not.
I'm drawing a blank about how to go about this, has anyone encountered something similar?
I've used bluebird to do the following;
it('element should be present', function(done)
Promise.cast(elementImLookingFor.isPresent)
.then(function(present){
expect(present).toBeTruthy();
})
.nodeify(done);
});
If you have a few elements that you want to check the isPresent on you should be able to do the following;
it('check all elements are present', function(done){
var promises = [element1, element2].map(function(elm){
return elm.isPresent();
});
// wait until all promises resolve
Promise.all(promises)
.then(function(presentValues){
// check that all resolved values is true
expect(presentValues.every(function(present){
return present;
})).toBeTruthy();
})
.nodeify(done);
});
Hope this helps
So elementImLookingFor is a promise returned by element.all, I presume? Or, as stated in the Protractor documentation, an ElementArrayFinder. You can call the method .each() on it and pass it a function that expects things.

Testing redirection using regex.test() instead of Jasmine expect

I'm testing the redirection after the sign-up of an AngularJs app.
After clicking the registration button i call a function to check if the url matches with targetRegex.
The first code block use Jasmine expect but the i get the error: timeout: timed out after 30000 msec waiting for spec to complete
return browser.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return expect(url).toContain(targetRegex);
});
});
Meanwhile the following code seems working well:
return browser.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return targetRegex.test(url); // look for a match of the regex /profile/ in the 'url'
});
});
Is anybody able to explain me why please?
From the Jasmine docs: The 'toContain' matcher is for finding an item in an Array.
For matching via a regular expression, I think you want to use toMatch instead, as in expect(url).toMatch(targetRegex);.
However, I'm not sure if you want to use that toMatch method after return. It doesn't return a simple boolean result. If you look at the source code for that method, you'll see that it returns an object with a compare method. Judging from the source code for other methods in the matchers subdirectory, apparently that's a standard pattern used internally by the Jasmine library.
So, bottom line, you might be better off sticking with the return targetRegex.test(url); approach instead, since that returns a boolean.

Resources