Karma unit testing of controller using service. Ionic app - javascript

I'm new to Ionic and trying to test my controller which is using a service but keep getting 'undefined' with '$scope.order', '$scope.stock' and all the functions included in my controller. I have tested the service separately all tests passing there but can't get my head around controller testing. I'm sure I'm doing something wrong. Would be grateful is somebody could guide me a little bit.
controller.js
angular.module('shop.controllers', [])
.controller('StockCtrl', function($scope, Stock) {
$scope.stock = Stock.all();
$scope.order = Stock.order();
$scope.showTotalPrice = function() {
$scope.total = Stock.total();
}
$scope.addToBasket = function(chatId){
Stock.update(chatId);
Stock.updateBasket(chatId);
}
});
service.js
angular.module('shop.services', [])
.factory('Stock', function() {
var order = [];
var prices = [];
var total = 0;
var items = [{
id: 0,
name: "Black Shoes",
price: 50,
quantity: 7
},
{
id: 1,
name: "Blue Shoes",
price: 10,
quantity: 2
},
{
id: 2,
name: "Green Shoes",
price: 14,
quantity: 5
},
{
id: 3,
name: "Red Flip Flops",
price: 9,
quantity: 6
}
}];
return {
all: function() {
return items;
},
get: function(itemId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parseInt(itemId)) {
return items[i];
}
}
return null;
},
update: function(itemId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parseInt(itemId)) {
return items[i].quantity -= 1;
}
}
return null;
},
updateBasket: function(itemId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parseInt(itemId)) {
order.push({name: items[i].name, price: items[i].price});
prices.push(items[i].price);
}
}
return null;
},
order: function() {
return order;
},
total: function() {
return total = eval(prices.join('+'));
},
};
});
controller.spec.js
describe('Controllers', function(){
var scope;
var control;
var StockMock;
beforeEach(module('shop.controllers'));
beforeEach(function(){
StockMock = jasmine.createSpyObj('Stock', ['all', 'get', 'update', 'updateBasket', 'order'])
inject(function($rootScope, $controller){
scope = $rootScope.$new();
control = $controller('StockCtrl', {$scope: scope, Stock: StockMock});
});
});
it("should have a scope variable defined", function() {
expect(scope).toBeDefined();
});
});

I think your problem is here:
beforeEach(module('shop.controllers'));
You should add the application module instead of controller module.
beforeEach(module('shop'));

Related

How to call transformResponse many times in Angularjs

I need to call transformResponse many times based persons array. But the following code call only the last index
function fill() {
var persons = [
{ id: 34, text: $translate.instant("enter") },
{ id: 36, text: $translate.instant("high") },
{ id: 53, text: $translate.instant("graduates") },
{ id: 35, text: $translate.instant("persons") },
]
var personSubCategoriesList = [];
for (var i = 0; i < persons.length; i++) {
$scope.remote = {
url: window.config.apiHostUrl + `lookup/Get?id=${persons[i].id}`,
transformResponse: function (data) {
var personSubCategories = angular.fromJson(data);
angular.forEach(personSubCategories, function (personSubCategoriesObjet) {
var categories = { name: personSubCategoriesObjet.localizedName, code: personSubCategoriesObjet.id };
personSubCategoriesList.push(categories);
});
return personSubCategoriesList.map(function (adminCategories) {
return {
name: adminCategories.name,
code: adminCategories.code
};
});
}
};
}
}
I found the solution by using observable $q

Javascript array of headers to a tree

I'm working with a list of HTML headers (h2,h3,h4,h5,h6).
The picture describes the idea:
[
{
text: 'Some header',
rank: 2, // stays for <h2>
},
{
text: 'Some another header',
rank: 3, // stays for <h3>
},
{
text: 'A header with the same rank',
rank: 3, // stays for <h3>
},
{
text: 'One more subsection header',
rank: 4, // stays for <h4>
}
]
And I'm trying to turn it into a tree:
[
{
text: 'Some header',
children: [
{
text: 'Some another header',
},
{
text: 'A header with the same rank',
children: [
{
text: 'One more subsection header',
}
]
}
]
}
]
Here's my current code:
function list_to_tree(list) {
// We go from the end to the beggining
list = list.reverse();
let node, nextNode, roots = [], i;
for (i = 0; i < list.length; i += 1) {
node = list[i];
nextNode = list[i+1];
// If the next one's rank is greater, the current into the next as a child
if (nextNode !== undefined && node.rank > nextNode.rank) {
list[i+1].children.push(node);
} else {
// Else it's a root
roots.push(node);
}
}
return roots;
};
But it works only for the first h3, but the second h3 will go as a root. Any idea on how to achieve the goal? Thank you.
You could use the level property rank for indicating the nested position in a helper array.
Then iterate the data and build children arrays, if necessary.
function getTree(array) {
var levels = [{}];
array.forEach(function (o) {
levels.length = o.rank;
levels[o.rank - 1].children = levels[o.rank - 1].children || [];
levels[o.rank - 1].children.push(o);
levels[o.rank] = o;
});
return levels[0].children;
}
var data = [{ text: 'Main Heading', rank: 1 }, { text: 'Sub Heading', rank: 2 }, { text: 'Sub Sub Heading', rank: 3 }, { text: 'Sub Heading', rank: 2 }, { text: 'Sub Sub Heading', rank: 3 }, { text: 'Sub Sub Heading', rank: 3 }];
console.log(getTree(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This solution will work irrespective of starting rank and also of the order in which the list is given... and it uses the exact data you provided...
var jsonHeaders =
[
{
text: 'Some header',
rank: 2, // stays for <h2>
},
{
text: 'Some another header',
rank: 3, // stays for <h3>
},
{
text: 'A header with the same rank',
rank: 3, // stays for <h3>
},
{
text: 'One more subsection header',
rank: 4, // stays for <h4>
}
];
function list_to_tree(list)
{
var jsonTree = [{}];
list = list.reverse();
for (i = 0, l = list.length; i < l; i++)
{
node = list[i];
var json = {};
json.text = node.text;
json.rank = node.rank;
if(jsonTree[0].rank == undefined)
{
jsonTree[0] = json;
}
else
if(jsonTree[0].rank == json.rank)
{
jsonTree.push(json);
}
else
if(jsonTree[0].rank < json.rank)
{
jsonTree[0] = ranker(jsonTree[0], json);
}
else
if(jsonTree[0].rank > json.rank)
{
var jsonTemp = jsonTree[0];
jsonTree[0] = json;
json = jsonTemp;
jsonTree[0] = ranker(jsonTree[0], json);
}
}
return jsonTree;
}
function ranker(jsonTree, json)
{
if(jsonTree.children == undefined)
{
jsonTree.children = [];
jsonTree.children.push(json);
}
else
if(jsonTree.children[0].rank == json.rank)
{
jsonTree.children.push(json);
}
else
if(jsonTree.children[0].rank < json.rank)
{
jsonTree.children[0] = ranker(jsonTree.children[0], json);
}
else
if(jsonTree.children[0].rank > json.rank)
{
var jsonTemp = jsonTree;
jsonTree = json;
json = jsonTemp;
jsonTree.children[0] = ranker(jsonTree.children[0], json);
}
return jsonTree;
}
var jsonTree = list_to_tree(jsonHeaders);
console.log('jsonArrayTree = ', jsonTree);
Here's the working function in case someone needs it:
function list_to_tree(list) {
list = list.reverse();
let node, currentRank = list[0].rank, i, roots = [];
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node.rank > currentRank) {
for (let n = i; n < list.length; n += 1) {
if (list[n].rank < node.rank) {
list[n].children.unshift(node);
break;
}
}
} else {
currentRank = node.rank;
roots.push(node);
}
}
return roots.reverse();
};

sum total depending for each department without duplicates

I want to sum total depending for each department without duplicates.
Yesterday user #yBrodsky helped me with that and suggested to use SQL but today I want to add a couple options and I can't do this in sql.
Main problem:
I have an array like:
var data = [{
dept:"test",
task_time:"83"
},{
dept:"test",
task_time:"41"
},{
dept:"other",
task_time:"10"
}];
And I want to sum task_time for every dept: for example test = 124 and other = 10.
There is a function which should calculate it but it works like test = 83. test = 41 and other = 10. And shows every dept instead one with sum.
There is function.
var totalPerDept = {};
angular.forEach(data, function(item) {
if(!totalPerDept[item.dept]) {
totalPerDept[item.dept] = 0;
}
totalPerDept[item.dept] += parseFloat(item.task_time);
});
Here's the above as a snippet:
var data = [{
dept:"test",
task_time:"83"
},{
dept:"test",
task_time:"41"
},{
dept:"other",
task_time:"10"
}];
var totalPerDept = {};
angular.forEach(data, function(item) {
if(!totalPerDept[item.dept]) {
totalPerDept[item.dept] = 0;
}
totalPerDept[item.dept] += parseFloat(item.task_time);
});
console.log(totalPerDept);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
I did some modifications to your code to obtain an array with the result you want:
function sumDeptData() {
var data = [{
dept:"test",
task_time:"83"
},{
dept:"test",
task_time:"41"
},{
dept:"other",
task_time:"10"
}];
var totalPerDept = [];
angular.forEach(data, function(item) {
var index = findWithAttr(totalPerDept, 'dept', item.dept);
if (index < 0) {
totalPerDept.push({
dept: item.dept,
total: parseFloat(item.task_time)
});
} else {
totalPerDept[index].total += parseFloat(item.task_time);
}
});
return totalPerDept;
}
function findWithAttr(array, attr, value) {
for(var i = 0; i < array.length; i += 1) {
if(array[i][attr] === value) {
return i;
}
}
return -1;
}
sumDeptData() returns [{"dept":"test","total":124},{"dept":"other","total":10}]
Here is an example using Plain JavaScript.
var data = [{
dept: "test",
task_time: "83"
}, {
dept: "test",
task_time: "41"
}, {
dept: "other",
task_time: "10"
}],
minArr = [];
data.forEach(function(v) {
if (!this[v.dept]) {
this[v.dept] = {
dept: v.dept,
task_time: 0
};
minArr.push(this[v.dept]);
}
this[v.dept].task_time = parseInt(this[v.dept].task_time) + parseInt(v.task_time);
}, {});
console.log(minArr);

Return match between two array values in AngularJS

Am having a problem to return match array between two array element, please any help is important
here is my code
$scope.MacA = [
{
name: '24:fd:52:c3:d8:35',
sector: 'A23'
},
{
name: '56:db:30:4b:57:45',
sector: 'It support'
},
{
name: 'b6:b6:76:6b:e9:00',
sector: 'A24'
},
{
name: 'e8:74:e6:a1:14:16',
sector: 'Vodafone Guest'
},
{
name: 'dc:4a:3e:b7:32:0e',
sector: 'Direct HP officejet'
}
,
{
name: '7c:4c:a5:32:13:29',
sector: 'skyb7'
}
]
and array 2 is
scope.match = ['dc:4a:3e:b7:32:0e','7c:4c:a5:32:13:29' ];
and here is the function that returns the match if found
$scope.getList = function(){
// $scope.wifiList = WifiService.list();
var c = $scope.MacA;
var m = WifiService.list();
for(var i = 0;i < c.length;i++) {
for(var j = i;j < m.length;j++) { // Notice the j = i;
if (c[i].name === m[j]) {
$scope.result = c[i].sector;
// $scope.result = 'Its working';
break;
} else {
$scope.result = "Sorry!";
}
};
};
return $scope.result;
}
You didn't specify what exactly you want as the result, but here is a possible version that looks for matches.
var result = [];
match.forEach(m => result.push(MacA.find(macA => macA.name === m)));
MacA = [
{
name: '24:fd:52:c3:d8:35',
sector: 'A23'
},
{
name: '56:db:30:4b:57:45',
sector: 'It support'
},
{
name: 'b6:b6:76:6b:e9:00',
sector: 'A24'
},
{
name: 'e8:74:e6:a1:14:16',
sector: 'Vodafone Guest'
},
{
name: 'dc:4a:3e:b7:32:0e',
sector: 'Direct HP officejet'
},
{
name: '7c:4c:a5:32:13:29',
sector: 'skyb7'
}
]
Match = ['dc:4a:3e:b7:32:0e','7c:4c:a5:32:13:29' ];
MacA.filter(({name}) => Match.includes(name)).map(({sector}) => sector)
// RETURNS // ["Direct HP officejet", "skyb7"]
SO, given your code above, something like this:
$scope.getList = function(){
return $scope.result = $scope.MacA.filter(({name}) => $scope.match.includes(name)).map(({sector}) => sector)
}
I've refactored some of your code.
$scope.getList = function(){
var devices = $scope.MacA;
var macList = WifiService.list();
var results = devices.reduce((acc, device) => acc.concat(macList.find(current.name)? [current.sector]:[]), []);
return results.length? $scope.results = results : $scope.results = 'Sorry!';
}

how to dynamically generate model names in a service

I have a service that i am using to apply a unique number to a model name. the result i am getting is this
"sectionInputs": [
{
"model": "price_min1"
},
{
"model": "price_max2"
},
{
"model": "units_occ3"
},
{
"model": "inv_mod4"
},
{
"model": "inv_fin5"
},
{
"model": "inv_vdl6"
},
{
"model": "inv_uc7"
},
{
"model": "inv_fut8"
},
{
"model": "inv_con9"
},
{
"model": "units_total10"
}
]
i need this to each have '1'. and then in the next object array i need them to have '2', etc... as of now every object array looks like this. i have a plunker with everything setup.
plunker
function sectionInputSvc(sectionInputs) {
var vm = this;
vm.sectionInputsArry = sectionInputs;
vm.sectionInputs = function () {
var arry = [];
var counter = 0;
for (var i = 0; i < vm.sectionInputsArry.length; i++) {
counter++
var obj = {
model: vm.sectionInputsArry[i].model + counter
};
arry.push(obj);
};
return arry;
};
};
[EDIT 2]
in app.js...
sections[i].sectionInputs = sectionInputSvc.sectionInputs(sections[i],i);
and in section.service.js...
function sectionInputSvc(sectionInputs) {
var vm = this;
vm.sectionInputsArry = sectionInputs;
var obj2={};
vm.sectionInputs = function (obj2,num) {
var arry = [];
var counter = 0;
for (var i = 0; i < vm.sectionInputsArry.length; i++) {
counter++
var obj = {
model: vm.sectionInputsArry[i].model + num
};
arry.push(obj);
};
return arry;
};
};
Using linq.js, and assuming the suffixes do not already exist on the names:
vm.sectionInputs = function () {
return Enumerable.From(vm.sectionInputsArry).Zip(Enumerable.ToInfinity(1),
"{ model: $.model+$$ }"
).ToArray();
};

Categories

Resources