I have hit a problem that seems like it might be some sort of bug in the Nashorn engine, but I can't figure out a good way to distill a test case that will demonstrate it.
I have a block of code (that used to work!) which looks roughly like this:
'use strict';
function Dummy() {
this.val = 'I am fubar';
this.aContainer = [];
}
Dummy.prototype.toString = function() { return JSON.stringify(this);};
let obj = {};
obj.aMethod = function(arg) {
let fubar = new Dummy();
print('Okay so far');
fubar.aContainer.push({"some":"thing"});
print('Still okay');
fubar.aContainer.push({"==": [{"var": "something_else"}, fubar.val]});
return fubar;
};
print(obj.aMethod(null));
Unfortunately, running this example with jss --language=es6 -strict doesn't crash. In my real code though, I get the following:
jdk.nashorn.internal.runtime.ECMAException: ReferenceError: "fubar" is not defined
If I change the code as follows, it runs fine:
'use strict';
function Dummy() {
this.val = 'I am fubar';
this.aContainer = [];
}
Dummy.prototype.toString = function() { return JSON.stringify(this);};
let obj = {};
obj.aMethod = function(arg) {
let fubar = new Dummy();
print('Okay so far');
fubar.aContainer.push({"some":"thing"});
print('Still okay');
let x = fubar.val;
fubar.aContainer.push({"==": [{"var": "something_else"}, x]});
return fubar;
};
print(obj.aMethod(null));
Is there anything I can do to try to instrument the real code further or otherwise track this issue down? The odd thing is the error happens very early in execution. If I put a print() call anywhere in the method, the print is never reached. The last line of my code in the callstack is actually the line that calls the method.
I did just pick up a new version of Java via auto-update, but I need to see if this code is running under it or not. My current version from the console is:
➜ ~ java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
A full summary of all you can do to trace Nashorn is contained in this document:
jdk8u-dev/nashorn/file/tip/docs/DEVELOPER_README
It describes system properties that are used for internal debugging and instrumentation purposes, along with the system loggers, which are used for the same thing.
Related
I am trying to create a library for a project, its like this:
module.exports = Diary;
function Diary() {
someFunction = function( message ) {
console.log(message)
}
function D() {
return new D._Section;
}
D.about = {
version: 1.0
};
D.toString = function () {
return "Diary "+ D.about.version;
};
var Section = function () {
this.Pages = []
}
D._Section = Section;
//to extend the library for plugins usage
D.fn = sectionproto = Section.prototype = D.prototype;
sectionproto.addPage = function (data) {
this.Pages.push(data)
conole.log(this.Pages)
};
return D;
};
main purpose for this is to use same library for server side and client side operations, so we can have same code base.
this issue is that when i use this in node app
var Diary = require('./diary.js');
var myDiary = new Diary();
console.log(myDiary.addPage('some text on page'))
and run it, it throws an error
TypeError: myDiary.addPage is not a function
i am not not sure what to do here to make this work for node js, as our client app is very huge and making changes to it would require some effort if we have to go in some other pattern.
First Question is:
1. is this approach right or we need to look in to something else
2. if this can work on node js app then how with minimum changes to library
The main problem is that you're exporting your overall Diary function, but then using it as though you'd received its return value (the D function) instead.
The way you're exporting it, you'd use it like this:
var Diary = require('./diary.js')();
// Note -------------------------^^
var myDiary = new Diary();
But beware that that means every import will create its own D function and associated things.
Alternately, export the result of calling Diary, but then the Diary function has no purpose.
Other issues are:
You're falling prey to The Horror of Implicit Globals* by not declaring someFunction or sectionproto. Be sure to declare your variables.
The structure is over-complicated without any obvious reason it needs to be so complicated.
* (disclosure: that's a post on my anemic little blog)
I have following code in a file named index.js. I want to test some functions in it add, print being the prime one.
(function($){
"use strict";
$(function(){
var add = function(a, b){
// ...
},
print = function(str){
// ...
},
setup = function(){
// ...
},
init = function(){
// ...
};
setup();
init();
});
})(jQuery);
How can I do so?
Does this way of coding add any security on client side? All I have is code that runs on the client side. No server involvement what-so-ever.
I tried :
var outerObj = (function(greet){
var innerObj = (function(){
return {test: function(){ console.log(greet); }}
})();
return innerObj;
})("hi");
outerObj.test();
but, in my case, innerObj line has a $ on the right hand of equal sign, making console yell error that shouts $(...) is not a function.
Which I agree, it's an array of single document object.
Check out var a = (function(){ var val = $(function(){return 10;})(); })(); in any jquery enabled web-page's console, for the error.
Even if I ditch outer shell and bring $(function() {}); out. How am I gonna test that?
It's still an object, still an error.
What kind of testing can I perform, unit, bdd, etc. and how?
I don't quite see what pattern you're using here - it seems like a bit of an anti-pattern. It's not testable, and doesn't expose any behaviour for real world use. I'd highly recommend reading (or at least skimming) Javascript Design Patterns by Addy Osmani, available for free.
For Unit Testing, I've always found a happy midpoint between the simple constructor pattern and revealing module pattern easiest to work with.
var x = function($){
"use strict";
var add = function(a, b){
alert('add');
},
print = function(str){
return 1;
},
setup = function(){
alert('setup');
},
init = function(){
alert('init');
};
init();
setup();
return {
add: add,
print: print
};
};
var y = new x(jQuery);
In the above example, y will have the add and print methods available. Check out a sample test on this fiddle.
As a side note, I've recently been using the excellent QUnit framework for setting up and running my JS Unit Tests. It's by the jQuery Team, so you know it's gonna be good ;).
I'd also suggest checking out BlanketJS for reporting on coverage, and qunit-parameterize for setting up multiple test cases.
For what its worth, BDD isn't a 'test type', but a way of working. For what tests you should have - Unit Tests and Integration Tests are the most important 2, IMO. I use QUnit for Unit Tests, and Selenium with NUnit for Integration Testing.
Problem:
The GhostDriver API does not yet support alert handling. There is an acceptable workaround for the time being, which is to inject your own javascript into the page that will handle the alert and store it's text for you.
I'm having trouble using this workaround via the python webdriver bindings. It might be related to my novice level understanding of javascript.
Here is an example of the workaround I am trying to utilize:
https://github.com/detro/ghostdriver/issues/20#issuecomment-15641983
I'm using a public site that demonstrates an alert to make this more straightforward: http://www.tizag.com/javascriptT/javascriptalert.php
Here is my code:
from selenium import webdriver
button_xpath = "/html/body/table[3]/tbody/tr/td[2]/table/tbody/tr/td/div[4]/form/input"
js = """
(function () {
var lastAlert = undefined;
window.alert = function (message) {
lastAlert = message;
};
window.getLastAlert = function () {
var result = lastAlert;
lastAlert = undefined;
return result;
};
}());
"""
driver = webdriver.PhantomJS()
driver.get('http://www.tizag.com/javascriptT/javascriptalert.php')
driver.execute_script("window.alert = %s" % js)
driver.find_element_by_xpath(button_xpath).click()
#exception just occured
driver.execute_script("return window.getLastAlert && window.getLastAlert();")
The exception is:
WebDriverException: Message: u'Error Message => \'Click failed: TypeError: \'undefined\' is not a function (evaluating \'alert(\'Are you sure you want to give us the deed to your house?\')\')\'\n caused by Request => {"headers":{"Accept":"application/json","Accept-Encoding":"identity","Connection":"close","Content-Length":"81","Content-Type":"application/json;charset=UTF-8","Host":"127.0.0.1:41752","User-Agent":"Python-urllib/2.7"},"httpVersion":"1.1","method":"POST","post":"{\\"sessionId\\": \\"0eaf7680-9897-11e2-b375-55b9cb6ceb0f\\", \\"id\\": \\":wdc:1364578560610\\"}","url":"/click","urlParsed":{"anchor":"","query":"","file":"click","directory":"/","path":"/click","relative":"/click","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/click","queryKey":{},"chunks":["click"]},"urlOriginal":"/session/0eaf7680-9897-11e2-b375-55b9cb6ceb0f/element/%3Awdc%3A1364578560610/click"}' ; Screenshot: available via screen
I'm a JS noob. I'm hoping somebody can point me in the right direction.
A simple solution is to rewrite the window.alert method to output the argument to a global variable.
Define the js injection variable with your override function:
js = """
window.alert = function(message) {
lastAlert = message;
}
"""
And then just pass the js variable through the execute_script call in python like this:
driver.execute_script("%s" % js)
Then when it's all been run you can execute a return on the global lastAlert:
driver.execute_script("return lastAlert")
This is some workaround.
Use this for every reloaded page that would have an alert later.
driver.execute_script("window.confirm = function(){return true;}");
This works for PhantomJS within Selenium/Splinter.
See more reference here.
I've got a browser addon I've been maintaining for 5 years, and I'd like to share some common code between the Firefox and Chrome versions.
I decided to go with the Javascript Module Pattern, and I'm running into a problem with, for example, loading browser-specific preferences, saving data, and other browser-dependent stuff.
What I'd like to do is have the shared code reference virtual, overrideable methods that could be implemented in the derived, browser-specific submodules.
Here's a quick example of what I've got so far, that I've tried in the Firebug console, using the Tight Augmentation method from the article I referenced:
var core = (function(core)
{
// PRIVATE METHODS
var over = function(){ return "core"; };
var foo = function() {
console.log(over());
};
// PUBLIC METHODS
core.over = over;
core.foo = foo;
return core;
}(core = core || {}));
var ff_specific = (function(base)
{
var old_over = base.over;
base.over = function() { return "ff_specific"; };
return base;
}(core));
core.foo();
ff_specific.foo();
Unfortunately, both calls to foo() seem to print "core", so I think I've got a fundamental misunderstanding of something.
Essentially, I'm wanting to be able to call:
get_preference(key)
set_preference(key, value)
load_data(key)
save_data(key, value)
and have each browser do their own thing. Is this possible? Is there a better way to do it?
In javascript functions have "lexical scope". This means that functions create their environment - scope when they are defined, not when they are executed. That's why you can't substitute "over" function later:
var over = function(){ return "core"; };
var foo = function() {
console.log(over());
};
//this closure over "over" function cannot be changed later
Furthermore you are "saying" that "over" should be private method of "core" and "ff_specific" should somehow extend "core" and change it (in this case the private method which is not intended to be overridden by design)
you never override your call to foo in the ff_specific code, and it refers directly to the private function over() (which never gets overridden), not to the function core.over() (which does).
The way to solve it based on your use case is to change the call to over() to be a call to core.over().
That said, you're really confusing yourself by reusing the names of things so much, imo. Maybe that's just for the example code. I'm also not convinced that you need to pass in core to the base function (just to the children).
Thanks for your help. I'd forgotten I couldn't reassign closures after they were defined. I did figure out a solution.
Part of the problem was just blindly following the example code from the article, which meant that the anonymous function to build the module was being called immediately (the reusing of names Paul mentioned). Not being able to reassign closures, even ones that I specifically made public, meant I couldn't even later pass it an object that would have its own methods, then check for them.
Here's what I wound up doing, and appears to work very well:
var ff_prefs = (function(ff_prefs)
{
ff_prefs.foo = function() { return "ff_prefs browser specific"; };
return ff_prefs;
}({}));
var chrome_prefs = (function(chrome_prefs)
{
chrome_prefs.foo = function() { return "chrome_prefs browser specific"; };
return chrome_prefs;
}({}));
var test_module = function(extern)
{
var test_module = {};
var talk = function() {
if(extern.foo)
{
console.log(extern.foo());
}
else
{
console.log("No external function!");
}
};
test_module.talk = talk;
return test_module;
};
var test_module_ff = new test_module(ff_prefs);
var test_module_chrome = new test_module(chrome_prefs);
var test_module_none = new test_module({});
test_module_ff.talk();
test_module_chrome.talk();
test_module_none.talk();
Before, it was running itself, then when the extension started, it would call an init() function, which it can still do. It's just no longer an anonymous function.
There are some third party Javascript libraries that have some functionality I would like to use in a Node.js server. (Specifically I want to use a QuadTree javascript library that I found.) But these libraries are just straightforward .js files and not "Node.js libraries".
As such, these libraries don't follow the exports.var_name syntax that Node.js expects for its modules. As far as I understand that means when you do module = require('module_name'); or module = require('./path/to/file.js'); you'll end up with a module with no publicly accessible functions, etc.
My question then is "How do I load an arbitrary javascript file into Node.js such that I can utilize its functionality without having to rewrite it so that it does do exports?"
I'm very new to Node.js so please let me know if there is some glaring hole in my understanding of how it works.
EDIT: Researching into things more and I now see that the module loading pattern that Node.js uses is actually part of a recently developed standard for loading Javascript libraries called CommonJS. It says this right on the module doc page for Node.js, but I missed that until now.
It may end up being that the answer to my question is "wait until your library's authors get around to writing a CommonJS interface or do it your damn self."
Here's what I think is the 'rightest' answer for this situation.
Say you have a script file called quadtree.js.
You should build a custom node_module that has this sort of directory structure...
./node_modules/quadtree/quadtree-lib/
./node_modules/quadtree/quadtree-lib/quadtree.js
./node_modules/quadtree/quadtree-lib/README
./node_modules/quadtree/quadtree-lib/some-other-crap.js
./node_modules/quadtree/index.js
Everything in your ./node_modules/quadtree/quadtree-lib/ directory are files from your 3rd party library.
Then your ./node_modules/quadtree/index.js file will just load that library from the filesystem and do the work of exporting things properly.
var fs = require('fs');
// Read and eval library
filedata = fs.readFileSync('./node_modules/quadtree/quadtree-lib/quadtree.js','utf8');
eval(filedata);
/* The quadtree.js file defines a class 'QuadTree' which is all we want to export */
exports.QuadTree = QuadTree
Now you can use your quadtree module like any other node module...
var qt = require('quadtree');
qt.QuadTree();
I like this method because there's no need to go changing any of the source code of your 3rd party library--so it's easier to maintain. All you need to do on upgrade is look at their source code and ensure that you are still exporting the proper objects.
There is a much better method than using eval: the vm module.
For example, here is my execfile module, which evaluates the script at path in either context or the global context:
var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
context = context || {};
var data = fs.readFileSync(path);
vm.runInNewContext(data, context, path);
return context;
}
And it can be used like this:
> var execfile = require("execfile");
> // `someGlobal` will be a global variable while the script runs
> var context = execfile("example.js", { someGlobal: 42 });
> // And `getSomeGlobal` defined in the script is available on `context`:
> context.getSomeGlobal()
42
> context.someGlobal = 16
> context.getSomeGlobal()
16
Where example.js contains:
function getSomeGlobal() {
return someGlobal;
}
The big advantage of this method is that you've got complete control over the global variables in the executed script: you can pass in custom globals (via context), and all the globals created by the script will be added to context. Debugging is also easier because syntax errors and the like will be reported with the correct file name.
The simplest way is: eval(require('fs').readFileSync('./path/to/file.js', 'utf8'));
This works great for testing in the interactive shell.
AFAIK, that is indeed how modules must be loaded.
However, instead of tacking all exported functions onto the exports object, you can also tack them onto this (what would otherwise be the global object).
So, if you want to keep the other libraries compatible, you can do this:
this.quadTree = function () {
// the function's code
};
or, when the external library already has its own namespace, e.g. jQuery (not that you can use that in a server-side environment):
this.jQuery = jQuery;
In a non-Node environment, this would resolve to the global object, thus making it a global variable... which it already was. So it shouldn't break anything.
Edit:
James Herdman has a nice writeup about node.js for beginners, which also mentions this.
I'm not sure if I'll actually end up using this because it's a rather hacky solution, but one way around this is to build a little mini-module importer like this...
In the file ./node_modules/vanilla.js:
var fs = require('fs');
exports.require = function(path,names_to_export) {
filedata = fs.readFileSync(path,'utf8');
eval(filedata);
exported_obj = {};
for (i in names_to_export) {
to_eval = 'exported_obj[names_to_export[i]] = '
+ names_to_export[i] + ';'
eval(to_eval);
}
return exported_obj;
}
Then when you want to use your library's functionality you'll need to manually choose which names to export.
So for a library like the file ./lib/mylibrary.js...
function Foo() { //Do something... }
biz = "Blah blah";
var bar = {'baz':'filler'};
When you want to use its functionality in your Node.js code...
var vanilla = require('vanilla');
var mylibrary = vanilla.require('./lib/mylibrary.js',['biz','Foo'])
mylibrary.Foo // <-- this is Foo()
mylibrary.biz // <-- this is "Blah blah"
mylibrary.bar // <-- this is undefined (because we didn't export it)
Don't know how well this would all work in practice though.
I was able to make it work by updating their script, very easily, simply adding module.exports = where appropriate...
For example, I took their file and I copied to './libs/apprise.js'. Then where it starts with
function apprise(string, args, callback){
I assigned the function to module.exports = thus:
module.exports = function(string, args, callback){
Thus I'm able to import the library into my code like this:
window.apprise = require('./libs/apprise.js');
And I was good to go. YMMV, this was with webpack.
A simple include(filename) function with better error messaging (stack, filename etc.) for eval, in case of errors:
var fs = require('fs');
// circumvent nodejs/v8 "bug":
// https://github.com/PythonJS/PythonJS/issues/111
// http://perfectionkills.com/global-eval-what-are-the-options/
// e.g. a "function test() {}" will be undefined, but "test = function() {}" will exist
var globalEval = (function() {
var isIndirectEvalGlobal = (function(original, Object) {
try {
// Does `Object` resolve to a local variable, or to a global, built-in `Object`,
// reference to which we passed as a first argument?
return (1, eval)('Object') === original;
} catch (err) {
// if indirect eval errors out (as allowed per ES3), then just bail out with `false`
return false;
}
})(Object, 123);
if (isIndirectEvalGlobal) {
// if indirect eval executes code globally, use it
return function(expression) {
return (1, eval)(expression);
};
} else if (typeof window.execScript !== 'undefined') {
// if `window.execScript exists`, use it
return function(expression) {
return window.execScript(expression);
};
}
// otherwise, globalEval is `undefined` since nothing is returned
})();
function include(filename) {
file_contents = fs.readFileSync(filename, "utf8");
try {
//console.log(file_contents);
globalEval(file_contents);
} catch (e) {
e.fileName = filename;
keys = ["columnNumber", "fileName", "lineNumber", "message", "name", "stack"]
for (key in keys) {
k = keys[key];
console.log(k, " = ", e[k])
}
fo = e;
//throw new Error("include failed");
}
}
But it even gets dirtier with nodejs: you need to specify this:
export NODE_MODULE_CONTEXTS=1
nodejs tmp.js
Otherwise you cannot use global variables in files included with include(...).