Mocha undefined tests and weird behavior - node.js

Issue is mocha is outputting incorrect data
output of mocha test/test
PS C:\Users\rluth\API\main\test> mocha
kordata API
matching given hufflepuff and gryffindor
1) should be false
matching given gryffindor and gryffindor
2) should be true
values of grades
3) given A it should be 4
values of grades
4) given F it should be 0
0 passing (17ms)
4 failing
1) kordata API
matching given hufflepuff and gryffindor
should be false:
TypeError: scripts.matchingClass is not a function
at Object.matchShouldFail (src\testscripts.js:7:24)
at Context.it (test\test.js:7:42)
2) kordata API
matching given gryffindor and gryffindor
should be true:
TypeError: scripts.matchingClass is not a function
at Object.matchShouldPass (src\testscripts.js:11:24)
at Context.it (test\test.js:11:41)
3) kordata API
values of grades
given A it should be 4:
TypeError: test.AShouldBe4 is not a function
at Context.it (test\test.js:15:49)
4) kordata API
values of grades
given F it should be 0:
TypeError: test.FShouldBe0 is not a function
at Context.it (test\test.js:19:49)
Heres the test/src/testscripts.js
'use strict';
const expect = require("chai").expect
var scripts = require("../../Resources/js/functions.js")
module.exports = {
matchShouldFail: function() {
expect(scripts.matchingClass("hufflepuff","gryffindor").to.equal(false))
},
matchShouldPass: function() {
expect(scripts.matchingClass("gryffindor","gryffindor").to.equal(true))
},
AshouldBe4: function() {
expect(scripts.calculateGradePoint("A").to.equal(4))
},
FshouldBe0: function() {
expect(scripts.calculateGradePoint("F").to.equal(0))
},
shouldBe3: function() {
expect(scripts.roundToHundreth(3,1,1).to,equal(3))
},
shouldBe2_25: function() {
expect(scripts.roundToHundreth(18,4,2).to.equal(2.25))
},
classShouldBe1: function() {
student = ["gym"]
expect(scripts.countClasses(student).to.equal(1))
},
classShouldBe3: function() {
student = ["gym", "english", "potions"]
expect(scripts.countClasses(student.to.equal(3)))
}
};
As you can see I'm getting this weird output where its renamed half my variables to test.functionname and the other half stay the same. As well I feel my code for my tests are perfectly fine
/main/resources/js/functions/js
module.exports = {
CalculateGradePoint: function (letterGrade) {
if (letterGrade === "A")
return 4
if (letterGrade === "B")
return 3
if (letterGrade === "C")
return 2
if (letterGrade === "D")
return 1
if (letterGrade === "E")
return 0
},
//checks if two values are the same
matching: function (actual, expected) {
if (actual === expected)
return true
return false
},
//calculates a GPA value to the nearest hundreth depeding
//on amount of students and classes and each students grade from that class
roundToHundreth: function (GPA, students, totalClasses) {
return Math.round(100 * GPA / (students * totalClasses)) / 100
},
//counts the amount of classes a student is taking
countClasses: function (student) {
var count = 0,
loop = 0
len = student.courses.length
for (loop = 0; loop < len; loop++)
count++
}
};
and the file that calls them
main/test/src/testscripts.js
'use strict';
const expect = require("chai").expect
var scripts = require("../../Resources/js/functions.js")
module.exports = {
matchShouldFail: function() {
expect(scripts.matchingClass("hufflepuff","gryffindor").to.equal(false))
},
matchShouldPass: function() {
expect(scripts.matchingClass("gryffindor","gryffindor").to.equal(true))
},
AshouldBe4: function() {
expect(scripts.calculateGradePoint("A").to.equal(4))
},
FshouldBe0: function() {
expect(scripts.calculateGradePoint("F").to.equal(0))
},
shouldBe3: function() {
expect(scripts.roundToHundreth(3,1,1).to,equal(3))
},
shouldBe2_25: function() {
expect(scripts.roundToHundreth(18,4,2).to.equal(2.25))
},
classShouldBe1: function() {
student = ["gym"]
expect(scripts.countClasses(student).to.equal(1))
},
classShouldBe3: function() {
student = ["gym", "english", "potions"]
expect(scripts.countClasses(student.to.equal(3)))
}
};
Ive tried looking around for other issues but they were usually caused by not importing the functions at all or just incorrectly. And what i really dont understand is why half the tests names have the old variable name and the other ones have the new ones. Mainly why my code isnt working. I feel everything is setup correctly. I did have issues with not finding the functions but I figured out how to handle that. And now im being told that these functions are not a function. Im assuming its some small thing since this is my first time using this stuff on my own. Any help is appreciated it.

Related

Sequelize - NodeJS - Return o function is undefined

I am trying to understand how I can fix my code, because my function is return undefined. I am wirting my code with Sequelize and NodeJS.
exports.getCreditsStudent = function(sgecode,collections,grade,year){
mssql.query('SELECT total FROM [dbo].[creditosAvulsos] WHERE codsge = $sgecode1 and nivelensino_idnivelensino = $collections1 and produto_idproduto = $grade1 and ano = $year1',
{ bind:{sgecode1: sgecode, collections1: collections, grade1: grade, year1: year}, type: mssql.QueryTypes.SELECT})
.then(total => {
return total
})
}
And I call this function on my Service.js, like this:
examples = db.getCreditsStudent(sgecode,collections,grade,year);
Where and how is the problem?
Thanks.
The function getCreditsStudent does not actually return anything. Instead it simply defines a async process. You'll need to return the promise you've defined and then either use async/await or a promise chain to use the result.
exports.getCreditsStudent = function(sgecode,collections,grade,year){
return mssql.query('SELECT total FROM [dbo].[creditosAvulsos] WHERE codsge = $sgecode1 and
nivelensino_idnivelensino = $collections1 and produto_idproduto = $grade1 and ano = $year1',
{ bind:{sgecode1: sgecode, collections1: collections, grade1: grade, year1: year},
type: mssql.QueryTypes.SELECT})
.then(total => {
return total
})
}
And then inside an async function you can do
examples = await db.getCreditsStudent(sgecode,collections,grade,year);
or you can use
db.getCreditsStudent(sgecode, collections, grade, year)
.then(value => {
examples = value;
// whatever you want to do with examples...
});

Sequelize.js afterFind argument explanation

I'm trying to implement an afterFind hook on a model and can't quite figure out what the semantics are. I'll pulled the following together from trial and error using the doc and other StackOverflow questions as guidelines.
My goal is to massage the result (by applying get(plain : true)) and pass the transformed value as the result of the promise. For instance, I'd expect/want this to return an empty result set:
hooks: {
afterFind: function(result, options, fn)
{
result = [];
}
},
but it just causes the request to hang. Documentation says the arguments are pass by reference and doesn't include a return. Other samples imply something like:
hooks: {
afterFind: function(result, options, fn)
{
result = [];
return fn(null, result);
}
},
which doesn't hang, but doesn't change my result set. Not to mention, I've no idea what the magical "fn" argument is/does.
I had a similar problem. This is because when you do a findAll the argument passed to the hook is an array of values instead of a single object. I did this as a workaround -
hooks: {
afterFind: function(result) {
if(result.constructor === Array) {
var arrayLength = result.length;
for (var i = 0; i < arrayLength; i++) {
result[i].logo = "works";
}
} else {
result.logo = "works";
}
return result;
}
}
In the above code I change the logo attribute of the record(s) after finding it.

Handsontable numeric cell globalization

I'm relatively new to js and now have to implement a handsontable into our project.
This worked well so far, but I am hitting a roadblock with globalization.
Basically, we use comma as a decimal seperator, but when I try and copy something like "100,2" into a cell designated as 'numeric,' it will show as 1002.
If the same value is entered in a cell designated as 'text' and the type is changed to numeric afterwards, the value will be shown correctly.
For this I already had to add 'de' culture to the table sourcecode.(basically copying 'en' and changing the values currently relevant to me.)
numeral.language('de', {
delimiters: {
thousands: '.',
decimal: ','
},//other non-relevant stuff here
When I copy the values directly from the table and insert them to np++ they show as 100.2 etc. However, when inserting them into handsontable the arguments-array looks as follows:
[Array[1], "paste", undefined, undefined, undefined, undefined]
0: Array[4]
0: 1 //row
1: 1 //column
2: "100.2" //previous value
3: 1002 //new value
Here's what I have tried currently:
hot.addHook("beforeChange", function () {
if (arguments[1] === "paste") {
hot.updateSettings({
cells: function (row, col, prop) {
var cellProperties = {
type: 'numeric',
language: 'en'
};
return cellProperties;
}
});
//hot.updateSettings({
// cells: function (row, col, prop) {
// var cellProperties = {
// type: 'text',
// };
// return cellProperties;
// }
//});
}
}, hot);
hot.addHook("afterChange", function () {
if (arguments[1] === "paste") {
ChangeMatrixSettings(); //reset cell properties of whole table
}
}, hot);
I hope I've made my problem clear enough, not sure if I missed something.
Are there any other ways to get the correct values back into the table? Is this currently not possible?
Thanks in advance.
You asked more than one thing, but let me see if I can help you.
As explained in handsontable numeric documentation, you can define a format of the cell. If you want '100,2' to be shown you would format as follows
format: '0.,'
You can change that to what you really need, like if you are looking for money value you could do something like
format: '0,0.00 $'
The other thing you asked about is not on the latest release, but you can check it out how it would work here
I have since implemented my own validation of input, due to other requirements we have for the table mainly in regards to showing invalid input to user.
function validateInputForNumeric(parameter) {
var value = parameter[3];
var row = parameter[0];
var col = parameter[1];
if (decimalSeperator === '') {
var tmpculture = getCurrCulture();
}
if (value !== null && value !== "") {
if (!value.match('([a-zA-Z])')) {
if (value.indexOf(thousandSeperator) !== -1) {
value = removeAndReplaceLast(value, thousandSeperator, ''); //Thousandseperators will be ignored
}
if (value.indexOf('.') !== -1 && decimalSeperator !== '.') {
//Since numeric variables are handled as '12.3' this will customize the variables to fit with the current culture
value = removeAndReplaceLast(value, '.', decimalSeperator);
}
//Add decimalseperator if string does not contain one
if (numDecimalPlaces > 0 && value.indexOf(decimalSeperator) === -1) {
value += decimalSeperator;
}
var index = value.indexOf(decimalSeperator)
var zerosToAdd = numDecimalPlaces - (value.length - index - 1);
for (var j = 0; j < zerosToAdd; j++) {
//Add zeros until numberOfDecimalPlaces is matched for uniformity in display values
value += '0';
}
if (index !== -1) {
if (numDecimalPlaces === 0) {
//Remove decimalseperator when there are no decimal places
value = value.substring(0, index)
} else {
//Cut values that have to many decimalplaces
value = value.substring(0, index + 1 + numDecimalPlaces);
}
}
if (ErrorsInTable.indexOf([row, col]) !== -1) {
RemoveCellFromErrorList(row, col);
}
} else {
AddCellToErrorList(row, col);
}
}
//console.log("r:" + row + " c:" + col + " v:" + value);
return value;
}
The inputParameter is an array, due to handsontable hooks using arrays for edit-events. parameter[2] is the old value, should this be needed at any point.
This code works reasonably fast even when copying 2k records from Excel (2s-4s).
One of my main hindrances regarding execution speed was me using the handsontable .getDataAtCell and .setDataAtCell methods to check. These don't seem to handle large tables very well ( not a critique, just an observation ). This was fixed by iterating through the data via .getData method.

YUI, instantiable module that is not a widget?

If I want a module that is instantiable, let say, a module that handles storing preferences in a subcookies, and i want the main cookie to be configurable, but i don't want it to be a widget... what patterns should i use with YUI?
the end code should be something:
Y.use('my-pref-manager', function(Y){
var A = Y.my-pref-manager.prefStore('A"),
B = Y.my-pref-manager.prefStore('B");
// A and B are now loaded with the contents of cookies A and B, if they exist
A.set('xy', 123 );
});
So far i either found patterns that create widgets within my-module or i have to use methods directly in my-method which will be globals and lack initializers, etc.
There is a bunch of ways of doing this. You could do it using Y.Base.create, like below. The code might not be production ready, or even working properly, but hopefully it answers how you can create a module without it being a Widget.
The code below creates a module that extends Y.Base. This let us use Attributes and other cool things. Check the doc for Y.Base.
YUI.add('my-pref-manager', function (Y) {
var PrefManager = Y.Base.create('myPrefManager', Y.Base, [], {
initializer: function () {
this.after('prefsChange', this.changePref);
},
changePref: function (e) {
Y.Cookie.setSub(this.get('prefStore'), e.subAttrName, this.get(e.subAttrName));
},
setPref: function (name, val) {
this.set('prefs.'+name, val);
},
getPref: function (name) {
return this.get('prefs.'+name);
}
}, {
ATTRS: {
prefStore: {
value: null,
setter: function (val) {
return Y.Cookie.set(val, val);
}
},
prefs: {
value: {}
}
}
});
Y.namespace('My').PrefManager = PrefManager;
}, '0.0.1', {
requires: ['base', 'cookie']
});
YUI().use('my-pref-manager', function (Y) {
var A = new Y.My.PrefManager({prefStore: 'userPrefs'}),
B = new Y.My.PrefManager({prefStore: 'displayPrefs'});
A.setPref('x', 3);
A.setPref('y', 54);
B.setPref('tty', 7);
console.log(A.getPref('x')); // 3
});
Try it out: http://jsfiddle.net/B62nu/

Mongodb $where query always true with nodejs

When I query my database with a function passed in the "$where" clause in nodejs, it always return me all documents in the db.
For example, if I do
var stream = timetables.find({$where: function() { return false; }}).stream();
it return me all the documents.
Instead, if I do
var stream = timetables.find({$where: 'function() { return false; }'}).stream();
the function is really executed, and this code doesn't return any document.
The problem is that if I convert in string my function the context's bindinds are removed, and I need them for more complex query. For example:
var n = 1;
var f = function() { return this.number == n; }
var stream = timetables.find({$where: f.toString()}).stream();
// error: n is not defined
Is this a normal behaviour? How can I solve my problem?
Please excuse me for my poor english!
First off, keep in mind that the $where operator should almost never be used for the reasons explained here (credit goes to #WiredPrairie).
Back to your issue, the approach you'd like to take won't work even in the mongodb shell (which explicitly allows naked js functions with the $where operator). The javascript code provided to the $where operator is executed on the mongo server and won't have access to the enclosing environment (the "context bindings").
> db.test.insert({a: 42})
> db.test.find({a: 42})
{ "_id" : ObjectId("5150433c73f604984a7dff91"), "a" : 42 }
> db.test.find({$where: function() { return this.a == 42 }}) // works
{ "_id" : ObjectId("5150433c73f604984a7dff91"), "a" : 42 }
> var local_var = 42
> db.test.find({$where: function() { return this.a == local_var }})
error: {
"$err" : "error on invocation of $where function:\nJS Error: ReferenceError: local_var is not defined nofile_b:1",
"code" : 10071
}
Moreover it looks like that the node.js native mongo driver behaves differently from the shell in that it doesn't automatically serialize a js function you provide in the query object and instead it likely drops the clause altogether. This will leave you with the equivalent of timetables.find({}) which will return all the documents in the collection.
This one is works for me , Just try to store a query as a string in one variable then concat your variable in query string,
var local_var = 42
var query = "{$where: function() { return this.a == "+local_var+"}}"
db.test.find(query)
Store your query into a varibale and use that variable at your find query. It works..... :D
The context will always be that of the mongo database, since the function is executed there. There is no way to share the context between the two instances. You have to rethink the way you query and come up with a different strategy.
You can use a wrapper to pass basic JSON objects, ie. (pardon coffee-script):
# That's the main wrapper.
wrap = (f, args...) ->
"function() { return (#{f}).apply(this, #{JSON.stringify(args)}) }"
# Example 1
where1 = (flag) ->
#myattr == 'foo' or flag
# Example 2 with different arguments
where2 = (foo, options = {}) ->
if foo == options.bar or #_id % 2 == 0
true
else
false
db.collection('coll1').count $where: wrap(where1, true), (err, count) ->
console.log err, count
db.collection('coll1').count $where: wrap(where2, true, bar: true), (err, count) ->
console.log err, count
Your functions are going to be passed as something like:
function () {
return (function (flag) {
return this.myattr === 'foo' || flag;
}).apply(this, [true])
}
...and example 2:
function () {
return (
function (foo, options) {
if (options == null) {
options = {};
}
if (foo === options.bar || this._id % 2 === 0) {
return true;
} else {
return false;
}
}
).apply(this, [ true, { "bar": true } ])
}
This is how it is supposed to be. The drivers don't translate the client code into the mongo function javascript code.
I'm assuming you are using Mongoose to query your database.
If you take a look at the actual Query object implementation, you'll find that only strings are valid arguments for the where prototype.
When using the where clause, you should use it along with the standard operators such as gt, lt that operates on in the path created by the where function.
Remember that Mongoose querying, as in Mongo, is by example, you may want to reconsider your query specification in a more descriptive fashion.

Resources