I'm abstracting away the code to focus on the core question. I have a main.js file, which requires a second file, optionsmod.js.
I'd like to be able to send a message from optionsmod.js to main.js, so that main.js can then go on to do other things. I don't know how to do this...
Here is an example that does't work.
main.js:
var optionsmod = require("optionsmod.js");
var self = require("sdk/self");
optionsmod.init();
self.port.on("message",function(){
console.log("message received");
});
optionsmod.js:
var self = require("sdk/self");
function init(){
console.log("here in init");
//FOR THIS EXAMPLE, I'VE MADE THE CALL HERE. BUT WONT BE NORMALLY
sendMessage();
}
function sendMessage(){
self.port.emit("message");
console.log("message sent");
}
exports.init = init;
The code I've added doesn't work, but is there a way to do something similar?
There is no default way of passing messages between modules. It is quite easy to get something to happen in optionsmod.js when an event occurs in main.js. Simply export the function and call it from main.js. It isn't so straightforward the other way around, though. Two ways I handle this are by passing callback functions and creating event targets. Here's an example with a callback function:
main.js
var optionsmod = require("optionsmod.js");
var eventCallback = function(message) {
console.log('message received: '+message);
};
optionsmod.init(eventCallback);
optionsmod.js
exports.init = function(eventCallback) {
foo.on('bar', function() {
eventCallback('the message');
console.log('message sent');
});
};
The alternative is to export foo, then call foo.on from main.js, but that probably defeats the whole purpose of writing a separate module, in which case the docs I linked to will be helpful. Frankly, you could probably use those docs to create your own proprietary messaging system, but I think you're better off thinking in the above terms.
Related
I have build an angularjs application. there are many places I used javascript console functions.
now I want to use a single variable to turn off those console.
I dont want to check the variable everytime whenever I use the console function.
so I decided to make a service to handle that process.
Console factory
AppModule
.factory("$console", function (ENV) {
function log (txt) {
var args = arguments;
if(ENV.debug) {
console.log.apply(this, args);
}
}
...
...
});
And I called that function like the following way.
Controller
AppModule
.controller('CommonCtrl', function ($scope, $console
$scope.personalInfo = function () {
$scope.errmsg = false;
getPersonalInfo(function (data) {
if(!$scope.errmsg) {
$console.log("userdatainfo:",data);
}
...
...
})
});
All is working perfectly.
But Only the problem is I can only see the line number of the factory file on inspect panel.
I need to have the line number from where the factory function is getting called (like the line no of the above controller file).
Please reply with valuable suggestion.
This is a javascript feature and not specifically Angular. You can use arguments in a function like this. However the line number is not given but you get the caller name.
function Hello()
{
console.log("caller is " + arguments.callee.caller.toString());
}
I am using nodejs and webdriver for automation tests. I am trying to export a function from one js file to another. e.g there is a function called abc under file abc.js and i want to use that function with other file called xyz.js. I tried using export and require but it exports and runs entire test (abc.js) instead of just a function.
//abc.js
console.log('print this');
client= function client() {
driver.get(baseUrl + '/#/login');
};
exports.client = client;
//xyz.js
var client1 = require('abc.js').client();
Requiring a module for the first time causes the module to be cached and it's code to be executed, that's why you're seeing your "print this" log. Next time you call your client function you shouldn't see it.
This is not relevant to the question, but still, in your xyz.js file, since your function isn't returning anything you can use:
require('abc.js').client();
Instead of:
var client1 = require('abc.js').client();
In your abc.js, there's no need for a named function, you can just use:
var client = function() {
...
};
give it a try
function abc(){
console.log('print this');
this.client= function client() {
driver.get(baseUrl + '/#/login');
};
return this;
}
module.exports = abc;
//xyz.js
var abc = require('abc.js')();
abc.client();
its a good practice when capsulating objects in nodejs
I have an AfterFeatures hook that I'm using to try to gracefully shut down an expressjs web server that is used for testing only. In this hook, I need to call the visit method, which has been added to World, but I apparently don't have access to World from within this hook. What can I do to gain access to things in World inside this and other hooks?
// features/support/after_hooks.js
var myAfterHooks = function () {
this.registerHandler('AfterFeatures', function (event, callback) {
this.visit('/quit', callback);
});
};
module.exports = myAfterHooks;
I do not think you can. In the AfterFeatures the cucumber process has already finished, so this no longer references it.
But, if all you want is to visit a page, you can register your browser outside cucumber so that it is still accessible from the AfterFeatures hook. If you are using AngularJS + Protractor, Protractor handles the browser for you, and therefore it is still accessible in the AfterFeatures hook. It would be the same principle. This can be done with the following.
hooks.js
var myHooks = function () {
this.registerHandler('AfterFeatures', function (event, callback) {
console.log('----- AfterFeatures hook');
// This will not work as the World is no longer valid after the features
// outside cucumber
//this.visit('/quit', callback);
// But the browser is now handled by Protractor so you can do this
browser.get('/quit').then(callback);
});
};
module.exports = myHooks;
world.js
module.exports = function() {
this.World = function World(callback) {
this.visit = function(url) {
console.log('visit ' + url);
return browser.get(url);
};
callback();
};
}
The AfterFeatures example in the cucumber-js GitHub repository is a little misleading, as it looks like you can access the driver that you previously registered in the World. But if you are using pure cucumber-js only, I have not seen that work.
By the way, you can use just this instead of registerHandler.
this.AfterFeatures(function (event, callback) {
browser.get('/quit').then(callback);
});
Hope this helps.
I have a function which calls out for JSON and then in the success function makes some changes to the DOM. I'm trying to use the mock-ajax library in my Jasmine tests to avoid having to expose the various private functions for mocking.
Even though when stepping through the test the request.response is set the onSuccess method is never called.
My tests:
describe('the table loader', function () {
var request;
beforeEach(function() {
//html with a loader div, an output div and a transit and dwell template
setFixtures('<div class="loader"></div><div class="row"><div id="output" class="col-xs-12"></div></div><script id="thingTemplate" type="text/x-handlebars">{{snip}}</script>');
expect($('.loader')).toBeVisible();
//start ajax call
window.dashboards.thing.display({
loaderId: '.loader',
templateId: '#thingTemplate',
templateOutletId: '#output',
dataUrl: '/my/fake/url'
});
//catch the ajax request
request = mostRecentAjaxRequest();
});
describe('on success', function () {
beforeEach(function() {
//populate the response
request.response({
status: 200,
responseText: "{rowItem: [{},{},{}]}"
});
});
it('should hide the loader', function () {
//thing should now receive that JSON and act accordingly
expect($('.loader')).not.toBeVisible();
});
});
});
and my code:
(function (dashboards, $) {
dashboards.thing = dashboards.thing || {};
var compileTable = function(templateId, jsonContext) {
var source = $(templateId).html();
var template = Handlebars.compile(source);
var context = jsonContext;
return template(context);
};
var getDashboardData = function(options) {
$.getJSON(
options.dataUrl,
function (data) {
processDashboardData(options, data);
}
).fail(function (jqxhr, textStatus, error) {
console.log('error downloading dashboard data');
console.log(textStatus + ': ' + error);
}).always(function() {
console.log('complete');
});
};
var processDashboardData = function (options, data) {
$(options.loaderId).hide();
$(options.templateOutletId).html(compileTable(options.templateId, data));
};
dashboards.thing.display = function (options) {
getDashboardData(options);
};
}(
window.dashboards = window.dashboards || {},
jQuery
));
None of the deferred functions (success, error, and always) are being called.
Edit
based on #gregg's answer below (and he's right I didn't include the UseMock call in the example code) this feels like a versions issue. As even with that call included this still isn't working for me.
I've added a runnable example on github
You need to make sure to install the ajax mock with jasmine.Ajax.useMock() before you actually make the call or jasmine-ajax won't have taken over the XHR object and you'll be making real requests. Once I did that against your sample code, it looks like the responseText you're sending isn't JSON parsable and jQuery blows up. But I was still seeing the 'complete' message logged in my console.
So, as of 29th Jan 2014, the download link in the Readme for mock-ajax on Github in the 1.3.1 tag doesn't point to the correct version of the file.
Manually downloading the mock-ajax file from the lib folder of the tag does work.
In other words for the 1.3.1 tagged release don't download from the readme link download from the tag lib folder directly
It's possible that the format of the data returned by your ajax call and jasmine's is different -- I believe that would throw an exception that wouldn't be recoverable, hence the reason none of your callback functions are running.
Newer versions of jasmine-ajax also use request.respondWith, and it's also of note (although I think jQuery handles this), that Jasmine doesn't have XMLHttpRequest.Done defined, so if you use vanilla JS you have to handle this case yourself. Lastly I use jasmine.Ajax.install() and not jasmine.Ajax.useMock().
Whew -- it's hard to know what exactly to do because Jasmine has such poor documentation for older versions and there are so many inconsistencies across them.
This is a bit of a tricky question.
I am very familiar with javascript, however I am on a project that auto-crawls a website using PhantomJS and CasperJS. These are entirely new subjects to me.
I was able to figure out how to use Casper and navigate, log in to pages, etc, however it is unweildy as the general flow seems to be:
casper.start('http://google.fr/');
casper.then(function() {
this.echo("I'm in your google.");
});
casper.then(function() {
this.echo('Now, let me write something');
});
casper.then(function() {
this.echo('Oh well.');
});
casper.run();
My problem with this is that I want to do all sorts of things with the website, depending on what data is gotten with it. I can't pre-layout the sequence of navigations and not have it change. I hope this makes sense.
To solve this, I created a Javascript Navigator object with builtin functions. My general concept was:
navigator.logIn(function()
{
navigator.actionA(parameters, function()
{
if (navigator.data.a == navigator.data.b) {
navigator.actionB();
} else {
navigator.actionC();
}
});
});
And embedded in each of these functions would be casper functions.
Here is a shortened version of my actual code, and where things started getting funky:
var casper = require('casper').create({
clientScripts: [ 'jquery.min.js' ],
onError: function(self, m) {
console.log('FATAL:' + m);
self.exit();
},
});
var navigator = new _Navigator();
function _Navigator() { }
_Navigator.prototype.logIn = function(aCallback)
{
var self = this;
casper.start('https://website/login.asp', function()
{
if (1 == 1) {
this.evaluate(function() {
$("input[name=blah]").val('blahblah');
});
// ... A LOT MORE CODE
aCallback();
}
});
}
_Navigator.prototype.search = function(aDataSet, aCallback)
{
var self = this;
console.log('this works');
casper.then(function(){
console.log('this works');
});
var firstName = 'foobar';
casper.then(function(){
console.log('this works');
this.evaluate(function()
{
console.log('this no longer works!!');
$('input[id=blah]').val(firstName);
aCallback();
});
});
}
navigator.logIn(function() {
// LOG IN RUNS, AND CALLS BACK SUCCESSFULLY...
navigator.search({'dataset'}, function()
{
console.log('This never runs');
});
});
casper.run();
You'll notice that in the navigator.login function, I call casper.start(); In this, the evaluation function works fine, however then I do a callback function within that casper.start(); In my callback, I call the next function, navigator.search, which I suppose is still technically executing in the casper.start?
When I try running casper.evaluate within this new function called by the first callback function, everything seems to behave fine with the exception that casper.evaluate no longer works! It seems to eat the function, not printing any console logs or anything.
I have tried everything on this. I am not sure how to do this correctly. Does anyone have any suggestions on what I am doing wrong? Thanks.
I know this is quite old, but: What's going on here is a combination of two issues:
casper.evaluate() seems to eat all errors within the current stack - onError won't run from inside an .evaluate() callback.
Functions used in .evaluate are not standard closures - they're sandboxed, and have no access to variables outside their scope, unless passed as explicit arguments to casper.evaluate. So in the evaluated function where you call aCallback() there's no aCallback in scope, and the function will fail (silently) with a ReferenceError.
casper.evaluate() is as a window onto the headless browser session.
Anything that happens in functions passed to evaluate doesn't appear on your local console.
However, you can either log any value returned from evaluate or print all output by setting up a listener:
casper.on('remote.message', function(message) {
console.log(message);
});