I found the solution by using global.consoleLog = v => this.log(v));. Now the variable consoleLog is available anywhere.
ORIGINAL QUESTION
Currently I am participating in the battlecode challenge. My question is about Javascript though and accessing a global variable.
I have a minimal working example with two files.
// === robot.js ===
import { BCAbstractRobot } from 'battlecode';
import Test from './test.js';
class MyRobot extends BCAbstractRobot {
constructor() {
super();
this.log("asdf"); // the log function does work
// Test.setConsoleLog(this.log); // way 1
// console.log = this.log; // way 2
}
turn() {
Test.testFunction("hello");
return this.move(0, 1);
}
}
// === test.js ===
let consoleLog = undefined;
function setConsoleLog(c) {
consoleLog = c;
}
function testFunction(s) {
// consoleLog(s); // way 1
// console.log(s); // way 2
}
export default { testFunction, consoleLog, setConsoleLog };
Since battlecode gives you the log function, you cannot use console.log for security reasons. However I want to be able to log from any file. The log function is a property of the MyRobot class, but I want to be able to access the function from other files and functions without passing parameters every time.
I tried a couple ways. First I tried creating an export from a util file (test.js) which would start out as undefined and then be set by setConsoleLog. However, when I attempt to use consoleLog, it is still undefined.
I also tried overwriting the console.log reference, but this only works within one file and the reference is still to console.log in other files.
What would be the recommended way to go about creating a global reference or import to this.log such that any file could import it and access it?
The bot is run within a node vm, but with a bundler as far as I know.
I'm currently working with the discord.js library.
I guess I can call it by this name, but whenever I want to access a file, this doesn't work.
Let's say I have a file called calc.js and I want to access the main.js file and take a variable out of there using exports and require it to just take the value out of it.
But I haven't found even one way online to modify the variables and return another value to the file.
Can someone help me?
As noted, JavaScript doesn't pass every variable by reference. If you need to access a primitive value like a number, you could declare it as a local variable and export functions to access and modify it. Something like this rough example:
increment.js
let count = 0;
module.exports = {
get: () => count,
increment: () => ++count
};
main.js
const { get, increment } = require('./increment.js');
console.log(get());
console.log(increment());
console.log(get());
Edit: You should probably not name your accessor get, as that's the key word used to describe getters in ES6. Or better yet, turn such a get function into a getter with a more suitable name.
I have recently started working on a JavaScript project and coming from Java world things seem, not surprisingly, weird at times.
I was implementing a simple module (Using revealing module pattern, afaik) which would provide config based on initialisation but notice that after a "local" variable domain is assigned in init() function its value differs depending whether it is accessed via a "getter" function getDomain() or directly via domain variable as exposed via modules "public" API.
See the following stripped down code which demonstrates the issue.
var ConfigManager = (function() {
var privateDomain = 'default';
function init(dom) {
privateDomain = dom;
}
function getDomain() {
return privateDomain;
}
return {
init: init,
domain: privateDomain,
getDomain: getDomain
};
})();
console.log(ConfigManager.domain); // Prints 'default'
console.log(ConfigManager.getDomain()); // Prints 'default'
ConfigManager.init('new domain');
console.log(ConfigManager.domain); // Prints 'default' <-- What??
console.log(ConfigManager.getDomain()); // Prints 'new domain'
At this point I am very confused how a variable returned from a getter function can have a different value when it is accessed directly?
Than you in advance!
Since privateDomain is a String, you're not copying / returning the reference, but the value.
Therefore when you're changing the domain using the init function, it just updates privateDomain, since domain has no link to it other than being a copy.
Hope it helps! :)
It's because when domain is returned, it's value is still "default". It's how Javascript works, more info here: Javascript by reference vs. by value
But when you use the function "getDomain" you will get the updated value.
Also have a look at the get/set syntax: Getter
How can I make a globally accessible variable in nightwatch.js? I'm using a variable to store a customized url (dependent on which store is loaded in our online product), but I need it to be accessible across several javascript functions. It appears the value of it resets after each function ends, despite it being declared outside of the function at the head of the file.
It's been some time since you asked your question and support for what you requested might not have been (natively) available before. Now it is.
In the developer guide two methods are provided for creating global variables accessible from any given test, depending on your needs. See here for good reading.
Method 1:
For truly global globals, that is, for all tests and all environments. Define an object, or pass a file, at the "globals_path" section of your nightwatch.json file, i.e.
"globals_path": "./lib/globals.js",
You will need to export the variables, however, so brushing up on Node is a good idea. Here is a basic globals.js file example:
var userNames = {
basicAuth: 'chicken',
clientEmail: 'SaddenedSnail#domain.com',
adminEmail: 'admin#domain.com',
};
module.exports = {
userNames: userNames
}
This object/file will be used for all of your tests, no matter the environment, unless you specify a different file/object as seen in method 2 below.
To access the variables from your test suite, use the mandatory browser/client variable passed to every function (test), i.e:
'Account Log In': function accLogin(client) {
var user = client.globals.userNames.clientEmail;
client
.url(yourUrl)
.waitForElementVisible('yourUserNameField', 1000)
.setValue('yourUserNameField', user)
.end();
}
Method 2:
For environment based globals, which change depending on the environment you specify. Define an object, or pass a file, at the "globals" section of your nightwatch.json file, nested under your required environment. I.e.
"test_settings" : {
"default" : {
"launch_url" : "http://localhost",
"selenium_port" : 4444,
"selenium_host" : "localhost",
"globals": {
"myGlobal" : "some_required_global"
}
}
}
Please note that at the time of writing, there seems to be a bug in nightwatch and thus passing a file using Method 2 does not work (at least in my environment). More info about said bug can be found here.
To expand on Tricote's answer, Nightwatch has built-in support for this. See the documentation.
You can either specify it in the nightwatch.json file as "globals": {"myvar": "whatever"} or in a globals.js file that you reference within nightwatch.json with "globals": "path/to/globals.js". In the latter case, globals.js could have:
module.exports = {
myvar: 'whatever'
};
In either case, you can access the variable within your tests as Tricote mentioned:
module.exports = {
"test": function(browser) {
console.log(browser.globals.myvar); // "whatever"
}
};
I'll probably get down-voted for this, but another option that I have been using successfully to store and retrieve objects and data is to do a file write as key value pairs to an existing file.
This allows me to, at the end of a test run, see any data that was randomly created. I create this file in my first test script using all of the data I will use to create the various accounts for the test. In this way, if I see a whole lot of failures, I can take a look at the file and see what data was used, then say, log in as that user and go to that location manually.
In custom commands I have a file that exports the following function:
saveToFile : function(path, filename, data) {
this.yfs = fs;
buffer = new Buffer(data);
console.log("Note: About to update the configuration with test data" )
fs.open(path, 'w', function(err, fd) {
if (err) {
throw 'error opening file: ' + err;
}
fs.write(fd, buffer, 0, buffer.length, null, function(err) {
if (err) throw 'error writing file: ' + err;
return fs.close(fd, function() {
console.log('File write: ' + path + ' has been updated.' );
})
});
})
},
In this file, 'data' is key value pairs like "username" : "Randy8989#mailinator.com". As a result I can use that data in later scripts, if so desired.
This being true, I'll be exploring GrayedFox's answer immediately.
Not sure it's the best way, but here is how I do it : you can define a variable in the browser.globals and access it in your different tests
For instance :
module.exports = {
before: function(browser) {
console.log("Setting up...");
// initialize global variable state
browser.globals.state = {};
},
"first test": function(browser) {
var settings = browser.globals,
state = browser.globals.state;
state.my_shared_var = "something";
browser.
// ...
// use a shared variable
.setValue('input#id', state.my_shared_var)
// ...
// ...
// save something from the page in a variable
.getText("#result", function(result) {
state.my_shared_result = result.value;
})
// ...
},
"second test": function(browser) {
var settings = browser.globals,
state = browser.globals.state;
browser.
// ...
// use the variables
.url("http://example.com/" + state.my_shared_result + "/show")
.assert.containsText('body', state.my_shared_var)
// ...
}
}
An alternative of globals.json if you need read data with complex procedure, is just to create a function in the same test file.
In the following example, I needed simple values and data from csv.
So I created getData() function and I can invoke directly from inside:
let csvToJson = require('convert-csv-to-json');
function getData(){
let users = csvToJson.getJsonFromCsv("/../users.csv");
return {
"users:": users,
"wordToSearch":"JRichardsz"
}
}
module.exports = {
"login": function(browser) {
//data is loading here
var data = getData();
browser
.url('https://www.google.com')
.waitForElementVisible('input[name="q"]', 4000)
.setValue('input[name="q"]', data.wordToSearch)
.keys(browser.Keys.ENTER)
.waitForElementVisible('#result-stats', 4000)
.end();
}
};
generaly it is a bad practice, but you can assign it as field of window class.
window.someGlobalVar = 'http://example.org/'
and window object is accessible globally
I have code in a module which looks something like this:
var MyModule = module.exports;
MyModule.some_function = function(arg) {
// Do some code here
// Do some logging using the function name
// var function_name = calleeArgs.callee.toString().match(/function ([^\(]+)/)[1];
// BAD, this method doesnt have a name
};
The code above does not work as the function does not have a name.
As an alternative, I could do the following, in which case the log would contain the method name:
function _some_function(arg) {
// Do some code here
// Do some logging using the function name - BAD, this method doesnt have a name
// var function_name = calleeArgs.callee.toString().match(/function ([^\(]+)/)[1];
// GOO, this method doesnt have a name
}
MyModule.some_function = function(arg) {
_some_function(arg);
};
So my question is:
1.) Does this way of writing make any sense - as far as I understand _some_function() is local to this module so there will be no negative implications as far as global scope/access is concerned
2.) Does this (the second option) have any performance implications? (my guess would of course be no, or at least relatively negligible)?
1) I find that code style very confusing and bloated. I think the following is the cleanest approach:
function some_function(arg) {
// Do some code here
// Do some logging using the function name
}
// Put exports at the end
exports.some_function = some_function;
2) A function wrapping another function will add a negligible overhead, but it should be avoided if it adds no value.