Karma - Unexpected token when including an html file - karma-runner

I'm trying to include an simple html file in my karma config file to access the html elements from my javascript files and test this with jasmine in karma.
But I'm getting always an Unexpected token < error. I saw in an webcast that it is possible to include html files, but I don't know why it doesn't works with my configuration?
Thanks in advance

By karma config you have to register every file your want to use in your tests. You can do that by adding patterns to your files array in your config.
A file pattern looks like this:
files: [
{
pattern: 'test/unit/*.js',
watched: true, //watching file modifications for test autorun
included: true, //included as <script src="..."> in the runner html file
served: true //used by tests (the test server should serve it)
}
]
You can use short pattern syntax:
files: [
'test/unit/*.js'
]
This means exactly the same as the previous pattern.
If you don't want to use your file in your test included as <script src="file.js"></script>, then you have use included: false and load the file from within your tests via AJAX. Be aware that you should use relative urls for that, because the domain of the test server can always change...
The pattern order is important too, it uses reverse overriding:
files: [
{pattern: '*.js', included: true}
{pattern: '*.js', included: false}
]
In this case every js file will be included, so the first pattern overrides the second.
For example by html files:
karma config:
files: [
{pattern: 'bootstrap.js', included: true}
{pattern: 'x.html', included: false}
]
bootstrap.js:
var xhr = new XMLHttpRequest();
xhr.open('get', '/base/x.html', false);
xhr.send();
console.log(xhr.status, xhr.responseText); //200, '<html content>'
The URI always has a /base prefix because Karma stores its own index.html and js files on the top level, so it needs a subfolder. If you want to find out what URIs are served, you can use this code:
var servedUris = Object.keys(window.__karma__.files);
I wrote some basic fs stuff to support sync read by Yadda: https://github.com/acuminous/yadda/blob/master/lib/shims/karma-fs.js You might be able to move it to a different project extend it, and use fs instead of AJAX in browser. At least that's how I would do it with Browserify.

I ended up making a simple patch to the lib/middleware/karma.js file in my Karma installation. It uses an extension .literal to denote "just echo the entire file onto the page". I've always found it strange that Karma doesn't have an inbuilt way to do this. My way is certainly not brilliantly-constructed but it might be good enough for you.
With this you can just have in your karma.conf.js:
// ...
files: [
"path/to/my_html.literal", // Echoed directly onto the page
"path/to/other.js", // Normal behaviour
// ...
],
My nested scriptTags function (inside createKarmaMiddleware) just looks like this:
var scriptTags = files.included.map(function(file) {
var filePath = file.path;
var fileExt = path.extname(filePath);
// Include .literal files directly into the body of the HTML.
if (filePath.match(/.literal$/)) {
var fs = require("fs");
return fs.readFileSync(filePath, "utf-8");
}
// ...
The diff is here: https://github.com/amagee/karma/commit/c09346a71fc27c94cc212a2bd88b23def19ec3a4

You need use the html2js preprocessor (or the ng-html2js preprocessor if using AngularJS). See the preprocessor description for how it works.
Since Karma 0.10, the html2js preprocessor is shipped with Karma and configured by default:
module.exports = function(config) {
config.set({
files: [
'templates/*.html'
],
preprocessors: {
'**/*.html': ['html2js']
}
});
};
Then you can access the html content as JS string:
var elm = $(__html__['templates/x.html'])
The error you are getting means that the HTML files are not preprocessed. By default, all HTML files under the basePath are preprocessed, so maybe your HTML files are somewhere else, in which case you need to put them in the preprocessors config explicitly. Share your karma.conf.js if you need more help.

Related

How to use stage 3 syntax in svelte/sapper?

I want to use class property and private fields in my sapper project. Apparently they have to be preprocessed by babel right now.
I tried to add the corresponding babel plugins to rollup.config.js, only to realize a few things.
the babel rollup plugin is only used in legacy mode.
the server part doesn't use babel at all.
I tried to add the babel rollup plugin to the end of server plugins like this,
babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
runtimeHelpers: true,
exclude: ['node_modules/#babel/**'],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-private-methods',
],
}),
But it doesn't seem to take effect at all.
I also added it to the client plugins (before the legacy entry), but it complained about I needed to add #babel/plugin-syntax-dynamic-import, so looks like babel has to recognize the whole syntax in order to preprocess, and I don't really want to compile dynamic import for modern browsers.
How do I enable the use of esnext syntax in sapper?
You would need to preprocess the contents of <script>, using the preprocess option in rollup-plugin-svelte:
plugins: [
svelte({
// ...
preprocess: {
script: ({ content }) => {
return transformWithBabel(content);
}
},
// ...
})
]
In an ideal world we'd have a ready-made preprocessor plugin for doing this; as it is, the transformWithBabel function is left as an exercise to the reader for now. Essentially it would involve import * as babel from '#babel/core' and using the Babel API directly, which I guarantee will be lots of fun.
Note that #babel/plugin-syntax-dynamic-import doesn't compile dynamic import, it only allows Babel to parse it. Without it, Babel can't generate a valid AST from the code inside <script>.

How do I write a Webpack plugin to generate index.js files on demand?

In general, I want to know how to do code-generation/fabrication in a Webpack plugin on demand. I want to generate contents for files that do not exist when they are "required."
Specifically, I want a plugin that, when I require a directory, automatically requires all files in that directory (recursively).
For example, suppose we have the directory structure:
foo
bar.js
baz.js
main.js
And main.js has:
var foo = require("./foo");
// ...
I want webpack to automatically generate foo/index.js:
module.exports = {
bar: require("./bar"),
baz: require("./baz")
};
I've read most of the webpack docs. github.com/webpack/docs/wiki/How-to-write-a-plugin has an example of generating assets. However, I can't find an example of how to generate an asset on demand. It seems this should be a Resolver, but resolvers seem to only output file paths, not file contents.
Actually for your use case:
Specifically, I want a plugin that, when I require a directory, automatically requires all files in that directory (recursively).
you don't need a plugin. See How to load all files in a subdirectories using webpack without require statements
Doing code-generation/fabrication on demand can be done in JavaScript quite easily, why would you restrict your code generation specifically to only applied, when "required" by WebPack?
As NodeJS itself will look for an index.js, if you require a directory, you can quite easily generate arbitrary exports:
//index.js generating dynamic exports
var time = new Date();
var dynamicExport = {
staticFn : function() {
console.log('Time is:', time);
}
}
//dynamically create a function as a property in dynamicExport
//here you could add some file processing logic that is requiring stuff on demand and export it accordingly
dynamicExport['dyn' + time.getDay()] = function() {
console.log('Take this Java!');
}
module.exports = dynamicExport;

How to dictate a global variable in specific karma test block

I'm trying to write a test in Karma for a react/webpack application that tests conditionals depending on global variable __CLIENT__ being false or not.
How do I go about making it true for one it block, and then false for another? I tried setting global.__CLIENT__, but the console.logs from my module return true regardless of what I try to set it to in my tests.
How do I do this, hopefully in a way that keeps just one file and can be dictated in each test case. That avoids the karma.conf....
Probably won't help you now but maybe for others:
you need to create global.js file for example and within karma webpack files add it at the start of "files"
files: [
'./tests/global-variables.js',
{pattern: 'src/**/*-spec.js', watch: false}
],
And within global-variables.js:
var global = {
___CLIENT___: "some data"
}
Good luck!

Setting the --in-source-map uglify2 config option in r.js build config file

I wanted to use the --in-source-map option that is available in UglifyJS2 for consuming a source map file and outputting a new one along with the compressed js, thereby performing a multi-level source mapping. I am using r.js to do the minification of the javascript files and so I saw there was a way to define config values that will be passed on to the UglifyJS2. Here is a sample showing how it is done in the r.js build file:
uglify2: {
//Example of a specialized config. If you are fine
//with the default options, no need to specify
//any of these properties.
output: {
beautify: true
},
compress: {
sequences: false,
global_defs: {
DEBUG: false
}
},
warnings: true,
mangle: false
},
Obvously r.js has its own way of structuring the config options and I was not able to figure out how to set the --in-source-map option following this structure. I tried putting the following statement in the output element or the compress element or even outside, next to the warnings config option.
in-source-map: sample.map
I have also tried putting quotes around the file name. Unfortunately none of the methods worked. Can anyone help me figure out this problem? Can it also be the case that this option is not supported in r.js?

sails.js setup: How to make a node module available across the sails project (controller / model, etc)?

I just getting started with SailsJS as my first web framework on Node. Let's say I wanna add MomentJS in and use across the app. How to set it up?
you can use the bootstrap.js (in config/)
like:
module.exports.bootstrap = function (cb) {
sails.moment = require('moment');
cb();
};
in all Sails-Files you can use
sails.moment()
now.
If you're trying to include your node_modules into the client side, such as jQuery, AngularJS or one of the various many font libraries, then you can npm install them as normal, but just to be sure in sails you edit your tasks/config/copy.js and add a new block, example:
grunt.config.set('copy', {
dev: {
files: [{
expand:true,
cwd: './node_modules/font-awesome/fonts',
src: ['**/*'],
dest: '.tmp/public/fonts'
}
}
});
LESS can be #imported like normal without being copied around. Other assets will need to be copied as above. If you're using the sails linker then don't forget to add your JS paths to tasks/pipeline.js too (if necessary).
You can read more here:
http://ash.zi.vc/sails/2016/02/02/including-client-side-node-modules-in-my-sails-application/
It's not directly obvious how to sync npm modules to the web accessible directories.
SailsJS is no different to any other NodeJS app. So on top of your (say) Controller.js file, you do
var m = require("moment");
And you're good to go. #mdunisch's method will obviously let you use the moment package throughout your app, without having to do "require" in each file.