What can yeoman's withGenerators test helper be used for? - javascript

I've been creating a lot of tests for yeoman generators lately, and I'm having trouble understanding the purpose of the withGenerators() helper method.
The example given:
var angular = new RunContext('../../app');
angular.withGenerators([
'../../common',
'../../controller',
'../../main',
[helpers.createDummyGenerator(), 'testacular:app']
]);
The function itself:
RunContext.prototype.withGenerators = function (dependencies) {
assert(_.isArray(dependencies), 'dependencies should be an array');
this.dependencies = this.dependencies.concat(dependencies);
return this;
};
I see that the function adds an array of dependencies to the Run Context object, with each item in the array being a path to a dependent generator.
What are these paths used for?
When and why would I need to use this method?
In the example given, is calling angular.withGenerators([...]) identical to calling yo angular, yo angular:common, yo angular:controller, and so on from the command line, or does it somehow simulate or modify calls to composeWith() in the actual generator?
What is the difference between running withGenerators() in the tests, and calling composeWith() from the generator itself?

This is used for composeWith() (or the legacy invoke() and hookFor() methods).
You can see the relevant code here: https://github.com/yeoman/yeoman-test/blob/master/lib/index.js#L173-L188
Basically when calling composeWith(), it'll use the dummy generator mock you passed instead of the one the environment would resolve.
A tricky part at the moment is that if you pass the local path settings to composeWith, it'll ignore the stubs - you can see the bug filled here https://github.com/yeoman/generator/issues/704 (the ticket suggests some manual workarounds)

Related

Using sinon how does one fake/stub/mock a non existing JS API in a way than sinon.restore removes all trace of it afterwards?

While running my tests I sometimes want to provide a API for my tests. I want this api to be defined for the duration of the test(s) alone, and so I want to ensure that sinon.restore() removes this test api. This is not replacing an existing JS API. (eg. NOT something like window.requestAnimiationFrame). This API is assumed to exist globally. (eg. on the global/window object)
Now If I didn't care about removing this API, after the test was done I would do the following:
globalAPIObject.someTestApi = sinon.fake.returns('something');
However sinon.restore won't/can't remove globalAPIObject.someTestApi after the test has run.
I would like to be able to use fake, in the same way as stub. (but sinon doesn't provide this)
// !! this API doesn't exist !!
sinon.fake(globalAPIObject, 'someTestApi').returns('something');
// !! this API doesn't exist !!
So I use stub instead:
// This doesn't work if globalAPIObject.someTestAPi doesn't already exist.
sinon.stub(globalAPIObject, 'someTestApi').returns('something');
However this only works for replacing props/functions that already exist, so I have to do:
globalAPIObject.someTestApi = () = {};
sinon.stub(globalAPIObject, 'someTestApi').returns('something');
Which is less than ideal. (As globalAPIObject.someTestApi isn't removed at the end of the test, by sinon.restore(). Also I'd rather only have to write a single line)
Since I guess that providing a non existent API is something that lots of people want to do, I guessing I'm missing something obvious.
What is the best way to fake/stub/mock a new API in a way than sinon.restore removes all trace of it afterwards?
In short, you cannot do this using sinon.restore(). We explicitly made the API throw on trying to replace non-existent props, but we have had a longer discussion about this on the sinon team and essentially came to the the conclusion that we should add something like sinon.define(). Still, no one ever made that feature request into an actual issue, so if I were you I would just file a new issue with this as your feature request to the Sinon Github tracker. Lots of people would like this feature and it's really not that hard to implement, so just make it visible :)
To actually do this using today's existing machinery I would probably just do as mentioned in the comments: use your test frameworks before/after hooks to setup and tear down manually constructed stubs.
If I were to do it myself I would probably have redone the code to be able to inject the API into your module, though, instead of relying on globals. That's another school of thought, so, whatever rocks your boat :)
Given that 'oligofren' helpfully clarified that sinon.stub doesn't our use case yet we just extended it so does.
// sinonExtensions.js
import sinon from "sinon";
if (sinon.stub !== enhancedStub)
{
sinon.originalStub = sinon.stub;
sinon.stub = enhancedStub;
}
function enhancedStub(obj, method)
{
if (!obj)
return sinon.originalStub();
if (!obj[method])
obj[method] = () => { };
return sinon.originalStub(obj, method);
}
// TODO: enhance sinon.restore to return non-existing methods to undefined
Which we just import along with the rest of the sinon imports:
import sinon, { mock } from "sinon";
import sinonChai from 'sinon-chai';
import 'sinonExtensions.js';
chai.use(sinonChai);
Which is good for all our current usages of sinon.stub.
And now this happy works:
sinon.stub(globalAPIObject, 'someTestApi').returns('something');

Overriding core JS commands?

I'm trying to modify/limit/prevent access to certain JS commands of my browser. For example commands like navigator.clipboard; However, I'm not sure how to approach this.
Is it possible to override these commands with user-defined javascript injected in the page, or do i have to edit the browser's javascript compiler and re-compile it from source for this?
I'm not really familiar with browsers and want to save time by knowing a general direction to follow. Thanks
First of all navigator.clipboard is not a function, but here is an example using the read function of navigator.clipboard:
navigator.clipboard.read = function (originalFunction) {
return function (yourParamsYouWantForThisFunction) {
// Do Stuff you wanna do before the real call. For example:
console.log(yourParamsYouWantForThisFunction);
// Call the original function
return originalFunction.call();
};
}(navigator.clipboard.read); // Pass the original function reference as a parameter
You may wonder, why there are two function statements:
The first one is there, so that we can pass the original function at runtime. If we would not do that, we would not be able to access the original navigator.clipboard.read function.
The second function is the actual function, that you will be using later, when you call navigator.clipboard.read().

Unit tests in JavaScript with mocked objects

So I'm working with an enterprise tool where we have javascript scripts embedded throughout. These scripts have access to certain built-in objects.
Unfortunately, the tool doesn't give any good way to unit test these scripts. So my thinking was to maintain the scripts in a repo, mock the built-in objects, and then set up unit tests that run on my system.
I'm pretty ignorant to how JavaScript works in terms of building, class loading, etc. but I've been just trying things and seeing what works. I started by trying out Mocha by making it a node project (even though it's just a directory full of scripts, not a real node project). The default test works, but when I try and test functions from my code, I get compiler errors.
Here's what a sample script from my project looks like. I'm hoping to test the functions, not the entire script:
var thing = builtInObject.foo();
doStuff(thing);
doMoreStuff(thing);
function doStuff(thing) {
// Code
}
function doMoreStuff(thing) {
// More Code
}
Here's what a test file looks like:
var assert = require('assert');
var sampleScript = require('../scripts/sampleScript.js');
describe('SampleScript', function() {
describe('#doStuff()', function() {
it('should do stuff', function() {
assert.equal(-1, sampleScript.doStuff("input"));
});
});
});
Problem happens when I import ("require") the script. I get compilation errors, because it doesn't builtInObject. Is there any way I can "inject" those built in objects with mocks? So I define variables and functions that those objects contain, and the compiler knows what they are?
I'm open to alternative frameworks or ideas. Sorry for my ignorance, I'm not really a javascript guy. And I know this is a bit hacky, but it seems like the best option since I'm not getting out of the enterprise tool.
So if I get it right you want to do the unit tests for the frontened file in the Node.js environment.
There are some complications.
First, in terms of Node.js each file has it's own scope so the variables defined inside of the file won't be accessible even if you required the file. So you need to export the vars to use them.
module.exports.doStuff = doStuff; //in the end of sample script
Second, you you start using things like require/module.exports on the frontend they'll be undefined so you'll get an error.
The easiest way to run your code would be. Inside the sample script:
var isNode = typeof module !== 'undefined' && module.exports;
if (isNode) {
//So we are exporting only when we are running in Node env.
//After this doStuff and doMoreStuff will be avail. in the test
module.exports.doStuff = doStuff;
module.exports.doMoreStuff = doMoreStuff;
}
What for the builtInObject. The easies way to mock it would be inside the test before the require do the following:
global.builtInObject = {
foo: function () { return 'thing'; }
};
The test just passed for me. See the sources.
Global variables are not good anyway. But in this case seems you cannot avoid using them.
Or you can avoid using Node.js by configuring something like Karma. It physically launches browser and runs the tests in it. :)

How to parse and load javascript object?

I have one js files . I load it using other javascrupt file using eval() function. I have seen eval is slow and with some other limtation. Since i need to store my JS file object in cache and use it anytime i need after apllication starts. I dont want to do eval() everytime.
Is there anyway to do it in simple way.
var evalObj;
if(evalObj) {
console.log('eval object already evaluated');
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level, categoryName, message);
}
else {
evalObj = eval(fs.readFileSync('./myJSFile', 'utf8'));
console.log('re evaluating object ..' );
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
}
myJSFile
var _sigmaAlarmHandler_ =function(args)
{
var args = Array.prototype.slice.call(arguments);
args.unshift();
console.log('Alarm : ', args);
}
Either the conditional eval is not working.
In node.js you can simple require your js-file:
var obj = require('./myJSFile');
obj.foo();
./myJSFile.js:
exports.foo = function() {
console.log('foo');
}
This file becomes a module with exported functions, that you need.
It loads once, then every require reuse already loaded module.
If it is not commonjs-compliant (i.e. using module.exports will not work), then you can run it in its own vm:
var vm = require('vm');
vm.runInNewContext(jscode,{/*globalvars*/});
where the second parameter is an object with global vars made available in the context in which the jscode is run. So if the second param is, say, {a:1,b:"foo"} then your jscode will run with the global variable a set to 1 and the global variable b set to "foo".
The jscode itself is a string that you load from a file or elsewhere.
Think of vm.runInNewContext() as "practice safe eval". Well, relatively safe, you can still do some dangerous stuff if you pass in particular vars, like process or file etc.
I used this for the declarative part of cansecurity http://github.com/deitch/cansecurity for nodejs
You can view the sample in the file lib/declarative.js
Here is the API for vm http://nodejs.org/api/vm.html
There are options to run in the same context, etc. But that is very risky.
When you actually run the code, using your example above:
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
you are looking to pass in 4 params: startTime, threadName, level, message and execute the function. The issue is that you cannot run the function on the current context. You need the function to be defined and run in the file. So you should have something like:
vm.runInNewContext(jscode,{startTime:layouts.FormatDate(startTime),threadName:threadName,level:level,message:message});
And then the jscode should look like
function _myfunctionInJSFile(startTime,threadName,level,message) {
// do whatever you need to do
}
// EXECUTE IT - the above vars are set by the global context provide in vm.runInNewContext
_myfunctionInJSFile(startTime,threadName,level,message);
If you prefer to define the function and have it loaded and run in this context, then just use the commonjs format.
I think i have found the answer for this.
Since my application is running in node js which uses v8 engine platform. When the application starts v8 engine caches all the code/configuration and can be used anytime.
Similarly in my code i will pre-load the JS code using eval and i will do it only once. So on next call i will return only the loaded JS code. Here i need to modify the code to load once.
But main point we have look is that in future if any body has similar requirement they can cache their JS codes using eval (thanks to v8 engine) and use it till your application is running.

Make Closure Compiler strip log function usages

I have a logging API I want to expose to some internal JS code. I want to be able to use this API to log, but only when I am making a debug build. Right now, I have it partially working. It only logs on debug builds, but the calls to this API are still in the code when there is a regular build. I would like the closure-compiler to remove this essentially dead code when I compiler with goog.DEBUG = false.
Log definition:
goog.provide('com.foo.android.Log');
com.foo.Log.e = function(message){
goog.DEBUG && AndroidLog.e(message);
}
goog.export(com.foo.Log, "e", com.foo.Log.e);
AndroidLog is a Java object provided to the webview this will run in, and properly externed like this:
var AndroidLog = {};
/**
* Log out to the error console
*
* #param {string} message The message to log
*/
AndroidLog.e = function(message) {};
Then, in my code, I can use:
com.foo.Log.e("Hello!"); // I want these stripped in production builds
My question is this: How can I provide this API, use this API all over my code, but then have any calls to this API removed when not compiled with goog.DEBUG = true? Right now, my code base is getting bloated with a bunch of calls to the Log API that are never called. I want the removed.
Thanks!
The Closure Compiler provides four options in CompilerOptions.java to strip code: 1) stripTypes, 2) stripNameSuffixes, 3) stripNamePrefixes and 4) stripTypePrefixes. The Closure build tool plovr, exposes stripNameSuffixes and stripTypePrefixes through its JSON configuration file options name-suffixes-to-strip and type-prefixes-to-strip.
There are excellent examples of how these options work in Closure: The Definitive Guide on pages 442 to 444. The following lines are provided as common use cases:
options.stripTypePrefixes = ImmutableSet.of(“goog.debug”, “goog.asserts”);
options.stripNameSuffixes = ImmutableSet.of(“logger”, “logger_”);
To understand the nuances of these options and avoid potential pitfalls, I highly recommend reading the complete examples in Closure: The Definitive Guide.
Instead of running your own script as jfriend00 suggested I would look at the define api of the compiler (which is where goog.DEBUG comes from as well), you have DEBUG, COMPILED by default, but there you can roll your own.
OK, it turns out this is easy to do if I stop exporting com.foo.Log() and its methods. If I really want to be able to log in some specific cases, but still strip out the log calls in my internal code, I can just declare two classes for this:
// This will get inlined and stripped, since its not exported.
goog.provide('com.foo.android.Log');
com.foo.Log.e = function(message){
goog.DEBUG && AndroidLog.e(message);
}
// Don't export.
// This be available to use after closure compiler runs, since it's exported.
goog.provide('com.foo.android.production.Log');
goog.exportSymbol("ProductionLog", com.foo.android.production.Log);
com.foo.android.production.Log.log = function(message){
goog.DEBUG && AndroidLog.e(message);
}
// Export.
goog.exportProperty(com.foo.android.production.Log, "log", com.foo.android.production.Log.log);
I have modified a compiler and packaged it as an npm package.
You can get it here: https://github.com/thanpolas/superstartup-closure-compiler#readme
It will strip all logging messages during compilation

Categories