Unit testing AngularJS service method thet resolves multiple promises with $q.all - angularjs

I am trying to test the following service method that calls another method to retrieve data multiple times with different parameters.
I have only ever tested resolving one promise at a time so am not sure how to approach this method as a karma/jasmine unit test:
getMappings(dealerId){
let dfd = this.$q.defer();
let promises = [];
promises.push(this.DataService.getTranslationMappings(this.TRANSLATIONS.DEALER, dealerId));
promises.push(this.DataService.getTranslationMappings(this.TRANSLATIONS.DAYCOUNT, dealerId));
promises.push(this.DataService.getTranslationMappings(this.TRANSLATIONS.FREQUENCY, dealerId));
promises.push(this.DataService.getTranslationMappings(this.TRANSLATIONS.RATE_STATIC, dealerId));
promises.push(this.DataService.getTranslationMappings(this.TRANSLATIONS.SETTLEMENT_TYPE, dealerId));
this.$q.all(promises)
.then((resp) => {
dfd.resolve({
dealers: resp[0].data,
daycounts: resp[1].data,
frequencies: resp[2].data,
rateStatics: resp[3].data,
settlementTypes: resp[4].data
});
}, (resp) => {
dfd.reject(resp);
});
return dfd.promise;
}
Any help would be appreciated. Thanks :)

it('should get the mappings for listing', () => {
let dealerId = 1;
let resp;
let count = 0;
let dealers = [
{
"id": 1,
"dealerId": 1,
"translation": {
"id": 2,
"description": "Wayne Enterprise"
},
"synonym": "CTRPTYCODE 1"
}
];
let daycount = [
{
"id": 1,
"dealerId": 1,
"translation": {
"id": 1,
"description": "DAYCT 1"
},
"synonym": "DAYCTCODE 1"
}
];
let frequency = [
{
"id": 1,
"dealerId": 1,
"translation": {
"id": 1,
"description": "FREQ A"
},
"synonym": "FREQCODE 1"
}
];
let ratestat = [
{
"id": 1,
"dealerId": 1,
"translation": {
"id": 1,
"description": "RATESTAT 1"
},
"synonym": "RATESTATCODE 1"
}
];
let settlement = [
{
"id": 1,
"dealerId": 1,
"translation": {
"id": 1,
"description": "SETTYPE A"
},
"synonym": "SETTYPECODE 1",
"$$hashKey": "object:221"
}
];
spyOn(service, 'getMappings').and.callThrough();
spyOn(DataService, 'getTranslationMappings').and.callFake(function(){
var defer = this.$q.defer();
let data;
switch(count) {
case 0:
data = dealers;
break;
case 1:
data = daycount;
break;
case 2:
data = frequency;
break;
case 3:
data = ratestat;
break;
case 4:
data = settlement;
break;
}
defer.resolve({
success: true,
error: null,
data: data
});
count++;
return defer.promise;
});
service.getMappings(dealerId).then((data) => {
resp = data;
});
scope.$digest();
expect(service.getMappings).toHaveBeenCalled();
expect(service.getMappings).toHaveBeenCalledWith(dealerId);
expect(DataService.getTranslationMappings).toHaveBeenCalled();
expect(DataService.getTranslationMappings.calls.count()).toEqual(5);
expect(DataService.getTranslationMappings.calls.argsFor(0)).toEqual(['DEALER', dealerId]);
expect(DataService.getTranslationMappings.calls.argsFor(1)).toEqual(['DAYCOUNT', dealerId]);
expect(DataService.getTranslationMappings.calls.argsFor(2)).toEqual(['FREQUENCY', dealerId]);
expect(DataService.getTranslationMappings.calls.argsFor(3)).toEqual(['RATE_STATIC', dealerId]);
expect(DataService.getTranslationMappings.calls.argsFor(4)).toEqual(['SETTLEMENT_TYPE', dealerId]);
expect(resp.dealers).toEqual(dealers);
expect(resp.daycounts).toEqual(daycount);
expect(resp.frequencies).toEqual(frequency);
expect(resp.rateStatics).toEqual(ratestat);
expect(resp.settlementTypes).toEqual(settlement);
});
Solved! :)

Related

How do I sort this array by date?

I'm trying to sort the dates from this external API in my latestResults array by latest on top to oldest on bottom but can't seem to figure out how.
Right now they're displayed with the oldest date first and it's working fine, but it's in the wrong order for me.
I tried using result in latestResults.reverse() but that just reverses the 7 items currently in the array.
HTML:
<div v-for="result in latestResults" v-bind:key="result.latestResults">
<small">{{ result.utcDate }}</small>
</div>
Script:
<script>
import api from '../api'
export default {
data () {
return {
latestResults: [],
limit: 7,
busy: false,
loader: false,
}
},
methods: {
loadMore() {
this.loader = true;
this.busy = true;
api.get('competitions/PL/matches?status=FINISHED')
.then(response => { const append = response.data.matches.slice(
this.latestResults.length,
this.latestResults.length + this.limit,
this.latestResults.sort((b, a) => {
return new Date(b.utcDate) - new Date(a.utcDate);
})
);
setTimeout(() => {
this.latestResults = this.latestResults.concat(append);
this.busy = false;
this.loader = false;
}, 500);
});
}
},
created() {
this.loadMore();
}
}
</script>
The JSON where I'm getting matches like this that has utcDate:
{
"count": 205,
"filters": {
"status": [
"FINISHED"
]
},
"competition": {
"id": 2021,
"area": {
"id": 2072,
"name": "England"
},
"name": "Premier League",
"code": "PL",
"plan": "TIER_ONE",
"lastUpdated": "2021-02-01T16:20:10Z"
},
"matches": [
{
"id": 303759,
"season": {
"id": 619,
"startDate": "2020-09-12",
"endDate": "2021-05-23",
"currentMatchday": 22
},
"utcDate": "2020-09-12T11:30:00Z",
"status": "FINISHED",
"matchday": 1,
"stage": "REGULAR_SEASON",
"group": "Regular Season",
"lastUpdated": "2020-09-13T00:08:13Z",
"odds": {
"msg": "Activate Odds-Package in User-Panel to retrieve odds."
},
},

Mongoose-MongoDb : doc.pull inconsistent when multiple pull

node v7.7.1
mongodb: 2.2.33,
mongoose: 4.13.7
Hello all,
i'm having this unexpected behaviour when trying to update a document with multiple pull request based on matching criterias. here is what i mean
my document schma looks like this
{
"_id": "5a1c0c37d1c8b6323860dfd0",
"ID": "1511781786844",
"main": {
"_id": "5a3c37bfc065e86a5c593967",
"plan": [
{
"field1": 1,
"field2": 1,
"_id": "5a3c30dfa479bb4b5887e56e",
"child": []
},
{
"field1": 1,
"field2": 2,
"_id": "5a3c30e1a479bb4b5887e5c",
"child": []
},
{
"field1": 1,
"field2": 3,
"_id": "5a3c37bfc065e86a5c593968",
"child": []
},
{
"field1": 1,
"field2": 4,
"_id": "5a3c37bfc065e86a5c593655",
"child": []
},
{
"field1": 1,
"field2": 5,
"_id": "5a3c30dfa479bb4b5887e56f",
"child": []
},
{
"field1": 1,
"field2": 6,
"_id": "5a3c30e1a479bb4b6887e545",
"child": []
},
{
"field1": 1,
"field2": 7,
"_id": "5a3c37bfc065e86a5c5939658",
"child": []
},
{
"field1": 2,
"field2": 2,
"_id": "5a3c37bfc065e86a5c593963",
"child": []
},
]
},
...
....
}
and this is my code to update the document:
Schema.findOne({ID: data.ID})
.then(function(doc) {
var array = doc.main.plan;
for (i = 0; i < array.length; i++) {
if ( array[i].field1=== 1 )) {
var id = array[i]._id;
console.log('pulling');
doc.pull( { _id: id });
}
}
doc.save().then(function(doc) {
console.log('saving');
// console.log(doc);
if (doc && doc.docID) {
return { success: true };
} else {
return { success: false, error: 'unknownError'}
}
})
}
now the issue is let's say my array has 7 objects that matches the test (array[i].theField === parseInt(updFields.theField)), when i run this and check the logs i see that it will basically pull half of the objects and do a save.
so i would get
pulling
pulling
pulling
pulling
save.
and then i have to run the code for the remaining 3 objects in the array and get
pulling
pulling
saving
so i have to run it a third time to completely clear the array.
need help get this working
thank you
So i created a little workaround by doing a recursive function to pull all with only one click using lodash functions. not pretty but it does the job.
const delObjArray = (doc, cond) => {
const checkField = cond.field;
const checkVal = cond.value;
_.forEach(doc, (value) => {
if (value && value[checkField] === checkVal) {
doc.pull({ _id: value._id });
}
});
const isFound = _.some(doc, { [checkField]: checkVal });
if (isFound) {
delObjArray(doc, cond);
} else {
return true;
}
return true;
};

Protractor test not executing

I have a protractor test. I want to provide some data for a test so i can generate tests automatically.
My function is as below. The problem is that i can console log something after the opening of describe. But this is'nt the case after the it function.
The code:
bigTestFunction = function(testElements) {
testElements = JSON.parse(testElements);
for (i = 0; i < testElements.length; i++) {
var title = testElements[i].title;
var shouldText = testElements[i].should
var url = testElements[i].url;
var actions = testElements[i].action;
describe(title, function() {
it(shouldText, function() {
goToUrl(url);
for (x = 0; x < actions.length; x++) {
var action = actions[x].action;
var value = actions[x].value;
var element = actions[x].element;
var notEmpty = actions[x].notEmpty;
var nested = actions[x].nested;
if (action === 'sendKeys') {
sendKey(element, value);
}
if (action === 'click') {
click(element, notEmpty);
if (nested) {
for (x = 0; x < nested.length; x++) {
if (nested[x]['action'] === 'sendKeys') {
sendKey(nested[x]['element'], nested[x]['value']);
}
if (nested[x]['action'] === 'click') {
click(nested[x]['element'], nested[x]['notEmpty']);
}
}
}
}
}
});
});
}
}
testElements = JSON.parse(testElements);
the json:
[
{
"id": 1,
"title": "Small test one",
"should": "should start training",
"url": "https://ledmagazine.nl/home",
"actions": [
{
"id": 1,
"test_id": 1,
"element": "/html/body/div[1]/div/div/header/div/div[2]/div[2]/div/div/div/div/nav/section/ul/li[3]/a",
"action": "click",
"status": "notEmpty",
"value": "/html/body/div[1]/div/div/div[2]/div/div/div[1]/div/section",
"nested": {
"id": 1,
"action_id": 1,
"action": "sendKeys",
"element": "//*[#id=\"mce-EMAIL\"]",
"value": "dennisageffen#hotmail.com",
"created_at": null,
"updated_at": null
}
}
]
}
]
I think i'm really close but the function stops after 'describe(title, function() {...'
Propably you are missing beforeEach(function() {...} to get data.

Angularjs Splice in Nested Array

Hi can somebody help Removing element from nested json array like this
JSON
[{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}]
here how do I remove choice 1 of id 1 .
HTML
<div ng-repeat="cb in capital_budgets">
<div ng-repeat="choice in choices[$index]">
<input ng-model="cb.choice[$index].req_goods">
<input ng-model="cb.choice[$index].qty">
<button ng-hide="$first" ng-click="removeChoice($parent.$index,$index)">-</button>
</div>
<button ng-click="addNewChoice($index)">+</button>
</div>
JS
$scope.capital_budgets = [{"id":1,"name":"Furniture & Fixture"},
{"id":2,"name":"Miscellaneous Property"}];
$scope.choices = [{}];
$scope.choices[0] = [{}];
$scope.choices[1] = [{}];
$scope.choices[2] = [{}];
$scope.choices[3] = [{}];
$scope.choices[4] = [{}];
$scope.addNewChoice = function(id) {
$scope.choices[id].push({});
};
$scope.removeChoice = function(parent_id, id) {
$scope.choices[parent_id].splice(id, 1);
};
The Above removeChoice() remove last element but I want to remove the element that user choose to remove. please help i have been trying from 2 days.
You can make 'choice' of the array type as follows and use the index of the particular choice in the ng-repeat directive to remove the choice from the choices array.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
vm.removeChoice = removeChoice;
vm.addChoice = addChoice;
function removeChoice(itemId, index) {
for (var i = 0; i < vm.items.length; i++) {
if (vm.items[i].id === itemId) {
vm.items[i].choices.splice(index, 1);
break;
}
}
}
function addChoice(index) {
var id = vm.items[index].choices.length + 1;
vm.items[index].choices.push({
id: id,
req_goods: "",
qty: 0
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div ng-repeat="item in ctrl.items">
<h3>{{item.name}}</h3>
<div ng-repeat="choice in item.choices">
<input type="text" ng-model="choice.req_goods" />
<input type="text" ng-model="choice.qty" />
<button type="button" ng-click="ctrl.removeChoice(item.id, $index)">Remove</button>
</div>
<button type="button" ng-click="ctrl.addChoice($index)">Add</button>
</div>
</div>
</div>
You can remove choice "1" of id 1 using the below code snippet.
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}];
function removeChoice(json, parentId, choice) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
delete json[i].choice[choice];
break;
}
}
}
removeChoice(json, 1, "1");
console.log(json);
If you want the the choice also to be of the same type as its parent element i.e. an array you could change your JSON as follows and do as shown in the below code snippet to remove a choice from the JSON
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(json, parentId, choiceId) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
for (var j = 0; j < json[i].choices.length; j++) {
if (json[i].choices[j].id === choiceId) {
json[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(json, 1, 1);
console.log(json);
In both of the above methods I've passed the source you want to modify as a parameter to the removeChoice function whereas you can also directly use a variable available within the scope of execution of the removeChoice function and pass only parentId and choiceId as parameters in the below code snippet, you can replace items with the object on your controller's $scope.If you prefer isolation of the code you can pass the items object as a parameter to the removeChoice function as it won't be dependent on the external components directly being used in the method body, I would suggest to have separation of concerns.
var items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(parentId, choiceId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parentId) {
for (var j = 0; j < items[i].choices.length; j++) {
if (items[i].choices[j].id === choiceId) {
items[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(1, 1);
console.log(items);
Try This
$scope.removeChoice = function(parent_id,id) {
var TempArr=[];
var parentLength=$scope.choices[parent_id].length;
for(i=0;i<parentLength;i++ ){
if(parentLength[i]!==id){
TempArr.push(parentLength[i]);
}
if(i==parentLength-1){
$scope.choices[parent_id]=[];
$scope.choices[parent_id]=TempArr;
}
}
};

Issue with the object references in Angularjs

I have a simple function below using which am trying create dynamic div containing a d3 chart for each row from the given input "json.res_full_sk"
However, when I use apply in Angularjs, am losing the historic data that is being assigned to dyndata object.
<script>
var app = angular.module('rpPlotExampleApp', ['ui.rpplot']);
app.controller('rpPlotCtrl', function ($scope) {
$scope.dyndata={};
$scope.assign_sk = function (testjsobj) {
alert('From Angular JS'+ JSON.stringify(testjsobj));
$scope.dyndata=testjsobj;
};
});
</script>
<script type="text/javascript">
jsonList = [];
jsonList.res_full_sk = [
{ "tid": 20, "sk": [{ "name": "Banking", "value": 40, "id": 0 }, { "name": "Housing", "value": 4, "id": 1 }, { "name": "Home", "value": 4, "id": 2 }, { "name": "NET", "value": 4, "id": 3 }] },
{ "tid": 22, "sk": [{ "name": "Movie", "value": 12, "id": 0 }, { "name": "Movie2", "value": 4, "id": 1 }, { "name": "Housing", "value": 4, "id": 2 }, { "name": "Banking", "value": 4, "id": 3 }, { "name": "C", "value": 4, "id": 4 }] },
{ "tid": 24, "sk": [{ "name": "Housing", "value": 4, "id": 0 }, { "name": "Home", "value": 4, "id": 1 }, { "name": "Banking", "value": 4, "id": 2 }] }
];
arr = [];
function getObjContents(i) {
arr = $.grep(jsonList.res_full_sk, function (e) {
return e.tid == i;
});
var str = "";
for (var i = 0; i < arr[0].sk.length; i++) {
str += ","+ JSON.stringify(arr[0].sk[i]);
}
str=str.substring(1);
str = "[" + str + "]";
str_obj=JSON.parse(str);
str_fin = {};
str_obj.forEach(function (e, i) {
str_fin['d' + i] = e;
});
return str_fin;
}
function insertDiv(Num) {
array = [];
var ar1 = Num.replace('[', '');
array = JSON.parse("[" + ar1 + "]");
var i = 0;
for (i; i < array.length; i++) {
js_data={};
js_data=getObjContents(array[i]);
testjsobj=js_data;
var scope = angular.element(document.getElementById("rpPlotCtrl")).scope();
scope.$watch("dyndata", function (oldval, newval) {
}, true);
scope.$apply(function () {
scope.dyndata = js_data;
});
var id_num;
id_num = array[i];
var rChart = angular.element(document.getElementById("sktemp"));
rChart.injector().invoke(function ($compile) {
$('<div obj></div>').insertAfter("#sktemp")
var obj = $('[obj]'); // get wrapper
var scope1 = $('[obj]').scope();
// generate dynamic content
alert(JSON.stringify(scope1.dyndata));
obj.html("<div class='skpro' id='skpro" + id_num + "' name='cn'><div class='skprovis' id='skprovis" + id_num + "' >Hello " + id_num + "<div class='half-plot' style='height:95%;width:95%;margin-top:0px;margin-left:5px;'><rp-plot dsn='dyndata' point-radius='1.5' scale='log' labelled='true' class='plot-rp-plot'></rp-plot></div></div></div>");
// compile!!!
console.log(obj.contents());
$compile(obj.contents())(scope1);
scope1.$apply();
});
}
}
</script>
The problem is dyndata is being changed for each value of i in the for loop, and thus the d3 chart is updated with the lastly assigned dyndata object.
As I see the dyndata object is being assigned with different values each time for loop executes, but it is not remaining but changes with the next value of dyndata to all the charts that were created.
How can I get the historic data to persist for dyndata that is already rendered for each for loop execution?
Am new to Angularjs and not very sure how I can make use of Angular.copy() for this scenario.
Problem seems to be with below code -
var scope = angular.element(document.getElementById("rpPlotCtrl")).scope();
scope.$watch("dyndata", function (oldval, newval) {
}, true);
scope.$apply(function () {
scope.dyndata = js_data;
});
as soon as I assign new js_data value to dyndata, all the existing charts gets updated with new value.
I tried using angular.copy(scope.dyndata)=js_data.. But it didn't work out.
Can you please suggest me?

Resources