I have no idea how to test this with Qunit? - javascript

I want to test this function:
/js/lib/front.js
var Front = function(){
this.onSignUp = function(){
if (!Form.assertInput("email")) {
$("input[name=email]").focus();
this.showHiddenMessage("Email not set.");
return false;
}
}
}
I have in:
/js/lib/form.js
function Form() {
this.assertInput = function (name, defaultValue) {
var text = $("input[name=" + name + "]").val();
if (defaultValue != null) {
if (defaultValue && text == defaultValue)
return false;
}
if(this.trim(text)) return true;
return false;
}
}
This simple test passing:
test("Front", function() {
var front = new Front()
ok(front);
});
But if I write something like this:
test("On Sign Up ", function() {
var front = new Front()
equal(front.onSignUp(),false,"passing test");
});
I have error:
Died on test #1: Form.assertInput is not a function
I don't understand, what I need test in function like this and how include function inside another function?

I've saved a working fiddle here. As a side note, you might want to check out a tutorial on using qUnit, here.One thing that you need to pay attention to is when you're declaring your functions. It's saying Form.assertInput is not a function because you can't access it like that. You need to use the this keyword, which refers to current context. The code should be something like this:
var Form = function () {
//good to have assertInput first if you're using it in a later function
this.assertInput = function (name, defaultValue) {
var text = $("input[name=" + name + "]").val();
if (defaultValue != null) {
//safer to explicitly close your if statements with {}
if (defaultValue && text == defaultValue) {
return false;
}
}
if ($.trim(text)) { return true; }
return false;
};
this.showHiddenMessage = function (message) {
alert(message);
};
this.onSignUp = function() {
//this will point to the current context, in this case it will be Form class
if (!this.assertInput("email")) {
$("input[name=email]").focus();
this.showHiddenMessage("Email not set.");
return false;
}
};
};
Also in the example code that you gave you're missing the Front class. So I created a dummy one in my fiddle like this:
var Front = function() {};
Here are the tests that were run:
$(document).ready(function() {
test("Front", function() {
var front = new Front();
ok(front);
});
test("On Sign Up ", function() {
var form = new Form();
equal(form.onSignUp(), false, "passing test");
});
});

Related

JS functions and abstract class and prototypes

Here is a simplified version of my code :
function TextBox () {
this.builddom = function () {
// Building the text dom
}
}
function ImageBox () {
this.builddom = function () {
// Building the image dom
}
}
function Box (type) {
var handler =
(type == 'text') TextBox :
(type == 'Image') ImageBox : null;
if (handler) (handler).call (this);
this.builddom = function () {
// Here I would like to call the correct builddom function for the type.
}
}
var textbox = new Box ('text');
textbox.builddom ();
If Box.builddom doesn't exists, this works fine, the builddom function associated with the specific type is called. But I need to do some general thing in Box and then call the specific builddom. If I give a different name to Box builddom, say Box.dobuilddom, it is fine too, but breaks generic access to Boxes.
I think some clever prototype manipulation can do the job, but I was unable to find it.
Maybe would be better to avoid prototyping and use composition instead:
function TextBox(box) {
this.builddom = function() {
console.log('Building the text dom', box.props);
}
}
function ImageBox(box) {
this.builddom = function() {
console.log('Building the image dom', box.props);
}
}
function Box(props) {
this.props = props;
this.builddom = function() {
throw new Error('unsupported function');
}
}
var textbox = new TextBox(new Box({size:5}));
textbox.builddom();
I don't really understand the concept. The box is just some sort of container. It does not do anything but creates a new instance. What you'd really need here is a Box interface, but js does not have interfaces. You can use TypeScript if you want to...
function TextBox () {
this.builddom = function () {
// Building the text dom
}
}
function ImageBox () {
this.builddom = function () {
// Building the image dom
}
}
var container = {
createBox: function (type){
if (type == "text")
return new TextBox();
else if (type == "image")
return new ImageBox();
else
throw new Error();
}
};
var textbox = container.createBox('text');
textbox.builddom();
Another option is using proxy if you want to wrap objects, but I don't think that's your goal here.
If you need type check later, then you can use inheritance, but there is no multi inheritance, so even that way you cannot imitate interfaces. It goes this way btw.
function Box (){}
function TextBox () {}
TextBox.prototype = Object.create(Box.prototype, {
constructor:TextBox,
builddom: function () {
// Building the text dom
}
});
function ImageBox () {}
ImageBox.prototype = Object.create(Box.prototype, {
constructor:ImageBox,
builddom: function () {
// Building the image dom
}
});
var container = {
createBox: function (type){
if (type == "text")
return new TextBox();
else if (type == "image")
return new ImageBox();
else
throw new Error();
}
};
var textbox = container.createBox('text');
console.log(
textbox instanceof Box,
textbox instanceof ImageBox,
textbox instanceof TextBox
);
textbox.builddom();
If you want use prototyping, you can smth like this:
function TextBox(props) {
this.props = props;
}
TextBox.prototype = {
builddom: function () {
// Building the text dom
console.log("TextBox", this.props);
}
}
function ImageBox(props) {
this.props = props;
}
ImageBox.prototype = {
builddom: function () {
// Building the text dom
console.log("ImageBox", this.props);
}
}
function Box (type, props) {
var handler = (type == 'text') ? TextBox :
(type == 'Image') ? ImageBox : null;
if (handler) {
handler.call(this, props);
Object.assign(this, handler.prototype);
}
}
var textbox = new Box ('text', {text: 'some'});
textbox.builddom ();
var imagebox = new Box ('Image', {x: 1, y: 2});
imagebox.builddom ();
It's not clear why you don't just use standard prototype inheritance here. It will allow you to both inherit or override methods of the parent. For example, ImageBox inherits the parent method and TextBox overrides:
/* Define Box */
function Box (type) {
this.type = type || 'box'
}
Box.prototype.builddom = function (){
console.log(this.type, ": build called")
}
/* Define TextBox */
function TextBox () {
Box.call(this, "text")
}
TextBox.prototype = Object.create(Box.prototype);
/* Override method */
TextBox.prototype.builddom = function (){
// call parent method too?
// Box.prototype.builddom.call(this)
console.log(this.type, "Text box override method")
}
/* Define ImageBox */
function ImageBox () {
Box.call(this, "image")
}
ImageBox.prototype = Object.create(Box.prototype);
var box = new Box ();
box.builddom();
var textbox = new TextBox ();
textbox.builddom();
var imageBox = new ImageBox ();
imageBox.builddom();
There is no need to create a box class if you are not going to use it, instead create a factory function and return a new instance of the respective class.
function AbstractBox() {}
AbstractBox.prototype.builddom = function() {
console.warn("unimplemented method");
};
function TextBox() {}
TextBox.prototype.builddom = function() {
console.log("TextBox.builddom called");
};
function ImageBox() {}
ImageBox.prototype.builddom = function() {
console.log("ImageBox.builddom called");
};
function ErrorBox() {}
function createBox(type) {
var handler = Object.create(({
"text": TextBox,
"Image": ImageBox
}[type] || ErrorBox).prototype);
handler.constructor.apply(handler, [].slice.call(arguments, 1));
for (var property in AbstractBox.prototype) {
var method = AbstractBox.prototype[property];
if (typeof method === "function" && !(property in handler)) handler[property] = method;
}
return handler;
}
(createBox("text")).builddom(); // Text
(createBox("Image")).builddom(); // Image
(createBox("error")).builddom(); // Error
My suggestion is to use composition/delegation rather than inheritance (has-a instead of is-a).
function TextBox () {
this.builddom = function () {
// Building the text dom
}
}
function ImageBox () {
this.builddom = function () {
// Building the image dom
}
}
function Box (type) {
var constructor =
(type == 'text') ? TextBox :
(type == 'Image') ? ImageBox : null;
var delegate = new constructor();
this.builddom = function () {
// Pre-work goes here.
delegate.builddom();
// Post-work goes here.
}
}
var textbox = new Box ('text');
textbox.builddom ();

How to write a nightwatch custom command using jquery

I have the following custom command written in javascript for nightwatch.js. How can I translate this to using jquery?
exports.command = function (classId, indexIfNotZero) {
this.browser.execute(function (classId, indexIfNotZero) {
if (classId.charAt(0) == '.') {
classId = classId.substring(1);
}
var items = document.getElementsByClassName(classId);
if (items.length) {
var item = indexIfNotZero ? items[indexIfNotZero] : items[0];
if (item) {
item.click();
return true;
}
}
return false;
//alert(rxp);
}, [classId, indexIfNotZero], function (result) {
console.info(result);
});
};
There are a few things that I see that are causing your issues.
First, you have variable shadowing that may cause issues. Your global export command has 2 variables (classId and indexIfNotZero) and your internal execute command has the same parameter names.
Second, for custom commands, the this variable is actually the browser. So instead of doing this.browser.execute, you need to just call this.execute.
As for a complete working code example, here you go:
'use strict';
var ClickElementByIndex = function(className, index) {
if (!index) {
index = 0;
}
this.execute(function(selector, i) {
var $item = $(selector + ':eq(' + i + ')');
if (!!$item) {
$item.click();
return true;
}
return false;
}, [className, index], function(result) {
console.info(result);
});
};
exports.command = ClickElementByIndex;
Note that you do need jQuery available in the global scope of your app for this to work.

Associate a string with a function name

I have a text input that I want to enable users to call functions from.
Essentially I want to tie strings to functions so that when a user types a certain 'command' prefaced with a backslash the corresponding function is called.
Right now for example's sake you can type /name, followed by a value and it will set name as a property of the user object with the value the user gives.
So how would I do this with 20 or so 'commands'?
http://jsfiddle.net/k7sHT/5/
jQuery:
$('#textCommand').on('keypress', function(e) {
if(e.keyCode==13) {
sendConsole();
}
});
var user = {};
var sendConsole = function() {
value = $('#textCommand').val();
if (value.substring(0,5) === "/name") {
user.name = value.substring(6,20);
alert(user.name);
} else {
$('body').append("<span>unknown command: "+value+"</span><br />")
$('#textCommand').val("");
}
}
HTML:
<input id="textCommand" type="text"><br/>
Store your functions in an object, so you can retrieve and call them by key:
// Store all functions here
var commands = {
name : function() {
console.log("Hello");
}
}
var sendConsole = function() {
value = $('#textCommand').val();
// Strip initial slash
if(value.substring(0,1) === '/') {
value = value.substring(1);
// If the function exists, invoke it
if(value in commands) {
commands[value](value);
}
}
}
http://jsfiddle.net/NJjNB/
Try something like this:
var userFunctions = {
run: function(input)
{
var parts = input.split(/\s+/);
var func = parts[0].substr(1);
var args = parts.slice(1);
this[func].call(this, args);
},
test: function(args)
{
alert(args.join(" "));
}
};
userFunctions.run("/test hello there"); // Alerts "hello there".
You can do:
if(window["functionName"])
{
window["functionName"](params);
}

JavaScript: Accessing Nested Objects

The code looks like this
function Scripts() {this.FindById = function (id) {
this.FindById.constructor.prototype.value = function () {
return document.getElementById(id).value;
}}}
var Control = new Scripts();
Now when i say Control.FindById("T1").value(). I am not able to get the textInput("T1")'s value.
It seems that your code is a bit more complicated then it should be ;-)
Personally I would write it this way (not tested):
function Scripts() {
this.findById = function(id) {
var el = document.getElementById(id);
return {
value: function() {
return el.value;
}
}
}
}
The findById() now closes over a node and returns an interface that can return its value.
Also, your idea sounds a lot like Singleton, so you wouldn't even need the extra Scripts constructor:
var Control = {
findById: function(id) {
var el = document.getElementById(id);
return {
value: function() {
return el.value;
}
}
}
}
Working example: http://jsfiddle.net/YYkD7/
Try this:
function Scripts() {this.FindById = function (id) {
this.FindById.constructor.prototype.value = function () {
return document.getElementById(id).value
}}}
You didn't close the last "}" :-)

Resolve function pointer in $(document).ready(function(){}); by json string name

I have a json object retrieved from server in my $(document).ready(...); that has an string that I would like to resolve to a function also defined within $(document).ready(...); so, for example:
$(document).ready(function{
$.getJSON(/*blah*/,function(data){/*more blah*/});
function doAdd(left,right) {
return left+right;
}
function doSub(left,right) {
return left-right;
}
});
with json string:
{"doAdd":{"left":10,"right":20}}
One way I thought about was creating an associative array of the function before loading the json:
var assocArray=...;
assocArray['doAdd'] = doAdd;
assocArray['doSub'] = doSub;
Using eval or window[](); are no good as the function may not be called for some time, basically I want to link/resolve but not execute yet.
Change your JSON to
{method: "doAdd", parameters : {"left":10,"right":20}}
Then do
var method = eval(json.method);
// This doesn't call it. Just gets the pointer
Or (haven't tried this)
var method = this[json.method]
How about something like this?
$(function(){
// Function to be called at later date
var ressolvedFunc = null;
// Ajax call
$.getJSON(/*blah*/,function(data){
// Generate one function from another
ressolvedFunc = (function(data) {
var innerFunc;
var left = data.left;
var right = data.right;
// Detect action
for (action in data) {
if (action == "doAdd")
innerFunc = function() {
return left + right;
};
else
innerFunc = function() {
return left - right;
};
}
return innerFunc;
})(data);
});
});
The anonymous function returns fresh function, with the new values stored within the enclosure. This should allow you to call the function at later date with the data previously retrieved from the GET request.
Rich
try this:
var doX = (function() {
var
data = [],
getDo = function(action) {
for(var d in data) {
if (data[d][action]) {
return data[d];
}
}
return null;
};
return {
set: function(sdata) {
data.push(sdata);
},
doAdd: function() {
var add = getDo("doAdd");
if (!add)
return 0;
return add.doAdd.left + add.doAdd.right;
},
doSub: function() {
var sub = getDo("doSub");
if (!sub)
return 0;
return sub.doAdd.left + sub.doAdd.right;
}
};
})();
$(document).ready(function{
$.getJSON(/*blah*/,function(data){ doX.set(data); });
});

Categories