As part of a bootcamp I am taking, I have been asked to create an online shopping cart.
I am having such a problem with the addToCart function in the sense that I keep managing to to console log [{itemName: item, itemPrice: 8}] rather than 'item has been added to cart.
I think my problem lies in my template literal.
The aim is for the function to take in an item, create an object around it, apply additional properties, add to the cart array, console log that the item has been added (this is where my problem lies) then return the cart.
I have tried a number of alternatives such as trying to access the values via dot notation and using the key of the object to access the value. still have had no joy.
Below is my code:
function addToCart(item) {
// write your code here
var price = Math.floor(Math.random() * 100) + 1;
var obj = {itemName: item, itemPrice: price};
cart.push(obj);
console.log(`${item} has been added to your cart.`)
return cart;
}
What I am expecting is for the item that is being parsed into the function to be log to the console stating that the item has been added. I believe the rest of the code is working fine as it is passing the local tests.
The error I get is this:
Error: Expected [{itemName:'ice cream', itemPrice: 26}] to equal 'ice cream has been added to your cart.'
Any tips would be very helpful.
I had a look at your tests,
Try following
your test is (I hope I picked the right one) :
it("returns a message indicating that the item has been added", function() {
expect(addToCart("ice cream")).toEqual("ice cream has been added to your cart.");
expect(addToCart("juice")).toEqual("juice has been added to your cart.");
});
Change your code to :
function addToCart(item) {
// write your code here
var price = Math.floor(Math.random() * 100) + 1;
var obj = {itemName: item, itemPrice: price};
cart.push(obj);
console.log(`${item} has been added to your cart.`)
return `${item} has been added to your cart.`;
//OR
//return `${obj.itemName} has been added to your cart.`;
}
As you are comparing the returned value from "addToCart" in your test with the string in .toEqual so, so you should return that particular formatted string from your function.
So instead of returning cart, you should return that particular string that you want to check.
You need to define the cart as a global variable. Please check the below code snippet.
cart = [];
(function() {
addToCart("Apple");
addToCart("Orange");
console.log(this.cart)
})();
function addToCart(item) {
var price = Math.floor(Math.random() * 100) + 1;
var obj = {itemName: item, itemPrice: price};
this.cart.push(obj);
console.log(`${item} has been added to your cart.`)
return cart;
}
Looking at the error you're getting makes me think the error is thrown by a test you're running.
That test is checking the value returned by your function and not what's logged in the console. In order to not get the error anymore, you should fix that test.
Assuming your tests are using Jasmine, that test would look something like:
const cart = addToCart(item);
expect( cart[0]['itemName'] ).toBe('ice cream')
Related
I'm trying to refactor an object into an array to fit an API that I have to use.
function buildObject(data) {
console.log(data) // correct ouput
var jsonLayers = Object.entries({...data}).map(([k, v]) => {
console.log(`value : ${v}`) // correct output
return {
label: k,
pointMap: v,
color: v.layerColor?v.layerColor:tabList[tabList.map(i => i.tabName).indexOf(k)].layerColor?tabList[tabList.map(i => i.tabName).indexOf(k)].layerColor:defaultPOILayerColor,
}}
)
console.log(jsonLayers) // incorrect output
return jsonLayers
}
I have 2 scenarios in which I call this function but with the same data (console.log(data) logs the exact same result).
In the first scenario I obtain the desired result and in the second the pointMap attribute is an empty Array.
In the case where it does not work the console.log(`value : ${v}`) logs the correct value but when I log console.log(jsonLayers) the attribute pointMap is empty.
Any ideas on why this happens ?
Edit: as mentionned below this code works with sample data so I suppose this must comes to how the function is called. Everything runs in a UWA widget with jQuery
So for the context here is an idea of how they are called in both cases :
var data = {
a: { tabName: "tab1", layerColor: 1 },
b: { tabName: "tab2", layerColor: 2 },
};
$('#button1').on('click', function() {
ExternalAPI.Publish('some-external-address', buildObject(data));
});
$('#button2').on('click', function() {
let jsonData = buildObject(data);
//some manipulations of jsonData
ExternalAPI.Publish('some-external-address', jsonData);
});
It works on button1 but not on button2, they are clicked are at a different moment but data contains the same object when both are clicked
Edit2 :
Found the issue,
In the manipulations of jsonData I accidentally use slice(1,1) instead of splice(1,1) which empties the array.
What drove me crazy is that this modification was perform after the log but the var was log with the modification.
At least I learnt that spread operator does not deepcopy
Found the issue,
In the manipulations of jsonData I accidentally use slice(1,1) instead of splice(1,1) which empties the array.
What drove me crazy is that this modification was perform after the log but the var was log with the modification
I am following a course on blockchain which has the following piece of code.
What does " index:this.chain.length+1 " mean? Is index a variable in the object newBlock? Or is it a key value pair? If it is a variable, why don't we simply use index=this.chain.length+1? Also what is the type of the object newBlock?
function Blockchain()
{
this.chain=[];
this.newTranscations=[];
}
Blockchain.prototype.createNeBlock = function(nonce,previousBlockHash,hash)
{
const newBlock ={
index:this.chain.length+1,
timestamp:Date.now(),
// all of the transactions in this block will be the transactions that waiting to be put in a block
transactions:this.newTranscations,
// nonce is hust a number giving proof of the transaction
nonce:nonce,
hash:hash,
previousBlockHash: previousBlockHash
}
// As we move all the pending transactions to the new block, we clear this array
this.newTranscations=[];
this.chain.push(newBlock);
return newBlock;
}
var Box = {
"playdoh":{"playdoh":["none", "some", "none", "none", "some"]}
};
Box of playdoh upon playdoh, you're getting into the study of Objects/Arrays/Maps.
To call the above out, it'd be
console.log(Box["playdoh"]["playdoh"][0]);
= none
console.log(Box["playdoh"]["playdoh"][4]);
= some
console.log(Box["playdoh"]["playdoh"][5]);
= null (undefined)
is the same as
console.log(Box.playdoh.playdoh[0]);
= none
console.log(Box.playdoh.playdoh[4]);
= some
console.log(Box.playdoh.playdoh[5]);
= null (undefined)
It is one of several ways to initialize an object called newBlock in javascript. Take a look at this documentation on MDN
The index property is of type number in this case, and it is set to equal chain[].length + 1
I have a little web scraping scipt running which works well for the majority of items until the pattern changes on the website.
Website scraped (terms of use and robots.txt obeyed):
https://www.studycheck.de/hochschulen/fhvr-bayern/bewertungen
It's a german page with student reviews regarding their universities / courses.
In the code below I grab a whole div container with everything I need for every student rating and split that up for a constructor in a map function in the return statement of puppeteers page evaluate function.
Constructor:
function Corpus(course, rating, author, text, date){
this.course = course;
this.rating = rating;
this.author = author;
this.text = text;
this.date = date;
}
Function taking up div and returning properties of individual css-selector items:
var getReview = await page.evaluate(() => {
//this querySelectorAll get's the 4 review divs per page
let reviewBlock = Array.from(document.querySelectorAll("div [class*='report-item-boxed']"))
//now I split up the 5 items I need for my constructor
return reviewBlock.map(block => [
block.querySelector(".item-course-title a").textContent.trim(),
block.querySelector("div .rating-value").textContent.trim(),
block.querySelector(".item-author").innerText,
block.querySelector("p.item-text").innerText.trim(),
block.querySelector('span.item-date').innerText
]);
});
That works just fine for all reviews up to an certain age. These older reviews deep into the pagination don't have a element "div .rating-value" and so that .textcontent comes back null and the code breaks.
I tried to put a if(css-element == null){than return "null"} else {map the textcontent as normal) but it throws an error, that the if is an unexpected token in that place...
I tried to understand if these posts here on SO are my problem, but could not figured it out.
Javascript if statement inside return
Null check in the return statement
Should I do any error handling before the return statement and then return an object?
I deeply appreciate any hints how to solve that issue and return a placeholder value in case a selector isn't found / it's property value is null.
Thanks!!!
Not saying that this is the cleanest solution, but in order to fix your problem:
This:
return reviewBlock.map(block => [
block.querySelector(".item-course-title a").textContent.trim(),
block.querySelector("div .rating-value").textContent.trim(),
block.querySelector(".item-author").innerText,
block.querySelector("p.item-text").innerText.trim(),
block.querySelector('span.item-date').innerText
]);
is equivalent to:
return reviewBlock.map(block => {
// So you can make your if conditions here,
// and build the array dynamically before returning it.
return [
block.querySelector(".item-course-title a").textContent.trim(),
block.querySelector("div .rating-value").textContent.trim(),
block.querySelector(".item-author").innerText,
block.querySelector("p.item-text").innerText.trim(),
block.querySelector('span.item-date').innerText
]
});
Code:
initialize: function() {
this.todos = [
{id: 100, text: 'Rich'},
{id: 200, text: 'Dave'}
];
},
activeTodos: function() {
this.todos = this.todos.length(function() {
return this.todos;
});
this.emitChange();
}
<p>Todo's Remaining: {this.activeTodos} </p>
activeItems: function(){
this.context.executeAction(activeToDosAction);
},
Explanation:
I am trying to print out the size of the array to the browser window (this can be seen in the <p> tags within the code). So far nothing is displaying and I cant figure out why. activeTodos should be calling the length of todos.
i can post more code if people require it. i am using reactjs hence the { } brackets within HTML
There are a couple of weird things there. If you only need to display the length of this.todos you can do something like this:
<p>Todo's Remaining: {this.todos.length} </p>
I think the problem here is that you pass a function to length. That is not required.
Your code should work if you change it to:
activeTodos: function() {
return this.todos.length;
}
I'm not sure what your function emitChange should be doing, so I omitted it for now in the code example. If you need it to be called, put it before the return as that is the last thing that will run in your function.
First, to access the length of an array you just have to do
myArray = [1, 2, 3];
myArray.length; //3
Moreover you have 2 fonctions : initialize and activeTodos where you use this.todos = ...
Without further explanations I assume these variables created with the keyword 'this' inside 2 different functions are out of score.
Verify that your this.todos refers to the same thing.
You do not need active.Todos() as .length is a built in function by itself.
Just do
Todo's Remaining: {this.todos.length}
Cheers.
I test Angular application. This fact should not be of high importance here though.
My function to be tested looks like this:
$scope.showItem = function (item) {
if (item.selected) {
activeItems.push(item);
} else {
var index = _.indexOf(activeItems, items);
activeItems.splice(index, 1);
}
};
Function works as desired. Array activeItems is used in another function which after some modifications assigns the result to the scope.
The behavior is that if the item is not selected it is added to the array. If the item is already selected, it will be removed from the array.
it('should remove an item from the array', function () {
var activeItems = [{id: 1, selected: false}, {id:2, selected: true}];
var item = {
id: 1,
selected: false
};
expect(activeItems.length).toEqual(2);
scope.showItem(item);
expect(activeItems.length).toEqual(1); // FAIL!
// expects do not work for var variables. would work, if activeItems is assigned to the scope
});
If I assign activeItems to the scope (scope.activeItems instead of var activeItems), it all works; however, I believe that if the variable is not to be shown in the view, it should not be assigned to the scope.
First expect will work because is defined inside it block:
expect(activeItems.length).toEqual(2);
Second will not:
expect(activeItems.length).toEqual(1);
but it would for scope variable:
expect(scope.activeItems.length).toEqual(1);
My question is how to test that var value?
I'm not positive, as it's hard to tell your intentions, and if you have any other globals, but I think your error is that your using activeItems outside of it's scope., but again its hard to tell because you may have other globals causing the problem. If it is that activeItems is outside of it's scope, then it will reach an error at expect,scope, andexpect again. Then it won't effect the array, and it will stay as it was edited during showItem
Hope this helps!