Loading templates - javascript

Good day,
I've tried using both ng-html2js and grunt-html2js to try to load my directive templates as modules when testing but have hit a-bit of a road block on both cases. My questions will revolve around the former as this is what I've attempting to use most.
Correct me if I'm wrong; In order to use ng-html2js you must first register the module from node like so:
npm install karma-ng-html2js-preprocessor -g
This installs it globally which is what I want as I run my karma
tests using the following command which hands over to the global instance of karma installed.:
karma start
Next in the karma.conf.js file you must then specify which templates you
want to use and what dependency it is to be used with:
preprocessors: {
'webapp/scripts/*.js': 'coverage',
'webapp/modules/**/*.js': 'coverage',
'webapp/modules/groupbydrug.html': 'ng-html2js'
},
When it comes to the test, we can load the module doing this:
beforeEach(module('webapp/modules/groupbydrug.html'));
Finally we compile as usual, add the directive to a piece of html and test:
beforeEach(function () {
ele = angular.element('<div group-by-drug=""></div>');
compile(ele)(scope);
scope.$digest();
});
it('should have a table with a class of "drugs-by-mail"', function () {
var div = ele.find('div.outrepeat');
console.log(div);
});
BTW - The template looks like this:
<div ng-repeat="(orderNumber,orderData) in orders" class="drugs-by-mail">
<table class="recent-order-mail">
...
</table>
</div>
Based on what I've read I should beable to retrieve the div from the template but when I try and print it to the console I get an empty object (Object{}) when I'd actually expect to see all the content within that div - is that not correct?
So where along here am I going wrong? Or is this an issue with installation (global karma vs local)
Thanks

Related

npm global packages: Reference content files from package

I'm in the process of building an npm package which will be installed globally. Is it possible to have non-code files installed alongside code files that can be referenced from code files?
For example, if my package includes someTextFile.txt and a module.js file (and my package.json includes "bin": {"someCommand":"./module.js"}) can I read the contents of someTextFile.txt into memory in module.js? How would I do that?
The following is an example of a module that loads the contents of a file (string) into the global scope.
core.js : the main module file (entry point of package.json)
//:Understanding: module.exports
module.exports = {
reload:(cb)=>{ console.log("[>] Magick reloading to memory"); ReadSpellBook(cb)}
}
//:Understanding: global object
//the following function is only accesible by the magick module
const ReadSpellBook=(cb)=>{
require('fs').readFile(__dirname+"/spellBook.txt","utf8",(e,theSpells)=>{
if(e){ console.log("[!] The Spell Book is MISSING!\n"); cb(e)}
else{
console.log("[*] Reading Spell Book")
//since we want to make the contents of .txt accesible :
global.SpellBook = theSpells // global.SpellBook is now shared accross all the code (global scope)
cb()//callBack
}
})
}
//·: Initialize :.
console.log("[+] Time for some Magick!")
ReadSpellBook((e)=>e?console.log(e):console.log(SpellBook))
spellBook.txt
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ
ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ
ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ
ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ
ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ
If you require it from another piece of code, you will see how it prints to the console and initializes by itself.
If you want to achieve a manual initalization, simply remove the 3 last lines (·: Initialize :.) and use reload() :
const magick = require("core.js")
magick.reload((error)=>{ if(error){throw error}else{
//now you know the SpellBook is loaded
console.log(SpellBook.length)
})
I have built some CLIs which were distributed privately, so I believe I can illuminate a bit here.
Let's say your global modules are installed at a directory called $PATH. When your package will be installed on any machine, it will essentially be extracted at that directory.
When you'll fire up someCommand from any terminal, the module.js will be invoked which was kept at $PATH. If you initially kept the template file in the same directory as your package, then it will be present at that location which is local to module.js.
Assuming you edit the template as a string and then want to write it locally to where the user wished / pwd, you just have to use process.cwd() to get the path to that directory. This totally depends on how you code it out.
In case you want to explicitly include the files only in the npm package, then use files attribute of package.json.
As to particularly answer "how can my code file in the npm package locate the path to the globally installed npm folder in which it is located in a way that is guaranteed to work across OSes and is future proof?", that is very very different from the template thingy you were trying to achieve. Anyway, what you're simply asking here is the global path of npm modules. As a fail safe option, use the path returned by require.main.filename within your code to keep that as a reference.
When you npm publish, it packages everything in the folder, excluding things noted in .npmignore. (If you don't have an .npmignore file, it'll dig into .gitignore. See https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package) So in short, yes, you can package the text file into your module. Installing the module (locally or globally) will get the text file into place in a way you expect.
How do you find the text file once it's installed? __dirname gives you the path of the current file ... if you ask early enough. See https://nodejs.org/docs/latest/api/globals.html#globals_dirname (If you use __dirname inside a closure, it may be the path of the enclosing function.) For the near-term of "future", this doesn't look like it'll change, and will work as expected in all conditions -- whether the module is installed locally or globally, and whether others depend on the module or it's a direct install.
So let's assume the text file is in the same directory as the currently running script:
var fs = require('fs');
var path = require('path');
var dir = __dirname;
function runIt(cb) {
var fullPath = path.combine(__dirname, 'myfile.txt');
fs.readFile(fullPath, 'utf8' , function (e,content) {
if (e) {
return cb(e);
}
// content now has the contents of the file
cb(content);
}
}
module.exports = runIt;
Sweet!

Adding Webpack to an existing Angular app

I'm working on an existing (and working) Angular 1.5.5 app. It's very small and has a controller, a directive and a couple of services, all split into individual files.
I'd now like to move to Webpack and make the minimum number of changes to the app to support that. A lot of the Webpack/Angular demos I've found have been about creating a new Angular app with web pack built in from the start, but I don't want to rebuild the existing app, just make whatever changes are necessary to use a webpack-produced bundle. It's also using regular JS, whereas most of the tutorials I've seen are for ES6.
I've got grunt-webpack installed and working, it's creating the bundle.js file and I can see inside the bundle that it's pulling in Angular, Angular-aria and Angular-animate (my module dependencies)
However, when I run the site I see an error:
Uncaught TypeError: angular.module is not a function
My webpack task is as follows:
module.exports = {
dist: {
entry: './Static/js/Ng/app.js',
output: {
path: './Static/dist/js',
filename: 'bundle.js'
}
}
};
As I say, the actual Webpack bundling seems to be working as expected and creates the bundle.js file.
The main entry file (app.js) is as follows:
(function () {
'use strict';
var angular = require('../vendor/angular.js');
var ngAria = require('../vendor/angular-aria.js');
var ngAnimate = require('../vendor/angular-animate.js');
angular.module('app', [ngAria, ngAnimate]);
}());
If I log out the angular variable in this file, it's just an empty object, even though I can see the Angular source in the bundle.
What am I missing?
You probably shadow the global angular property by your local var angular variable. Try this:
(function () {
'use strict';
require('../vendor/angular.js');
require('../vendor/angular-aria.js');
require('../vendor/angular-animate.js');
angular.module('app', [ngAria, ngAnimate]);
}());

How to properly require modules from mocha.opts file

I'm using the expect.js library with my mocha unit tests. Currently, I'm requiring the library on the first line of each file, like this:
var expect = require('expect.js');
describe('something', function () {
it('should pass', function () {
expect(true).to.be(true); // works
});
});
If possible, I'd like to remove the boilerplate require code from the first line of each file, and have my unit tests magically know about expect. I thought I might be able to do this using the mocha.opts file:
--require ./node_modules/expect.js/index.js
But now I get the following error when running my test:
ReferenceError: expect is not defined
This seems to make sense - how can it know that the reference to expect in my tests refers to what is exported by the expect.js library?
The expect library is definitely getting loaded, as if I change the path to something non-existent then mocha says:
"Error: Cannot find module './does-not-exist.js'"
Is there any way to accomplish what I want? I'm running my tests from a gulp task if perhaps that could help.
You are requiring the module properly but as you figured out, the symbols that the module export won't automatically find themselves into the global space. You can remedy this with your own helper module.
Create test/helper.js:
var expect = require("expect.js")
global.expect = expect;
and set your test/mocha.opts to:
--require test/helper
While Louis's answer is spot on, in the end I solved this with a different approach by using karma and the karma-chai plugin:
Install:
npm install karma-chai --save-dev
Configure:
karma.set({
frameworks: ['mocha', 'chai']
// ...
});
Use:
describe('something', function () {
it('should pass', function () {
expect(true).to.be(true); // works
});
});
Thanks to Louis answer and a bit of fiddling around I sorted out my test environment references using mocha.opts. Here is the complete setup.
My project is a legacy JavaScript application with a lot of "plain" js files which I wish to reference both in an html file using script tags and using require for unit testing with mocha.
I am not certain that this is good practice but I am used to Mocha for unit testing in node project and was eager to use the same tool with minimal adaptation.
I found that exporting is easy:
class Foo{...}
class Bar{...}
if (typeof module !== 'undefined') module.exports = { Foo, Bar };
or
class Buzz{...}
if (typeof module !== 'undefined') module.exports = Buzz;
However, trying to use require in all the files was an issue as the browser would complain about variables being already declared even when enclosed in an if block such as:
if (typeof require !== 'undefined') {
var {Foo,Bar} = require('./foobar.js');
}
So I got rid of the require part in the files and set up a mocha.opts file in my test folder with this content. The paths are relative to the root folder:
--require test/mocha.opts.js
mocha.opts.js content. The paths are relative to the location of the file:
global.assert = require('assert');
global.Foo = require("../foobar.js").Foo;
global.Bar = require("../foobar.js").Bar;
global.Buzz = require("../buzz.js");

Using load-grunt-config with Sails.js

Context
I have a few grunt tasks that I've already written, and I'd like to use them with a new project I'm writing in Sails.js.
With Sails.js, you can add additional grunt tasks by adding a JS file to the /tasks/register folder. Before we get to the file I've added, let's talk about the problem.
The Problem
Sails won't lift. Debugger shows:
debug: --------------------------------------------------------
error: ** Grunt :: An error occurred. **
error:
------------------------------------------------------------------------
ERROR
>> Unable to process task.
Warning: Required config property "clean.dev" missing.
The issue in question is obviously with grunt, so then I try grunt build (which automatically runs with sails lift):
Running "clean:dev" (clean) task
Verifying property clean.dev exists in config...ERROR
>> Unable to process task.
Warning: Required config property "clean.dev" missing. Use --force to continue.
From this, I've garnered that this is a path issue. Let's take a look at the file I've added.
/tasks/register/customTask.js
The task here loads load-grunt-config, which is the source of my problems:
module.exports = function(grunt) {
// measures the time each task takes
require('time-grunt')(grunt);
// This require statement below causes my issue
require('load-grunt-config')(grunt, {
config: '../../package.json',
scope: 'devDependencies',
overridePath: require('path').join(process.cwd(), '/asset-library/grunt')
});
grunt.registerTask('customTask', [
'newer:jshint',
'newer:qunit',
'newer:concat',
'newer:cssmin',
'newer:uglify'
]);
};
I had assumed that using overridePath instead of configPath would solve my issue, but alas, it's not quite that simple. Is there some way to make it so that I can use my own custom tasks folder with load-grunt-config like I've done in other projects, or is there some magic conditional I can wrap the require statement around?
I only need it to run with grunt customTask, and not run with grunt * (anything else).
Okay, this was actually pretty easy. All I had to do was change the grunt.registerTask call in my customTask.js file from this:
grunt.registerTask('customTask', [
'newer:jshint',
'newer:qunit',
'newer:concat',
'newer:cssmin',
'newer:uglify'
]);
to this:
grunt.registerTask('customTask', 'My custom tasks', function() {
// The require statement is only run with "grunt customTask" now!
require('load-grunt-config')(grunt, {
config: '../../package.json',
scope: 'devDependencies',
overridePath: require('path').join(process.cwd(), '/asset-library/grunt')
});
grunt.task.run([
'newer:jshint',
'newer:qunit',
'newer:concat',
'newer:cssmin',
'newer:uglify'
]);
});
In case it's not clear, I did have to move the require('load-grunt-config') call, so if you're copy + pasting, make sure to remove the require statement that's outside the grunt.registerTask call.
You can find more information about custom Grunt tasks here.

Pull an HTML file into a TinyTest

TinyTest seems to be concerned only with unit testing; however, may Meteor packages have UI elements, and it would be helpful to pull in a pre-crafted HTML file that exercises a widget. For instance, we might want to transform a <table> into a grid with DataTables.net, then test if the instantiation was correct.
How can external HTML files be used in a TinyTest?
package.js:
Package.onTest(function (api) {
api.use(packageName, where);
api.use(['tinytest', 'http'], where);
// TODO we should just bring in src/test.html - but how to do that with TinyTest?
api.addFiles('src/test.html', where); // this won't magically display the HTML anywhere
api.addFiles('meteor/test.js', where);
});
test.js:
Tinytest.addAsync('Visual check', function (test, done) {
var iconsDropZone = document.createElement('div');
document.body.appendChild(iconsDropZone);
// TODO ideally we'd get src/test.html straight from this repo, but no idea how to do this from TinyTest
HTTP.get('https://rawgit.com/FortAwesome/Font-Awesome/master/src/test.html', function callback(error, result) {
if (error) {
test.fail('Error getting the icons. Do we have an Internet connection to rawgit.com?');
} else {
iconsDropZone.innerHTML = result.content;
test.ok({message: 'Test passed if the icons look OK.'});
}
done();
});
});
I personally think TinyTest is not the right tool for the job! You may get away with finding out how to include the Asset package or writing your own file loader, but you'll soon face the problem of needing to query the DOM in your tests.
Here are some options I can think of:
Option 1:
You can get access to a fully rendered page by using xolvio:webdriver. If you include this package in your onTest block, then you should have access to wdio in your TinyTest tests. I say should as I don't use TinyTest at all but I designed the webdriver package to be usable by any framework. Follow the instructions on the package readme and then do something like this:
browser.
init().
url('https://rawgit.com/FortAwesome/Font-Awesome/master/src/test.html').
getSource(function(err, source) {
// you have a fully rendered source here and can compare to what you like
}).
end();
It's a heavyweight option but might be suitable for you.
Option 2:
If you're willing to move away from TinyTest, another option is to use Jasmine. It supports client unit testing so you can load up the unit that does the visuals and isolate it with a unit test.
Option 3:
You can create a test app around your package. So you would have:
/package
/package/src
/package/example
/package/example/main.html
/package/example/tests
/package/example/tests/driver.js
And now the example directory is a Meteor app. In main.html you would use your package and under tests directory you can use the framework of your choice (jasmine/mocha/cucumber) in combination with webdriver. I like this pattern for package development as you can test the package as it is intended to be used by apps.

Categories