PhantomJS: require Script and set variables beforehand - javascript

I am using PhantomJS for page automation. For my script, I need to load another script which is also used on the actual client-side of my webpage. This script contains some parts where global variables - which are assumed to be set before the script is loaded - are used.
Now my problem is that I can't figure out how to set these variables before I require them within PhantomJS.
This (obviously) didn't do the trick:
variableX = 1024;
var moduleX = require('myScripts.js');
Now what's the proper and intended way ( if there is one) to do this?

If you prepare the testing script as a CommonJS module, you can require it and use its methods and variables in PhantomJS.
From the docs: http://phantomjs.org/release-1.7.html
As an example, supposed there is a script universe.js which contains the following code:
exports.answer = 42;
exports.start = function () {
console.log('Starting the universe....');
}
This module can be used in another script like the following:
var universe = require('./universe');
universe.start();
console.log('The answer is', universe.answer);
And if you want to assign global variables from such a module you can use the global object as in node.js:
exports.start = function () {
global.success = true;
console.log('Starting the universe....');
}

Related

How do I refer to a JavaScript function defined in a different script in WinDbg?

I have a couple of JavaScript scripts to house my functions (for modularity and reuse). I load them both from the windbg script I'm running. From within one script, how do I call a function defined in the other?
This engine doesn't seem to support the import/export feature employed by browsers.
From within the debugger script, I have to use #$scriptContents to access JavaScript functions.
How do I accomplish something similar from within one of the JavaScript functions?
Experiment
I was hoping there would be some sort of global namespace for all JavaScript functions, but it appears not.
Consider
// t1.js
function func1() {
host.diagnostics.debugLog('func1()...\n');
}
and
// t2.js
function func2() {
host.diagnostics.debugLog('func2()...\n');
func1();
}
In my cdb session
0:000> .load jsprovider.dll
0:000> .scriptload t1.js
JavaScript script successfully loaded from 't1.js'
0:000> .scriptload t2.js
JavaScript script successfully loaded from 't2.js'
0:000> dx #$scriptContents.func1()
func1()...
#$scriptContents.func1()
0:000> dx #$scriptContents.func2()
func2()...
Error: 'func1' is not defined [at t2 (line 3 col 5)]
Edit
Per #Mosè Raguzzini's comment and this answer, I went looking for some way to reference "foreign" functions.
I eventually unearthed this
host.namespace.Debugger.State.DebuggerVariables.scriptContents
as a container for all functions. Is this documented somewhere? Is there no simpler way to get there? (I realize I can just assign a short variable to that object; I'm just suspicious this this is more of a backdoor into something with a very simple front door, but I don't know where the front door is.)
AFAIK all scripts are imported in global scope, so you can act as them are written in a single file, once all are loaded.
Example (REF to blabb answer)
common.js has a few functions that are normally reusable like
host.diagnostics.debugLog()
First load it using .scriptload
Then in other js files create a var to those functions and use it
contents of common function file
C:\>cat c:\wdscr\common.js
function log(instr) {
host.diagnostics.debugLog(instr + "\n");
}
function exec (cmdstr){
return host.namespace.Debugger.Utility.Control.ExecuteCommand(cmdstr);
}
a js file using the function from common.js
C:\>cat c:\wdscr\usecommon.js
function foo(){
var commonlog = host.namespace.Debugger.State.Scripts.common.Contents.log
var commonexec = host.namespace.Debugger.State.Scripts.common.Contents.exec
commonlog("we are using the logging function from the common.js file")
var blah = commonexec("lma #$exentry")
for(var a of blah) {
commonlog(a)
}
}
actual usage
C:\>cdb calc
Microsoft (R) Windows Debugger Version 10.0.16299.15 X86
0:000> .load jsprovider
0:000> .scriptload c:\wdscr\common.js
JavaScript script successfully loaded from 'c:\wdscr\common.js'
0:000> .scriptload c:\wdscr\usecommon.js
JavaScript script successfully loaded from 'c:\wdscr\usecommon.js'
0:000> dx #$scriptContents.foo()
we are using the logging function from the common.js file
start end module name
00f10000 00fd0000 calc (deferred)
#$scriptContents.foo()
0:000>
well you can write a javascript function that calls any function from any script sitting in any directory
using something like below (you may need to tweak it the POC worked on my machine for a .js that returned a string)
function runFuncFromAnyScript(dir,script,somefunc) {
var unl = ".scriptunload " + script
host.namespace.Debugger.Utility.Control.ExecuteCommand(unl)
var pre = ".scriptload "
var post = "dx #$scriptContents." + somefunc
var cmd = pre + dir + script
host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
return host.namespace.Debugger.Utility.Control.ExecuteCommand(post)
}
used like
0:000> dx #$scriptContents.runFuncFromAnyScript("f:\\zzzz\\wdscript\\","mojo.js","hola_mojo(\"executethis\")" )
#$scriptContents.runFuncFromAnyScript("f:\\zzzz\\wdscript\\","mojo.js","hola_mojo(\"executethis\")" )
[0x0] : hola mojo this is javascript
[0x1] : hello mojo this is the argument you sent to me for execution I have executed your executethis
[0x2] : #$scriptContents.hola_mojo("executethis")

Adding global variables via a require Common Function file

I am doing a POC on switching to Protractor and Jasmine to perform our automated scripting. I'm trying to build a preliminary framework, but I'm having issues trying to translate my concept to reality.
I've set up three files: conf.js, spec.js, and cf.js. Conf.js is testplan-specific configuration file, spec.js contains the actual tests, and cf.js contains the common functions that I will be using through all test plans. I am trying to include a variable in cf.js to contain the starting URL to be used in the browser.get call. So far, I have not been able to get that to work. I've tried declaring it in cf.js before the //commonfunctions// function declaration, as well as within the function itself. What is the proper way to do this?
cf.js
var commonfunctions = function () {
global.StartPage = 'http://google.com/';
this.ccClick = function (clickElement) {
browser.wait(protractor.ExpectedConditions.visibilityOf(clickElement),
this.defaultWait);
browser.wait(protractor.ExpectedConditions.elementToBeClickable(clickElement),
this.defaultWait);
clickElement.click();
};
// Common text search
this.ConfirmText = function(testElement, compareString) {
browser.wait(protractor.ExpectedConditions.visibilityOf(testElement),
10000);
expect(testElement.getText()).toEqual(compareString);
};
};
module.exports = new commonfunctions();
spec.js
beforeEach(function() {
browser.waitForAngularEnabled(false);
browser.get(commonfunctions.StartPage);
});
Right now, it does not navigate to the webpage.
This should be possible, I have posted a similar answer before but let me know if you have further concerns about the approach. The approach I took was to require the common function file in the onPrepare as a global variable. This way anything exported from the file is accessible throughout all the tests.
Storing global variable in a separate file for Protractor Tests
Your made a mistake at following code:
// cf.js
var commonfunctions = function () {
global.StartPage = 'http://google.com/';
// spec.js
beforeEach(function() {
browser.waitForAngularEnabled(false);
browser.get(commonfunctions.StartPage);
});
// you define `StartPage` to a global variable, not a property of `commonfunctions`,
thus you shouldn't refer it from `commonfunctions`, but from `global` as following:
browser.get(global.StartPage)
or you define StartPage to be a property of commonfunctions
// cf.js
var commonfunctions = function () {
this.StartPage = 'http://google.com/';
// use `this` at here, rather than `global`
// spec.js
beforeEach(function() {
browser.waitForAngularEnabled(false);
browser.get(commonfunctions.StartPage);
});
Add the below one to your config.js
baseUrl: 'http://google.com/',
To use it in your test as below
browser.get(browser.baseUrl);
Hope this helps you

How to call a static JS function defined in other javascript file

I am using Meteor JS.
I have a JavaScript function defined in file A which I want to reuse by calling from file B. Example:
File A:
function Storeclass(){}
Storeclass.validate=function(){...}
From A JavaScript I try to call StoreClass.validateBasic() it works but the same call doesn't work from B. Also I tried in B doing var storeClassObj=new StoreClass(); and storeClassObj.validate(). I get error ReferenceError: StoreClass is not defined.
Read this doc about namespacing in Meteor.
The relevant portion is this:
// File Scope. This variable will be visible only inside this
// one file. Other files in this app or package won't see it.
var alicePerson = {name: "alice"};
// Package Scope. This variable is visible to every file inside
// of this package or app. The difference is that 'var' is
// omitted.
bobPerson = {name: "bob"};
However, later on in the same doc, it says this:
When declaring functions, keep in mind that function x () {} is just shorthand for var x = function x () {} in JavaScript.
This suggests that the function you have written is private to the file A and cannot be accessed from file B, even if load order is correct!
Because your function in file B might invoke before File A is ready so you have to make sure that all required js files are loaded successfully.
If you are using jQuery then in file B call your function in document ready function:
$( document ).ready(function() {
//File A code
});
or in plain JavaScript:
(function() {
// your page initialization code here
// file A code
})();

Load "Vanilla" Javascript Libraries into Node.js

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(...).

Load and execute external js file in node.js with access to local variables?

Is it easy/possible to do a simple include('./path/to/file') type of command in node.js?
All I want to do is have access to local variables and run a script. How do people typically organize node.js projects that are bigger than a simple hello world? (A fully functional dynamic website)
For example I'd like to have directories like:
/models
/views
... etc
Just do a require('./yourfile.js');
Declare all the variables that you want outside access as global variables.
So instead of
var a = "hello" it will be
GLOBAL.a="hello" or just
a = "hello"
This is obviously bad. You don't want to be polluting the global scope.
Instead the suggest method is to export your functions/variables.
If you want the MVC pattern take a look at Geddy.
You need to understand CommonJS, which is a pattern to define modules. You shouldn't abuse GLOBAL scope that's always a bad thing to do, instead you can use the 'exports' token, like this:
// circle.js
var PI = 3.14; // PI will not be accessible from outside this module
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
And the client code that will use our module:
// client.js
var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));
This code was extracted from node.js documentation API:
http://nodejs.org/docs/v0.3.2/api/modules.html
Also, if you want to use something like Rails or Sinatra, I recommend Express (I couldn't post the URL, shame on Stack Overflow!)
If you are writing code for Node, using Node modules as described by Ivan is without a doubt the way to go.
However, if you need to load JavaScript that has already been written and isn't aware of node, the vm module is the way to go (and definitely preferable to eval).
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) {
var data = fs.readFileSync(path);
vm.runInNewContext(data, context, path);
}
Also note: modules loaded with require(…) don't have access to the global context.
If you are planning to load an external javascript file's functions or objects, load on this context using the following code – note the runInThisContext method:
var vm = require("vm");
var fs = require("fs");
var data = fs.readFileSync('./externalfile.js');
const script = new vm.Script(data);
script.runInThisContext();
// here you can use externalfile's functions or objects as if they were instantiated here. They have been added to this context.
Expanding on #Shripad's and #Ivan's answer, I would recommend that you use Node.js's standard module.export functionality.
In your file for constants (e.g. constants.js), you'd write constants like this:
const CONST1 = 1;
module.exports.CONST1 = CONST1;
const CONST2 = 2;
module.exports.CONST2 = CONST2;
Then in the file in which you want to use those constants, write the following code:
const {CONST1 , CONST2} = require('./constants.js');
If you've never seen the const { ... } syntax before: that's destructuring assignment.
Sorry for resurrection. You could use child_process module to execute external js files in node.js
var child_process = require('child_process');
//EXECUTE yourExternalJsFile.js
child_process.exec('node yourExternalJsFile.js', (error, stdout, stderr) => {
console.log(`${stdout}`);
console.log(`${stderr}`);
if (error !== null) {
console.log(`exec error: ${error}`);
}
});

Categories