Run jsTestDriver in WebStorm for Jasmine + Backbone - javascript

I am writing tests in Jasmine for a Backbone application and I want to know what proportion of the code my tests cover. For this goal I want to use jsTestDriver. But I have a problem: I created a config file and added all resources there, but when I start test Backbone methods don't define. This is my config file:
server: http://localhost:9876
load:
- lib/jasmine-1.3.1/jasmine.js
- lib/jasmine-jquery.js
- lib/JasmineAdapter.js
- lib/sinon-1.5.2.js
- cordova-2.2.0.js
- libs/jquery-1.8.2.min.js
- libs/underscore-min.js
- libs/backbone-min.js
- libs/lazyload-min.js
- core/js/core.js
- index.js
test:
- spec/test.js
The order is the same as on SpecRunner file. It is my test file:
describe("Attributes", function(){
it("Test", function() {
c = new Cars;
expect(c.attributes.StartDate).toBeDefined();
expect(c.attributes.StartDate).toBeDefined();
})
});
Cars is a Backbone model and this model has default attribute StartSate. In my test I want check that this attribute defined. And ofcourse the mistake in WebStorm:
TypeError: TypeError: Cannot read property 'attributes' of undefined
TypeError: Cannot read property 'attributes' of undefined
at null.<anonymous> (spec/test.js:10:21)

I think it's better to use the has method of the model object to check for an attribute, rather than checking the attributes property:
describe("Attributes", function(){
it("Test", function() {
c = new Cars;
expect(c.has("StartDate")).toBe(true);
})
});
This way you can add some implicit logic to the model that can override the has method. Also, you didn't specify how you extended the model to create your Cars class. Have you specified default values?

Related

Why does putting Backbone and Handlebar's context into initialize function remove error?

I'm pretty sure this is a general JS question and not just limited to Backbone but I encountered this as I was learning Backbone. In the first example below, I don't get an error but that's not the same for the 2nd example. Can you explain what is going on behind the scenes that makes Chrome Dev Tools show the error in the latter example but not the first. My best guess is that when something is in a function (such as initialize), it doesn't get run right away as the browser is reading the script whereas if it's part of the class being defined (in this case, app.ItemView), the object context needs to be completed so the browser will need to read through this.model#get in order to build the context object.
app.ItemView = Backbone.View.extend({
initialize: function() {
this.context = {
title: this.model.get("title"),
completed: this.model.get("completed")
}
}
});
vs.
app.ItemView = Backbone.View.extend({
context: {
title: this.model.get("title"),
completed: this.model.get("completed")
}
});
Uncaught TypeError: Cannot read property 'get' of undefined
edit: it also doesn't work if the context in the first example isn't being defined appropriately -
app.ItemView = Backbone.View.extend({
initialize: function() {
this.context.title = this.model.get("title");
this.context.completed = this.model.get("completed");
this.render();
}
});
Uncaught TypeError: Cannot read property 'get' of undefined
EDIT Corrected explanation of this after reading mu is too short's comment.
The main reason for the error is that this in your second piece of code could refer to window or the caller of a function where Backbone.View.extend is being called.
That object doesn't have a model property, so it's undefined and calling get on undefined results in the error.
You need to make initialize a function because it will presumably be called by a Backbone.View object, which does have the model property available to it. In that context, this would refer to the Backbone.View object.

CKEditor + Protractor: Testing with Protractor can't find CKEditor instance

I am using Protractor for a non-Angular page and wanting to find the CKEditor instance on the page to then set data for. I can do this in Chrome console via:
CKEDITOR.instances.html_editor.setData("Hello")
In my test for the page, I have the code below:
it('should enter text in editor successfully', function() {
var composerPage = new ComposerPage();
browser.executeScript('return window.CKEDITOR');
window.CKEDITOR.instances.html_editor.setData( 'Hello' );
});
However, the error returned is:
Error: Failed: Cannot read property 'instances' of undefined
I've already had a look at this Stack Overflow question here: Protractor: How to access global variables that we have inside our application? but didn't really help get me unstuck.
Any suggestions as to how I can define the CKEditor instance and set data would be helpful!
Use browser.executeScript() to set the editor's data:
var value = 'Hello';
browser.executeScript(function (arguments) {
window.CKEDITOR.instances.html_editor.setData(arguments[0]);
}, value);

Meteor.js and Showdown extensions - how to add table extension to the renderer/convertor?

I have been fiddling for ages with custom handlebars helpers such as:
Handlebars.registerHelper('markdowner', function (input) {
var converter = new Showdown.converter({ extensions: 'tables' });
return converter.makeHtml(input);
});
yet i get thrown:
Uncaught TypeError: Cannot call method 'replace' of undefined
from showdown.js when trying to call the helper.
I have also tried redefining the converter when Meteor loads, but it is ignored - any ideas on how to get showdown convertors/extensions running would be greatly appreciated.
You need to provide the extensions as an array and also you need to refer to that extension as 'table' rather than 'tables' (based on the table.js file within the Showdown gitgub repository as below).
var converter = new Showdown.converter({ extensions: ['table'] });
I've just implemented this myself after having the same error you had.
When the extension is loaded you should be able to run this from the console and have it return something.
$ window.Showdown.extensions.table
To test it's working from the console try this:
new Showdown.converter({extensions:['table']}).makeHtml("| A | B | C | \n |-|-|").htmlSafe()
should output
SafeString {string: "<table>↵<thead>↵<tr>↵<th id="a" style="text-align:…C </th>↵</tr>↵</thead>↵↵<tbody>↵</tbody>↵</table>", toString: function}
References
table.js - https://raw.githubusercontent.com/coreyti/showdown/master/src/extensions/table.js
I found the array reference here: http://www.sluse.com/view/20863978

Durandal TodoMVC - Cannot write a value to a ko.computed

I'm trying to build a version of the todo app using Durandal (including Knockout + RequireJS) from a TodoMVC template. I realize that a todo app doesn't really show off the features of Durandal, but I'm on the learning path and figured it would be a good first project.
Anyway, in the process I've stumbled upon an error that I'm unable to solve (see below).
Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.")
I've also attached an image that shows these in the console.
You can find the source code at https://github.com/robksawyer/durandal-todo. The todo viewmodel is located at https://github.com/robksawyer/durandal-todo/blob/master/viewmodels/todos.js.
Update: Most of the Knockout code is borrowed from the Knockout+Require TodoMVC project at https://github.com/tastejs/todomvc/tree/gh-pages/labs/dependency-examples/knockoutjs_require/
Thanks for your time.
I think you're misreading the console.
For example, "allCompleted" is a property on your view model, which is declared as a dependent observable (i.e. a "computed"):
// writeable computed observable to handle marking all complete/incomplete
self.allCompleted = ko.computed({
// -- trimmed --
});
What you're seeing in the console isn't the Cannot write a value error; it's the debug output for a computed property - i.e. its function definition. For reference, here's the function definition of a dependent observable straight from the knockout (2.2.1) source:
function dependentObservable() {
if (arguments.length > 0) {
if (typeof writeFunction === "function") {
// Writing a value
writeFunction.apply(evaluatorFunctionTarget, arguments);
} else {
throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
}
return this; // Permits chained assignments
} else {
// Reading the value
if (!_hasBeenEvaluated)
evaluateImmediate();
ko.dependencyDetection.registerDependency(dependentObservable);
return _latestValue;
}
}
What you're seeing in your console is the minified version of this code.
If you want to see the value that's returned by the property you'd have to invoke it.

ExtJS 4 Object.prototype fail

have a bit problem to use prototype while using framework ExtJS version 4.1.1.
At first I made my prototypings before I load ExtJS.
On "Array.prototype.xyz" and "String.prototype.xyz" all work fine.
Bot on "Object.prototype.xyz" there is a bad behavior in mixin inclusion of ExtJS.
Example my test code:
Object.prototype.doSomething = function() {
console.log('I do it!');
}
var a = {};
a.doSomething();
Error message from ExtJS:
Uncaught TypeError: Cannot read property '$childEls' of undefined
And break.
And:
- Yes. Without "Uncaught TypeError: Cannot read property '$childEls' of undefined" it work
fine.
- No. I use not oter mixins currently.
- Yes. I try to use only one dummy panel Component.
Question: Is there a simple solution to prototype on Object class-object?
The problem stems from one of the fundamental methods of the Ext JS library: Ext.merge
Proving this is very simple:
Object.prototype.doSomething = function(){ console.log("Does something"); };
var emptyObj = {};
console.log(emptyObj.hasOwnProperty("doSomething")); // Prints "false"
var mergeObj = Ext.merge({}, {a: "b"});
console.log(mergeObj.hasOwnProperty("doSomething")); // Prints "true"
Basically, every time Ext.merge (or Ext.apply) is called with an object literal your prototype method is "promoted" up the prototype chain. When you go to create a panel (or any component, really) the class mixin object is merged with its prototype's mixin object. Since a mixin is defined as an object literal in the class definition, your "doSomething" method is promoted.
Then in Ext.util.ElementContainer#getClassChildEls, the mixin object is iterated over assuming each property is an existing class and tries to access mixins[name].self.$childEls (where mixins[name] is your "doSomething" method). Your method doesn't have a self property so accessing $childEls throws the error.
If you need an object available on every object, write it as a static method like Object.doSomething or even Ext.Object.doSomething.

Categories