"ReferenceError: Can't find variable: Mustache" in Unit Tests? - javascript

im running a rails app which im running Unit tests on the Javascript side (Using Teaspoon/Jasmine).
the funny thing is, on the function I call I KNOW Mustache.render function is working (Im able to console.log it's return value (which is the Mustache.render function) and see that it is working. However when I call that function from my unit tests im getting a:
Failure/Error: ReferenceError: Can't find variable: Mustache.
For reference I don't actually call the Mustache render function directly im simply calling the function that uses it and grabbing it's return value to check again.
I've been able to successfully grab and use various other functions and use them just fine, this one is just giving me trouble. Can the Mustache.render object not exist outside it's own file or scope or something?
Edit: Example code:
_makeSomething: function viewMakeSomething(data) {
const template = templates.something;
return Mustache.render(document.querySelector(template).innerHTML, data);
}
and my test code is simply:
it('_makeSomething object', function() {
let obj = {id: 1234, content: "_makeSomething Assertion", author: "Test User"}
let $something = _makeSomething(obj);
});
(Right now im just capturing it before I assert anything or split it up/etc...., but it's just calling it at all)

Problem is that you teaspoon doesn't have access to your dev/production assets pipelene. You should specify what JS to load for your tests. This is necessary to prevent loading all files from manifest to test some feature. Because this is unit testing.
From example:
//= require mustache
describe("My great feature", function() {
it("will change the world", function() {
expect(true).toBe(true);
expect(Mustache).toBeDefined();
});
});

Related

Protractor is not able to find a function from JS file

I created a function which return the new Browser object from the JS function browser.forkNewDriverInstance() and i created a global variable in my config file and i'm calling a function from that file by using this global variable. but here when i'm calling that function it is throwing error like utility.openNewBrowser is not a function error.
Config File:
onPrepare: function () {
global.utility=require("../src/test/resources/com.learnFramework.utility/timeOutConfig.js");
}
Cucumber Opts functions
cucumberOpts: {
//i'm using the same file for setting up the timeout.. is this creating the issue??
require:['../src/test/resources/com.learnFramework.utility/timeOutConfig.js'],
tags: false,
profile: false,
format:'json:../Reports/jsonResult/results.json',
'no-source': true
}
Function
var configure = function () {
this.setDefaultTimeout(100 * 1000);
this.openNewBrowser=function(){
return browser.forkNewDriverInstance(true);
}
};
module.exports = configure;
Error Log
TypeError: utility.openNewBrowser is not a function
When i called the forkNewBrowserInstance method directly i'm getting the below error.
both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details
can some help me to resolve this issue.. i got this error because the first browser ignoring synchronization but second browser how can i ignore the synchronization?
What you did above is the correct way of defining a global variable. But I think the global variable name should be configure instead of utility that is why it is throwing the TypeError.
And wherever you want to call it, use that variable name as is. This is actually how protractor, browser and other built-in global variables were made available globally. The following posting was helpful and also the protractor doc where it's explaining the property: params?: any;
Hope this helps, please let me know.
I faced the same issue but with jasmine.
so i had done the following workaround and issue was resolved.
class abc{
constructor() {
var configure = function () {
this.setDefaultTimeout(100 * 1000);
this.openNewBrowser=function(){
return browser.forkNewDriverInstance(true);
}
};
}
}
module.exports = new abc();

Refactoring a path in JS cannot find module

Hi working on a project at the moment and currently getting it to call the api, great! however I'm looking at refactoring my test files as there will be quite a few so initially this is how I've done it.
var chakram = require('chakram');
expect = chakram.expect;
var baseFixture = require('../../test/fixtures/');
it("Should return the matching test file", function () {
var response = chakram.get("http://testurl");
return expect(response).to.have.json(baseFixture + 'testfile.json')
});
However with the code above I'm getting this error.
Error: Cannot find module '../../../../test/fixtures'
If I put the json file into the variable at declared at the top with a call to base fixture within the function the test will pass.
Where am I going wrong?
Thanks in advance.

Wrapping `console.log` and retaining call stack

In my logging helper class, I have the following:
this.myInfo = console.info.bind(console);
When I call my myInfo function from elsewhere, the calling object and line number are correctly retained and logged in the Chrome devtools.
When I run myInfo though, I also want to run another local function in addition to the console.info. Hence, I figured I could just wrap the above and it would work. I've come up with the following:
var obj = this;
this.myInfo = (function() {
console.info.apply(this, arguments);
myOtherFunc.apply(obj, arguments);
}).bind(console);
The problem is that unlike my first example, I lose the calling context for console.info, and the wrong line number and file are logged in the devTools.
How can I wrap the first example and retain the proper context for the console.info?
You can use getter. In getter you call your other function and then return console.info.bind(console) to caller.
Object.defineProperty(this, "myInfo", { get: function () {
myOtherFunc();
return console.info.bind(console);
}});
In case of passing arguments. You can define following function:
this.myInfo = function()
{
myOtherFunc.apply(null, arguments);
return console.bind.apply(console, arguments);
}
// example of call
this.myInfo(1,2,3)();
I've new solution. You can implement your console.log wrapper in separate JS file or evaluate it with sourceURL then go to Chrome DevTools settings and add "console-wrapper.js" url to blackbox pattern or blackbox this script by link when first message is arrived to console.
When script become blackboxed then all messages will have correct location in source code.
It works in last Google Chrome Canary build and will be available in stable in around two months.
eval("\
function myAwesomeConsoleLogWrapper() {\
console.log.call(console, arguments);\
makeAnotherWork();\
}\
//# sourceURL=console-wrapper.js");
Alexey Kozyatinskiy's approach is cool. However, if not-pretty code like this.myInfo(1,2,3)() is a more serious problem than ugly console output, you could use the wrapper you posted in your question and print needed filename and line number manually having it extracted from new Error().stack. I'd personnaly use Alexey's method unless there was a team working on this project.

Front end javascript testing using Require and Resharper

So I've been trying to figure out how front end testing works (unit testing) but I am getting stuck on some point.
So I have my jasmine test set up as follows:
describe('Blabla', function () {
it('returns true', function () {
var people = require(["people"], function(ppl) {
return ppl;
});
expect(people.getTitle()).toBe('People piolmjage');
});
});
But running this gets me:
TypeError: undefined is not a funtion
So obviously, people is undefined. So perhaps my callback comes in too late. But if I remove the callback I get following error:
it('returns true', function () {
var people = require("people");
expect(people.getTitle()).toBe('People piolmjage');
});
Error: Module name "people" has not been loaded yet for context: _. Use require([])
I figure there is something wrong in my setup...Anyone have any idea how to get this FE testing to work?
I did manage to get it to work from console and using define combined with phantomjs and the durandal test files but I need this to work outside of the console and hereby I cannot use this define because the test runner won't find my tests.
That's why I need to use the CommonJS was of getting the required viewmodels.
people model
define([],
function () {
var getTitle = function() {
return "hello";
}
var peopleViewModel = {
title: 'People page',
getTitle: getTitle
};
return peopleViewModel;
});
UPDATE
I got the code working but not with resharper. Following this page from the durandal webpage.
But this gets me console output which is way to unstructured to actually read through.
I can however use the define keyword and then it works fine. So I assume it is the require keyword where I mess up something?
UPDATE 2
So I used fiddler to check what is going on. I also finally got it working (kinda...).
My testfile looks like this now:
///<reference path="../../Scripts/require.js"/>
///<reference path="../../test/lib/jasmine-2.1.3/jasmine.js"/>
///<reference path="../../App/viewmodels/people.js"/>
describe('Blabla', function () {
it('require test', function (done) {
require(['people'], function (people) {
expect(people.title).toBe('People page');
done();
});
});
});
And then I changed my people file:
define("people", ["bla"], function (bla) {
return {
title: 'People page',
bla: bla
};
});
As you can see here, I name my viewmodel to be people.
This works for the testrunner but he doesn't actually get any files through requireJS but only the reference paths. Also this does not fit my needs because the durandal models are unnamed.
Fiddler screenshot:
So basically he does not use requireJS to get the viewmodels and therefor I cannot just use the require.config initializer to get to my viewmodels folder and download every viewmodel using requireJS. Any thoughts?
I finally got it working, took me like a day and a half.
Anyway I don't use resharper anymore, or it's test runner to be more precise.
Chutzpah is the one I turned to in the end. This too took me some research but I got it to the point where it includes everything as I want it to.
Check this post for sure
Here is what I did:
My people.js looks like this:
define(['viewmodels/bla'], function (bla) {
return {
title: 'People page',
bla: bla //testing dependencies on other viewmodels
};
});
Then I also made a bla.js
define(function() {
return {
bla: "bla"
};
});
And now for the tests:
describe('Blabla', function () {
it('require test', function (done) {
require(['viewmodels/people'], function (people) {
expect(people.title).toBe('People page');
done();
});
});
it('dependency on require test', function (done) {
require(['viewmodels/people'], function (people) {
console.log(people.bla);
expect(people.bla.bla).toBe('bla');
done();
});
});
});
And then eventually, reading the answers on the link provided on top I had to create a Chutzpah config file to create a test harnass:
{
"Framework": "jasmine",
"TestHarnessReferenceMode": "AMD",
"TestHarnessLocationMode": "SettingsFileAdjacent",
"References" : [
{"Path" : "../Scripts/require.js" },
{"Path" : "requireConfig.js" }
],
"Tests" : [
{"Path": "specs"}
]
}
Now, running the tests with Visual studio test runner actually gets me everything I need and as you can see, I can now access all my viewmodels through require like so: require(['viewmodels/whateverviewmodel'], function(whateverviewmodel){....})
I hope this answer can get people on their way to testing your (Durandal)SPA using Jasmine and RequireJS.
I know my viewmodels in this answer, nor in the question itself, say much but this should get you an idea of how to go about all of this.
Small Edit
You can now also skip the callback mess with require([]... inside of the tests and build your tests like you do your viewmodels with define
define(['viewmodels/people'], function (people) {
describe('Blabla', function () {
it('require test', function () {
expect(people.title).toBe('People page');
});
it('dependency on require test', function () {
console.log(people.bla);
expect(people.bla.bla).toBe('bla');
});
});
});
This gets you less indents and is more readable in itself.
The require call provided by RequireJS is inherently asynchronous so you need to do something like this:
it('returns true', function (done) {
require(["people"], function(people) {
expect(people.getTitle()).toBe('People piolmjage');
done(); // Signal that the test is done.
});
});
The first attempt you show in your question cannot work. That's the classical "trying to return values synchronously form asynchronous code" mistake. The second attempt with require("people") does not work either because this require call is pseudo-synchronous and will work only if the module requested is already loaded. See this answer for an explanation of how this pseudo-synchronous require works.

QUnit multiple scripts in one page but no interaction between them

I'm very new to unit testing (this is my first day working with QUnit and I've never worked with anything other testng system before), and I'm a bit unclear on how to test stuff from multiple script files in one QUnit page without letting the scripts interact with each other. What I mean is, say, if I have script1.js, and it calls hello(), and hello() is defined in script2.js, how can I run a unit test on script1.js to make sure it calls hello(), but mock the output of hello() so that it's a true unit test, and then run script2.js's hello().
Basically, how am I supposed to hide one script's global variables and functions from another script in a single QUnit page?
This depends entirely on how the various script files are organized as well as the system as a whole. If you were using Angular, for example, then you are able to inject dependencies when you include a module in another script file. There are tools for mocking out things and "spying" on function calls such as Sinon, but it still depends heavily on how your code is organized.
For the sake of argument, let's say the two files look like so, and we'll ignore the design pattern (although you should seriously be considering that)...
// File A:
window.greeting = function() {
var world = hello();
return 'hello ' + world;
}
// File B:
window.hello = function() {
// possibly lots of code to determine what to return...
var value = 'foobar';
return value;
}
The hello() function could just as easily return any other value based on the state of the system, user input, etc. For our case it doesn't, and what we want to do is mock out File B's code so that we don't have to test what it is doing, just that it gives back a string. We could (and should) do this with a proper mocking/dependency injection library. However, just to give you a sense of the minimal setup you could do, and to see the general approach, here's our QUnit test file:
var _hello;
QUnit.module('File A', {
setup: function() {
_hello = window.hello; // hold onto the old value
// now we mock out hello()
window.hello = function() {
window.hello.called++; // track calls to it
return 'world'; // return our static value
}
window.hello.called = 0;
},
teardown: function() {
// put the old one back
window.hello = _hello || window.hello;
}
});
QUnit.test('Ensure greeting is correct', function(assert) {
var result = greeting();
assert.equal(window.hello.called, 1, 'hello should be called only once');
assert.equal(result, 'hello world', 'The greeting call should be "hello world"');
});
And if you want to see it running, here is a jsfiddle for you. As I said, this is a simple example to show you how you could do this, but you should look into proper code organization (think AMD modules, require, Angular, Ember, things like this) and a proper mocking library.

Categories