Error Retrieving substring from larger text source in Protractor - jasmine

I am trying to extract a URL from a registration email in my end-to-end test for Protractor, but I am getting errors trying to parse the larger string.
The error I am getting is:
*
Failures: 1) MockMock Get verification link Message:
Failed: regText.indexOf is not a function Stack:
TypeError: regText.indexOf is not a function
at getRegLink (D:\QA\Scripting\ProtractorHelloWorld\CCspecMockMock.js:19:27)
at UserContext. (D:\QA\Scripting\ProtractorHelloWorld\CCspecMockMock.js:37:14)
at C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:112:25
at new ManagedPromise (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:1077:7)
at ControlFlow.promise (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2505:12)
at schedulerExecute (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:95:18)
at TaskQueue.execute_ (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:3084:14)
at TaskQueue.executeNext_ (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:3067:27)
at asyncRun (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2974:25)
at C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:668:7
From: Task: Run it("Get verification link") in control flow
at UserContext. (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:94:19)
at C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:64:48
at ControlFlow.emit (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\events.js:62:21)
at ControlFlow.shutdown_ (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2674:10)
at shutdownTask_.MicroTask (C:\Users\dcoughler\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2599:53)
From asynchronous test:
Error
at Suite. (D:\QA\Scripting\ProtractorHelloWorld\CCspecMockMock.js:35:1)
at Object. (D:\QA\Scripting\ProtractorHelloWorld\CCspecMockMock.js:2:1)
at Module._compile (internal/modules/cjs/loader.js:688:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
at Module.load (internal/modules/cjs/loader.js:598:32)
at tryModuleLoad (internal/modules/cjs/loader.js:537:12) 1 spec, 1 failure Finished in 0.622 seconds
*
Here is the code:
// spec.js
describe('MockMock', function() {
var tRegMessage = element(by.className('well'));
var tabledata = $$('./table');
// get rows
var rows = tabledata.all(by.tagName("tr"));
// get cell values
var cells = rows.all(by.tagName("td"));
var commonfunctions = require('./CCCommonFunctions.js');
function clickRegistration(email) {
element(by.xpath("//td[. = '" + email + "']/following-sibling::td/a")).click();
}
function getRegLink(regText) {
var startUrl = regText.indexOf("http://");
var endUrl = regText.indexOf("Thank you",startUrl);
getRegLink = regText.substring(startUrl,endUrl);
}
function Login(username, password) {
fUserName.sendKeys(username);
fPassword.sendKeys(password);
commonfunctions.ccClick(bLoginButton);
}
beforeEach(function() {
browser.waitForAngularEnabled(false);
browser.get('http://ns-rd-app-wi:2525/');
});
it('Get verification link', function() {
clickRegistration('PhillipPies#mock.com');
browser.get(getRegLink(tRegMessage));
browser.pause();
});
});
How should I be parsing strings in protractor? I'm too used to vbscript, it seems.
==================================================================
I've made changes based on the comments below, but I am still stuck:
describe('MockMock', function() {
var tRegMessage = element(by.className('well'));
var tabledata = $$('./table');
// get rows
var rows = tabledata.all(by.tagName("tr"));
// get cell values
var cells = rows.all(by.tagName("td"));
var commonfunctions = require('./CCCommonFunctions.js');
function clickRegistration(email) {
element(by.xpath("//td[. = '" + email + "']/following-sibling::td/a")).click();
}
function getRegLink(regMessage) {
return new Promise(resolve => {
regMessage.getText().then(text => {
var startUrl = text.indexOf("http://");
var endUrl = text.indexOf("Thank you",startUrl);
resolve(text.substring(startUrl,endUrl-2))
} )
})
}
beforeEach(function() {
browser.waitForAngularEnabled(false);
browser.get('http://ns-rd-app-wi:2525/');
});
it('Get verification link', function() {
clickRegistration('PhillipPies#mock.com');
var regURL=getRegLink(tRegMessage.getText());
browser.get(regURL.toString());
browser.pause();
});
});
This gives a new error now:
Failed: unknown error: unhandled inspector error: {"code":-32000,"message":"Cannot navigate to invalid URL"}
(Session info: chrome=71.0.3578.98)
(Driver info: chromedriver=2.46.628402 (536cd7adbad73a3783fdc2cab92ab2ba7ec361e1),platform=Windows NT 10.0.16299 x86_64)

You got error on line:
browser.get(getRegLink(tRegMessage));
Because tRegMessage is not string. It is ElementFinder (you got it from this line element(by.className('well'));)
So, you need take a text from this element. For example:
it('Get verification link', function() {
const url = tRegMessage.getText();
clickRegistration('PhillipPies#mock.com');
browser.get(getRegLink(url));
browser.pause();
});
Also, your method getRegLink() does not return string. So, after first fix you will get an error that browser.get() should have argument string

The problem is tRegMessage is not a string. It's an ElementFinder. You need to call getText() first.
function getRegLink(regMessage) {
return new Promise(resolve => {
regMessage.getText().then(text => {
var startUrl = text.indexOf("http://");
var endUrl = text.indexOf("Thank you",startUrl);
resolve(text.substring(startUrl,endUrl));
}
}
}

Quite an old thread but might as well give it an answer.
The original response was updated, the error is now that .getText() is called twice.
Here
var regURL=getRegLink(tRegMessage.getText());
and then here:
regMessage.getText().then(text => {
To fix your error you need to remove one of these getText() (ideally remove the first one I quoteed so all Promise stuff happens in the functions).
Then you could change your function to return the Promise instead of creating a new one:
function getRegLink(regMessage) {
return regMessage.getText().then(text => {
var startUrl = text.indexOf("http://");
var endUrl = text.indexOf("Thank you",startUrl);
return text.substring(startUrl,endUrl-2);
});
}

Related

Jasmine: Expected spy <function> to have been called error

In my angular application, I am trying to write a test case for following scenario but getting error 'Expected spy reinvite to have been called.'. Im testing on "jasmine-core: ^2.5.2 and "karma: ^1.3.0". I have written similar test cases and they passed without error.
In my controller file:
function reinvite() {
var emailsToReInvite = $j.map($scope.settingsData.userSettingsDetails, function(user) {
if(user.reInviteChecked){
return user.email;
}
});
if (emailsToReInvite.length >= 1) {
var invitation = { invitees: emailsToReInvite, listId: listId};
invitation = JSON.stringify(invitation);
inviteCollaboratorsModalDataService.reinvite(invitation).then(
function success(response) {
if(response.data.messages[0].code == 214){
$scope.showReinviteSuccess = true;
}
}else{
$scope.showReinviteSuccess = false;
}
}
);
}
}
And my spec file:
describe('settingsModalController', function() {
var controllerUnderTest = "settingsModalController";
var controllerResolver, rootScope, injector, $scope, inviteCollaboratorsModalDataService
beforeEach(function(){
angular.mock.module('sharedListApp');
inject(function($controller, $rootScope, $injector){
controllerResolver = $controller;
rootScope = $rootScope;
injector = $injector;
});
$scope = rootScope.$new();
inviteCollaboratorsModalDataService = injector.get('uiCommon.inviteCollaboratorsModalDataService');
});
it("should send re-invitation mail to selected users successfully", shouldReinviteSelectedUsers);
function shouldReinviteSelectedUsers() {
var $q = injector.get('$q');
$scope.settingsData = {
userSettingsDetails: [{email: 'abc#xyz.com'}]
};
var data = {
messages: [ { code: 214 }],
invite: {
invitation: $scope.settingsData
}
};
var response = { data: data };
var mockResult = new $q.defer();
mockResult.resolve(response);
spyOn(inviteCollaboratorsModalDataService, 'reinvite').and.returnValue(mockResult.promise);
controllerResolver(controllerUnderTest, { $scope: $scope });
$scope.reinvite();
$scope.showReinviteSuccess = true;
$scope.$apply();
expect(inviteCollaboratorsModalDataService.reinvite).toHaveBeenCalled();
expect($scope.showReinviteSuccess).toBe(true);
}
}
What am i doing wrong or what am i missing? Thanks in advance.
Ok, so i missed one variable to add in $scope.settingsData in my spec file which was why my spec code was not parsing into the first 'if' loop of the controller. Got it working by adding 'reInviteChecked: true' in:
$scope.settingsData = {
userSettingsDetails: [{email: 'abc#xyz.com', reInviteChecked: true}]
};

dateObj.getMonth() not working in nativescript

I am trying to get the month from the date object . But I am getiing error whci displays says "getMonth is not a function".
Since I saw some Java script tutorials , where getMonth() is supported in ES6.
Am I missing importing anything.
var config = require("../../shared/config");
var fetchModule = require("fetch");
var ObservableArray = require("data/observable-array").ObservableArray;
var datePickerModule = require("tns-core-modules/ui/date-picker");
function TaskListViewModel(items){
var listModel = new ObservableArray(items);
listModel.getTaskList = function()
{
return fetchModule.fetch(config.TaskListURL,{
method:"Get"
})
.then(handleErrors)
.then(function(response){
return response.json();
}).then(function(data) {
data.forEach(function(element) {
var dateObj = Date.parse(element.followUpDate)
listModel.push({
fallowUpDateMonth:dateObj.getMonth(),
faloowUpDateDay:dateObj.getDate(),
fallowupDateYear:dateObj.getFullYear(),
});
});
});
};
return listModel;
}
module.exports = TaskListViewModel;

ioredis bluebird a promise was created in a handler but was not returned from it

Can someone please explain to me why i'm getting this warning Warning: a promise was created in a handler but was not returned from it when I execute the following code:
cache['deviceSlave'].getBySystemId(systemId).then(function(slavesMapping) {
// do other stuff
}).catch(function(err) {
// throw error
});
Here is the rest of the code:
var Promise = require('bluebird');
var _ = require('lodash');
var Redis = require('ioredis');
var config = require('/libs/config');
var redis = new Redis({
port: config.get('redis:port'),
host: config.get('redis:host'),
password: config.get('redis:key'),
db: 0
});
var self = this;
module.exports.getBySystemId = function(systemId) {
return new Promise(function(resolve, reject) {
var systemIds = [systemId];
self.getBySystemIds(systemIds).then(function(result) {
return resolve(_.values(result)[0]);
}).catch(function(err) {
return reject(err);
});
});
};
module.exports.getBySystemIds = function(systemIds) {
return new Promise(function(resolve, reject) {
var pipeline = redis.pipeline();
_.each(systemIds, function(systemId) {
var cacheKey = 'device_slaves:' + systemId.replace(/:/g, '');
// get through pipeline for fast retrieval
pipeline.get(cacheKey);
});
pipeline.exec(function(err, results) {
if (err) return reject(err);
else {
var mapping = {};
_.each(systemIds, function(systemId, index) {
var key = systemId;
var slaves = JSON.parse(results[index][1]);
mapping[key] = slaves;
});
return resolve(mapping);
}
});
});
};
I'm using the following libraries: ioredis & bluebird.
The code executes fine and everything just works good! I just dont like the fact I get an warning which I can not solve!
Bluebird is warning you against explicit construction here. Here is how you should write the above code:
module.exports.getBySystemId = function(systemId) {
return self.getBySystemIds([systemId]).then(result => _.values(result)[0]);
};
There is no need to wrap the promise - as promises chain :)

Nativescript - Pass array from home-view-model to home.js

I´m having a hard time understanding how to perform this action(as the title says), and maybe someone could help me understand the process, my code is below:
My home-view-model:
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var http = require("http");
function createViewModel() {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
return arrNoticias;
}, function (e) {
});
}
exports.createViewModel = createViewModel;
I have done a console.log of the arrNoticias before i have putted it inside a callback function and it returns [object object] etc...and then i have done this:
console.log(arrNoticias.getItem(0).titulo);
and it returns the info i need!.
Then in my home.js file i have this:
var observableModule = require("data/observable")
var ObservableArray = require("data/observable-array").ObservableArray;
var arrNoticias = require('./home-view-model.js');
console.log(arrNoticias.getItem(0).titulo);
and the result in the console is:
TypeError: arrNoticias.getItem is not a function. (In 'arrNoticias.getItem(0)', 'arrNoticias.getItem' is undefined)
My question is, how does this action is perform? passing the data from view-model to the .js file?
Thanks for your time
Regards
As that function send a URL request so probably it's an async function, which is on hold while requesting so that's why you get undefined. Normally, you will want your function that sends a URL request to return a promise. Based on that promise, you will the result as expected after the request is done. So:
function createViewModel() {
return new Promise<>((resolve, reject) => {
http.getJSON("http://myJsonfile").then(function (r) {
var arrNoticias = new ObservableArray(r.data);
resolve(arrNoticias);
}, function(e) {
reject(e);
});
}), (e) => {
console.log(e);
})
}
In home.js:
var homeVM= require('./home-view-model.js');
var arrNoticias;
homeVM.createViewModel().then(function(r) {
arrNoticias = r;
});

Parse Cloud Code Save Issue

I wrote some backend code for a Parse.com mobile app a couple of years ago, and have just been asked to add a feature. However, I found that after a small tweak the code wouldn't succeed. So, I rolled back to the working copy, downloaded, then deployed that back and it wouldn't work either! I wonder if this is a change in the Parse software?
The code is failing at the save method as all the logs are fine until then. The log for the error case shows 'No message provided'. If I don't use the message attribute it just shows '{}', so I presume it's empty. I have put the promise resolution in the error case to stop the job timing out while I debug. One thing I have never understood is why I have to make two Seed objects and piggy-back off one to save correctly. If I did a.save(null,...) it wouldn't work.
Any help would be fantastic. Thanks!
PS: Apologies for the indenting below - it is correct in my file.
function flush() {
//Clear the previous records from the class.
var Seed = Parse.Object.extend("Seeds");
var _ = require("underscore");
var arr = [];
var query = new Parse.Query(Seed);
return query.find().then(function(oldSeeds) {
_.each(oldSeeds, function(oldSeed) {
arr.push(oldSeed.destroy());
});
return Parse.Promise.when(arr);
});
}
Parse.Cloud.job("fetchjson", function(request, status) {
var url = 'someurl';
flush().then(function() { Parse.Cloud.httpRequest({url: url}).then(function(httpResponse){
var Seed = Parse.Object.extend("Seeds");
var jsonobj = JSON.parse(httpResponse.text);
var _ = require("underscore");
var results = [];
// do NOT iterate arrays with `for... in loops`
_.each(jsonobj.seeds, function(s) {
var p = new Parse.Promise();
results.push(p); // Needs to be done here or when() will execute immediately with no promises.
var seed = new Seed();
var a = new Seed(s);
var image_url = a.get("image")
//Get the JSON.
Parse.Cloud.httpRequest({url: image_url}).then(function(response) {
console.log("Fetching image at URL: " + image_url);
//Create a new image object and save, passing ref through promise.
var file = new Parse.File('thumb.jpg', { base64: response.buffer.toString('base64', 0, response.buffer.length) });
return file.save();
}).then(function(thumb) {
console.log("Attaching thumb to object");
//Set image ref as object attribute.
a.set("imageFile", thumb);
console.log("Parsing views into viewsint");
//Save decimal string as int into another attribute.
a.set("viewsInt", parseInt(a.get("views")));
console.log("Parsing description into descriptionarray");
//Save string as array into another attribute.
var dar = new Array(1);
//dar[0] = a.get("description")
a.set("descriptionarray", [a.get("description")]);
}, function(error) {
console.log("Error occurred :(");
}).then(function(){
console.log("Saving object");
//Save the object and resolve the promise so we can stop.
seed.save(a,{
success: function(successData){
console.log(successData);
p.resolve(successData);
},
error: function(error){
console.log(error.message);
p.resolve(error);
}
});
});
});
// .when waits for all promises to be resolved. This is async baby!
Parse.Promise.when(results).then(function(data){
console.log("All objects saved");
status.success("Updated Succesfully");
});
}, function(error) {
//Oh noes :'(
console.error('Request failed with response code ' + httpResponse.status);
status.error("Update Failed");
});
});
});
I changed your code a bit and put some comments to explain:
// DEFINE THESE ON THE TOP. NO NEED TO REPEAT.
var _ = require("underscore");
var Seed = Parse.Object.extend("Seeds");
function flush() {
//Clear the previous records from the class.
var arr = [];
var query = new Parse.Query(Seed);
return query.find().then(function(oldSeeds) {
_.each(oldSeeds, function(oldSeed) {
arr.push(oldSeed.destroy());
});
return Parse.Promise.when(arr);
});
}
Parse.Cloud.job("fetchjson", function(request, status) {
var url = 'someurl';
flush().then(function() {
Parse.Cloud.httpRequest({url: url}).then(function(httpResponse){
var jsonobj = JSON.parse(httpResponse.text);
var results = [];
_.each(jsonobj.seeds, function(s) {
// ONE SEED OBJECT WITH INITIAL SET OF DATA FROM JSON
var seed = new Seed(s);
var image_url = seed.get("image")
// A SERIAL PROMISE FOR EACH SEED
var promise = Parse.Cloud.httpRequest({url: image_url}).then(function(response) {
console.log("Fetching image at URL: " + image_url);
//Create a new image object and save, passing ref through promise.
var file = new Parse.File('thumb.jpg', { base64: response.buffer.toString('base64', 0, response.buffer.length) });
return file.save();
}).then(function(thumb) {
// SETTING MORE PROPERTIES
//Set image ref as object attribute.
console.log("Attaching thumb to object");
seed.set("imageFile", thumb);
//Save decimal string as int into another attribute.
console.log("Parsing views into viewsint");
seed.set("viewsInt", parseInt(seed.get("views")));
//Save string as array into another attribute.
console.log("Parsing description into descriptionarray");
seed.set("descriptionarray", [seed.get("description")]);
// SAVING THE OBJECT
console.log("Saving object");
return seed.save();
});
// PUSH THIS PROMISE TO THE ARRAY TO PERFORM IN PARALLEL
results.push(promise);
});
Parse.Promise.when(results).then(function(data){
console.log("All objects saved");
status.success("Updated Succesfully");
});
}, function(error) {
console.error('Request failed with response code ' + httpResponse.status);
status.error("Update Failed");
});
});
});
Thanks knshn. I had refactored the code a lot since that version (including several of the changes you made), but I had posted the version that was identical to that which was working fine before. Your changes let me see the right error. For some reason doing the simple single object implementation didn't work for me originally, hence the nasty workaround. It works now though.
I have now found the culprit - the Seed class had an attribute called 'id'. With the old version this worked fine, but when I deployed that code now it gave an error 101: 'object not found for update'. This must be because the new Parse code is mixing that up with the internal objectId and getting confused that the id is different to what it expects. I wonder how that could still work with the rollback though. Perhaps the at version was tagged to use the older Parse code.
My fix was to use a different name for the id - 'seed_id'.

Resources