How to include lib to karma tests? - javascript

I'm trying to use external libs in tests. I added all needed links in karma.conf.js and some libs were included without any problem. But for some libs karma sets "undefined" instead of "this" when compiling they, like this:
And of course, then I have errors because of it:
What could I do wrong? Is it possible to include such lib?

In a JavaScript module, this is undefined at the top level (i.e., outside functions). Because of that, Rollup will rewrite any this references to undefined so that the resulting behaviour matches what will happen when modules are natively supported.
To solve it you can use options.context and options.moduleContext to change this behaviour. Like this: context: 'window'

Related

Sharing global between JavaScript files without using modules/exports

I have a self contained JavaScript function in one file, and some Mocha BDD tests in another file that reference it using [nodejs] require(). So in my function under test I export using module.exports. That's all well and good, in the IDE/build.
Now my function under test is actually an external virtual endpoint, which when deployed into a cloud instance, runs standalone inside a JSVM sandbox (Otto) which has no support for exports or modules, and is ES5 based (it does however embed a version of the Underscore library). If I leave the nodejs module definition in there when I deploy to cloud, it kicks off an error at runtime (as Otto doesn't recognise modules). So I want to remove it, and use some vanilla JS mechanism for the linkage back to the Mocha tests and test runner.
So my question is, if I can't use nodejs or requirejs modules, how can I link my Mocha tests in one file to a JS function in another? I had a play with placing a function closure (which most module implementations use) in the file under test, and Otto is happy with this, as its vanilla JS, but any variable with global scope in the file is still not visible from my test file, so there is no linkage.
Any thoughts?
From a quick look at the Otto docs, it looks like Otto only wants whole files and (as you've said) doesn't recogise commonjs modules from node.
If you've got many files I would recommend bundling them into a single file with webpack/browserify/etc, which is how most people convert modules for use in the browser, which similarily doesn't recognise commonjs modules without tooling.
Alternatively, you could convert all the module.exports to simple var declarations, concatenate the files together and hope you don't have a naming collision.
I don't see anything in the docs about having access to a window or global object to hang globals onto, which limits your options
One of my colleague came up with a suggestion to use closure in the file under test which gets deployed into the cloud instance, if you are running under Nodejs, and conditionally do the export. I added the small anonymous closure below to do this, and Otto doesn't complain.
(function () {
if (typeof module != 'undefined') {
module.exports = pdp_virtual_endpoint;
}
}());
Not sure why I didn't think about this earlier :)

linking a separate .js file in Brackets text editor [duplicate]

I get JSLint errors in a file for undeclared functions and variables referenced from another file. Does brackets have a configuration/menu to remove these while keeping other linting errors?
JSLint complains whenever you reference an identifier that it can't see any declaration for in the file. So if you're using global variables/functions that were set by some other file, you'll get these warnings.
You can stop the warnings by individually specifying which undeclared globals you want to allow. To do that, place a directive like this at the top of your file:
/*jslint indent: 4 */
/*global ClassFoo, ClassBar, someFunction */
But of course, it's a pain to list things manually in each file.
Perhaps the best way to clean this up is to use a module loader like RequireJS. Then most your references to other files won't be through globals, and you'll only have to tell JSLint to ignore the few globals needed for RequireJS itself (usually just define).
Using a module loader has other benefits too. It eliminates "dependency spaghetti" by making cross-file dependencies very explicit, and it automatically load modules in proper dependency order. And there are easy tools that automatically concatenate all your modules into one file when you're ready for deployment.

Using TypeScript transpiled code utilizing es6-style classes with imports in a browser without an additional transpilation step?

If I use target:"es5" to transpile TypeScript code that uses es6-style classes & React, my intended entry point (here a file called App.ts) has transpiled code that looks like this:
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = require("react");
var react_router_1 = require("react-router");
When that first line in this snippet gets hit, I get an Uncaught ReferenceError: exports is not defined error. A similar issue is described on TypeScript's GitHub Issues pages here.
The quick answer is that exports will exist in an environment that supports class loading.
commonjs means there's an exports variable available. You can't run commonjs code directly in a browser.
Here's my html wrapper:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="./components/App.js"></script>
</head>
<body>
<div id="root"></div>
<script>
ReactDOM.render(
React.createElement('App', null),
document.getElementById('root')
);
</script>
</body>
</html>
It would appear (1, 2, 3) that the usual response is to put an additional transpilation step between your TypeScript and its release to a client on a browser. Wait, what? I need to transpile the transpiled code? This kinda smells like one of those "I thought the dishwasher washed the dishes" commercials.
Another recommendation is to use a module loading library like RequireJS or SystemJS (1, 2). That makes sense, but I haven't seen an example of adding a module loading lib to TypeScript compiled code for delivery to a browser. And, again, it seems like TypeScript could've intelligently (as in "with minimally duplicated code") included such a lib when it was transpiling.
(It also seems like RequireJS is at least conventionally used with a different syntax with require where you require(['lib1', 'lib2', 'lib3'], function (lib1, lib2, lib3) {...}}) rather than the simpler var lib1 = require('lib1') TypeScript is producing, though perhaps I'm missing something?)
So at least two related questions here:
What's the expected use case for the target="es5" TypeScript transpiled code?
How does one deliver es6 TypeScript code to the browser without transpilation steps beyond what TypeScript can do?
That is, is there a platform:"browser"-style setting I've missed?
If not, should RequireJS work with the code TS has produced? How should that be "bootstrapped"/started?
UPDATE: (Moving my comments from #felixmosh's answer into the question)
I have tried adding "module":"es2015" to my tsconfig.json, but the code started lighting up with errors on lines like this: import Home from './pages/Home'; that read error TS2307: Cannot find module './pages/Home'.
My impression was that the module option defined the way modules are defined in the TypeScript rather than how they'll be transpiled in the resultant JavaScript code. That is, if this option only affected output, why would my untranspiled code throw errors once the module setting is added/changed rather than simply change the resulting JavaScript files' syntax?
#felixmosh also [helpfully] suggests using something like RollUp.js, but that does an end run around loading modules by, well, it says compiles, but it's really just conglomerating "small pieces of code into something larger and more complex". Putting all the modules into one file is sort of cheating. (Though why doesn't TS at least do this conglomeration?)
So +1 to felix & thanks for the help, but I still don't understand why TS stops where it stops -- What's the use case for the code it does produce? Does TypeScript really require a step outside of TS to use es6-style classes in code delivered to browsers?
Why do I care? I've worked with RequireJS based codebases before, and it is nice to have your files broken out in a way that you can debug more easily than a monolithic codebase. But I also don't understand why TS seems like it doesn't produce deployable code in this use case.
If you want to keep the import/export of es6 you should define module:"es2015", by default, it converts those to cjs style that is used within node.
Modern browsers are no supports node's cjs style but es2015 style, so you need to specify that module type, and specify on your script tag an attribute of type="module", something like that:
<script type="module" src="entry-point.js"></script>
Currently there is a native support of modules only in chrome, therefore these days the best practice is to create a bundle from the dependency tree that you have created using imports.
The common boundlers are Webpack & RollUp, you can read their configs in-order to generate bundle that runs in browsers.
Small ref for typescript & webpack config: https://webpack.js.org/guides/typescript/
I see you are getting started with building TypeScript web applications. If so this is my advice:
Transpiling TypeScript to JS is unavoidable,
Don't use RequireJS or SystemJS and instead use a bundler tool like parcel, webpack, rollup, browserify. Particularly I recommend parcel since is super easy and plays nice with TypeScript
With a bundler, get rid of all those those defines() requires() SystemJs.calls() and use just standard JavaScript import declarations (import {foo} form 'bar'). I strongly recommend this too
BTW avoid using require.js, AMD, UMD, SystemJS or similar. Is not a good advice getting started using those. Only use them if really really necessary.
Good luck

How to make sure a module is loaded in NodeJS

This is a problem I faced more than one. Here is an example file structure:
app.js
folder
-- index.js
-- module1.js
-- module2.js
From app.js, the entry point of my application, I require folder/index.js. This file itself is just a loader who requires all the other files in the directory. module1.js and module2.js both define some methods I want to use eventually. They are never directly required by app.js since index.js takes care of that and adds common helper utilities and applies some transformations to these modules.
All works well if I then use some methods defined in those files from app.js after I required them. But the problem comes when a method defined in module2.js wants to use a method defined in method1.js (or vice-versa). Sometimes it will work, sometimes not (in folders with multiple files I didn't get to find out when precisely it works and when it doesn't yet).
If, from module2.js I require ./index.js and then use methods in it defined by module1.js, I sometimes get Cannot read property 'myMethod' of undefined. I assume it has to do with the order the modules are required by index.js, but I can't seem to find a solution to this common problem (other than duplicating code or not using methods of these other modules).
Is there a common solution to this problem? I tried doing something like this :
var modules = require(./index.js);
exports.myMethod = function() {
if(!modules.module1 || !modules.module1.myOtherMethod) {
modules = require('./index.js');
}
modules.module1.myOtherMethod();
};
But it doesn't to do anything, modules.module1 is still undefined.
It just sounds like module should require module2. That's the solution to module1 needing to call methods in module2.
If you're worried about many calls to require, don't. That's standard practice in every programming language I've used (in particular look at the import statements in any Java program. Java is verbose, I know, but this is correct practice.)
It's definitely bad practice to look at code in one module and have no idea where anything comes from, because the require statements are missing.
You have a circular dependency problem. Try moving some of the common functions to a third file and have module1 and module2 require it, or make sure that one of them requires the other in one way only.
Never ever require a file that requires the current file back.

Use Browserify with JavaScript libraries such as Backbone or Underscore?

I know I can install underscore using npm but that's not what I can do in my work environment. I need to be able to download the Underscore.js library and then make it "browserify-compatible".
So let's assume Underscore.js looks something like this:
(function() {
var root = this;
// Rest of the code
}.call(this));
I downloaded that file on my hard drive and saved it as under.js.
My file that requires underscore looks like this:
var underscore = require("./under");
console.log(underscore);
And then I run browserify from the cli.
I have an HTML page called test.html and basically all it does is load the generated bundle.js.
However, the console.log(underscore) line fails - says that underscore is undefined.
What have I tried?
Obviously I added module.exports to the first line - right before the function definition in under.js, and that's how I got the error mentioned above. I also tried the method from this answer , still got the same error.
So, how would I use Browserify to load libraries such as Underscore.js or Backbone without using npm-installed modules?
That's because browserify does not add variables to the global scope. The version you download is identical to the version that you install via NPM.
You need to explicitly attach it to the window to export it to the top level scope.
If you create a file called "expose_underscore.js" and put this in it:
var _ = require('./under');
window._ = _;
Will do it, followed by: browserify expose_underscore.js > bundle.js and then add bundle.js as a <script> tag you will be able to do the following in your console:
HOWEVER, you shouldn't do this if you're using browserify. The point behind it (and Node's version of commonJS) is that you explicitly require it everywhere you need it. So every file you have that needs underscore should import it to a local variable.
Don't worry -- you will still only have one copy loaded.
I typically add my vendor libs like Underscore as script tags. Underscore will attach itself to the global scope, so then you don't need to require it anywhere to use it.
If you do want to use it in a Browserified fashion, verify that you have the correct path in your require statement (browserify requires are relative paths) and move the module.exports statement to the end of the file.

Categories

Resources