I'm using jasmine+karma to run the following code...
and get the following error:
Expected { then : Function, catch : Function, finally : Function } to equal 123.
Can someone help me understand why I don't get a resolved value for my promise. thanks
'use strict';
angular
.module('example', ['ui.router'])
.config(function($stateProvider) {
$stateProvider
.state('stateOne', {
url: '/stateOne',
resolve: {cb: function($q) {
var deferred = $q.defer();
deferred.resolve(123);
return deferred.promise;
}},
controller: function($scope, cb) {console.log(' * in controller', cb);},
templateUrl: 'stateOne.html'
});
})
.run(function($templateCache) {
$templateCache.put('stateOne.html', 'This is the content of the template');
});
describe('main tests', function() {
beforeEach(function() {module('example');});
describe('basic test', function($rootScope) {
it('stateOne', inject(function($rootScope, $state, $injector, $compile) {
var config = $state.get('stateOne');
expect(config.url).toEqual('/stateOne');
$compile('<div ui-view/>')($rootScope);
$rootScope.$digest();
expect($injector.invoke(config.resolve.cb)).toEqual(123);
}));
});
});
Ok, Figured it out with some help (via email) from Nikas, whose blog I found at:
http://nikas.praninskas.com/angular/2014/09/27/unit-testing-ui-router-configuration/.
Here is a succinct example that demonstrates how to test the resolve values in ui.router, where the values involve $http.
angular
.module('example', ['ui.router'])
.factory('Clipboard', function($http) {
return {
get: function(args) {
return $http.get('/db/clipboard');
}
};
})
.config(function($stateProvider) {
$stateProvider
.state('stateOne', {
resolve: {cb: function(Clipboard) {
return Clipboard.get();
}}
});
});
describe('main tests', function() {
beforeEach(function() {module('example');});
it('stateOne', inject(function($state, $injector, $httpBackend) {
$httpBackend.whenGET('/db/clipboard').respond({a:1});
$injector.invoke($state.get('stateOne').resolve['cb'])
.then(function(res) {console.log(' *res ', res.data);})
.catch(function(err) {console.log(' *err ', err);});
$httpBackend.flush();
}));
afterEach(inject(function($httpBackend) {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
}));
});
Related
I am looking to assign as an object a Fetch API promise from a local GeoJSON file.
Here is the code
fetch("data/sites.geojson")
.then(function(response) {
return response.json();
})
.then(function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites
}).addTo(map);
});
};
I tried the call back method, as advised here
Saving fetched JSON into variable
(EDIT) New code, but there is still a missing formal parameter
function getData("data/sites.geojson", cb) {
fetch("data/sites.geojson")
.then(function(response) {
return response.json();
})
.then(function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites,
onEachFeature: function (feature, layer) {
layer.on('mouseover', function() {
layer.openPopup(layer.bindPopup("<b>"+feature.properties.nombre+"</b>"))
});
layer.on('mouseout', function() {
layer.closePopup();
});
layer.on('click', function () {
layer.bindPopup("<b>Nombre: </b>"+feature.properties.nombre+"<br><b>Barrio: </b>"+feature.properties.barrio+"<br><b>Tipo: </b>"+feature.properties.tipo+"<br><b>Ubicacion: </b>"+feature.properties.ubicacion+"<br><b>Correo: </b>"+feature.properties.contacto);
});
}
}).addTo(map);
.then(function(result) {
cb(result);
});
});
};
getData("data/sites.geojson", function (data) {
return console.log({data});
});
Most probably just incorrect syntax of your callback function:
// Use either arrow function
getData("data/sites.geojson", (data) => {
return console.log({data});
});
// or standard function
getData("data/sites.geojson", function (data) {
return console.log({data});
});
I found the way to work this out by adding within the fetch function, what I originally wanted to do on the map.
This was to add a L.controlLayer using the geojson as overlay.
This is the code that made it work:
let sites = getData()
.then((function(data) {
L.geoJSON(data, {
pointToLayer: styles_sites,
onEachFeature: function LayerControl(feature, layer) {
var popupText = "<b>" + feature.properties.nombre + "<br>";
layer.bindPopup(popupText);
category = feature.properties.tipo;
// Initialize the category array if not already set.
if (typeof categories[category] === "undefined") {
categories[category] = L.layerGroup().addTo(map);
layersControl.addOverlay(categories[category], category);
}
categories[category].addLayer(layer);
layer.on('mouseover', function() {
layer.openPopup(layer.bindPopup("<b>"+feature.properties.nombre+"</b>"))
});
layer.on('mouseout', function() {
layer.closePopup();
});
layer.on('click', function () {
layer.bindPopup("<b>Nombre: </b>"+feature.properties.nombre+"<br><b>Barrio: </b>"+feature.properties.barrio+"<br><b>Tipo: </b>"+feature.properties.tipo+"<br><b>Ubicacion: </b>"+feature.properties.ubicacion+"<br><b>Correo: </b>"+feature.properties.contacto);
});
}
}).addTo(map);
}));
Actually it comes from one of your answer on another post ghybs.
I am trying to create a framework for API tests using cypress and I am facing an issue accessing the data between tests using an alias. Is there something that I am missing?
custom.js
Cypress.Commands.add('getResource', function (uri) {
cy.request({
url: uri,
method: 'GET'
}).then(function (response) {
return cy.wrap(response);
});
});
test.js
exports.__esModule = true;
context('requests', function () {
it('validate get call response', function () {
let re = cy.getResource('https://reqres.in/api/users?page=2','resp')
re.then(function (response) {
cy.wrap(response.body).as('respbody');
cy.wrap(response.status).as('respstatus');
//cy.log(JSON.stringify(response.body));
});
});
it('Tests test', function () {
cy.wait('#respbody').then((body) => {
console.log(JSON.stringify(body));
});
});
});
cypress version - 8.2.0
By design cypress cleans up aliases after each test. So you can do something like this cypress recipe
Your getResource custom command is taking just one parameter, hence we are passing just one papameter.
exports.__esModule = true;
let responseBody;
let responseStatus;
context('requests', () => {
before(() => {
cy.getResource('https://reqres.in/api/users?page=2')
.then(function(response) {
responseBody = response.body
responseStatus = response.status
})
})
beforeEach(() => {
cy.wrap(responseBody).as('responseBody')
cy.wrap(responseStatus).as('responseStatus')
})
it('Get Response status', function() {
cy.wait('#responseStatus').then((responseStatus) => {
console.log(responseStatus)
})
})
it('Get Response Body', function() {
cy.wait('#responseBody').then((responseBody) => {
console.log(JSON.stringify(responseBody))
})
})
})
I need to iterate over result set from the sequelize result. I have a code that works, but I think something is wrong with it, and it should not be done this way.
I have a feeling this is a blocking code.
This is the code that works:
models.Project.findAll({
where: {ProjectId: projectId}
})
.then(function (projects) {
//Iteration is here
var projectList = [];
projects.forEach(function (res) {
projectList.push(res.dataValues.PartId);
});
//then bulk lookup for the result
models.Customers.findAll({
where: {'id': {in: [projectList]}}
}).then(function (customers) {
reply(customers).code(200);
}, function (rejectedPromiseError) {
reply(rejectedPromiseError).code(401);
});
//reply(sameparts).code(200);
}, function (rejectedPromiseError) {
reply(rejectedPromiseError).code(401);
});
This iteration parts is done:
projects.forEach(function (res) {
projectList.push(res.dataValues.PartId);
});
And then this code is executed as another query:
models.Customers.findAll({
where: {'id': {in: [projectList]}}
}).then(function (customers) {
reply(customers).code(200);
}, function (rejectedPromiseError) {
reply(rejectedPromiseError).code(401);
});
How can I rearange it so it uses Promises?
EDIT (Possible solution):
After playing a bit, I believe I have implemented promises.
getAll: function (request, reply) {
var projectId = request.params.projectid;
var promises = [];
var post;
models.SamePart.findAll({
where: {ProjectId: projectId}
})
.then(function (sameparts) {
//Iteration is here
sameparts.forEach(function (res) {
promises.push(
Promise.all([
models.Parts.findAll({where: {id: res.dataValues.PartId}})
]))
});
//Bulk lookup for the parts that were marked as identical
return Promise.all(promises);
}).then(function (completepartslist) {
reply(completepartslist).code(200);
});
Is this a correct approach? It seems that completepartslist contains many unwanted objects, including Promise stuff. How can I flatten it, so to avoid complex for loops?
If you are using .then(), then you are, in all probability, already using promises.
Your original, working code doesn't appear to be blocking.
Your final getAll() looks like it should simplify to :
getAll: function (request, reply) {
models.SamePart.findAll({
where: { ProjectId: request.params.projectid }
}).then(function (sameparts) {
return Promise.all(sameparts.map(function (res) {
return models.Parts.findAll({ where: { id: res.dataValues.PartId } });
}));
}).then(function (completepartslist) {
reply(completepartslist).code(200);
});
}
However, you need to add error handling back in.
even more simplified
getAll: function (request, reply) {
models.SamePart.findAll({
where: { ProjectId: request.params.projectid }
}).reduce(function (completepartslist, sameparts) {
return models.Parts.findAll({ where: { id: sameparts.PartId } }).
then(function(res){
completepartslist.concat(res)
});
}), []);
}).then(function (completepartslist) {
reply(completepartslist).code(200);
});
}
I keep getting this error in my client/app.js file as I use grunt to compile it into production. I never had this error before while in development. I've not found any clear guidance on how to fix this on the client side. I initialize Parse at the bottom of the page.
My app.js:
'use strict';
angular.module('cpApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router',
'ui.bootstrap',
'parse-angular',
'angularPayments',
'elif'
])
.config(function ($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider) {
$urlRouterProvider
.otherwise('/');
$locationProvider.html5Mode(true);
$httpProvider.interceptors.push('authInterceptor');
})
.factory('authInterceptor', function ($rootScope, $q, $cookieStore, $location) {
return {
// Add authorization token to headers
request: function (config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
},
// Intercept 401s and redirect you to Landing Page
responseError: function(response) {
if(response.status === 401) {
$location.path('/');
// remove any stale tokens
$cookieStore.remove('token');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
};
})
.run(function ($rootScope, $location, Auth) {
Parse.initialize('key1', 'key2');
// Redirect to card if route requires auth and you're not logged in
$rootScope.$on('$stateChangeStart', function (event, next) {
Auth.isLoggedInAsync(function(loggedIn) {
if (next.authenticate && !loggedIn) {
$location.path('/');
}
});
});
});
The issue was in my config function. I needed to move Parse there from run:
.config(function ($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider, Parse) {
Parse.initialize('Id1', 'Id2');
$urlRouterProvider
.otherwise('/');
$locationProvider.html5Mode(true);
$httpProvider.interceptors.push('authInterceptor');
})
I want to test the "addGroup" function using Jasmine. I get the following error:
Error: Expected spy modifyMyHtml to have been called.at null.
I don't know what is the best way to test the addGroup function. Please HELP.....
var myRecord = {
addGroup: function(groupNumber) {
$.when(myRecord.getHtml())
.done(function(returnedHtml){
myRecord.modifyMyHtml(returnedHtml);
});
},
getHtml: function() {
return $.ajax({url: "myHtmlFile.html", dataType: "html" });
},
// adds options and events to my returned HTML
modifyMyHtml: function(returnedHtml) {
$('#outerDiv').html(returnedHtml);
var myOptions = myRecord.getOptions();
$('#optionsField').append(myOptions);
myRecord.bindEventsToDiv();
},
}
====JASMINE TEST
describe("Configure Record page", function() {
var fixture;
jasmine.getFixtures().fixturesPath = "/test/" ;
jasmine.getFixtures().load("myHtmlFile.html");
fixture = $("#jasmine-fixtures").html();
describe("addGroup", function(){
beforeEach(function() {
var groupNumber = 0;
spyOn(myRecord, "getHtml").andCallFake(function(){
return $.Deferred().promise();
});
spyOn(myRecord, "modifyMyHtml");
myRecord.addGroup(groupNumber);
});
it("Should call getHtml", function() {
expect(myRecord.getHtml).toHaveBeenCalled();
});
it("Should call modifyMyHtml", function() {
expect(myRecord.modifyMyHtml).toHaveBeenCalled(); ==>FAILS
});
});
});
You have to resolve the promise before you return em in your andCallFake.
spyOn(myRecord, "getHtml").andCallFake(function(){
return $.Deferred().resolve ().promise();
});
Btw. you should not test that the function on the object you wanna test are called, but that the html in the DOM are set with the right html
it("Should call modifyMyHtml", function() {
spyOn(myRecord, "getHtml").andCallFake(function(){
return $.Deferred().resolveWith(null, 'returnedHtml').promise();
});
expect($('#outerDiv').html).toEqual('returnedHtml')
});