mochajs referenceerror when testing function not in test file - javascript

I have a mochajs test file and a javascript code file in setup as below:
/js/module/codefile.js
/js/test/testfile.js
The codefile.js contains some javascript functions eg:
function addNumbers(a, b){
return a+b;
}
the testfile.js calls functions in the codefile to test them:
describe("Add numbers test", function() {
it("checks valid result", function() {
var a = 2;
var b = 1;
var result = addNumbers(a, b);
expect(result).to.equal(3);
});
});
From the command line I cd to the js folder (parent of test and module directories) then I run mocha and get the following error: ReferenceError: addNumbers is not defined at Context <anonymous> (test/testfile.js).
I can't actually see how it could be defined as how can mocha know where this function is comming from? (NB I am using client side JS so can't use import, and havent see any way to specificy (in Mocha or Karma or JS in general) where functions are defined as you would in Python or Java). Any ideas on how I can get simple unit tests running in mocha?
I initially tried getting mocha to run in WebStorm but gave up after similar errors.

Well, the mocha command is a nodejs program. This means that you can use Nodejs's module system to load your function.
function addNumbers(a, b){
return a+b;
}
module.exports = addNumbers;
and in your test file you will have
var addNumbers = require('../module/codefile.js');
describe("Add numbers test", function() {
it("checks valid result", function() {
var a = 2;
var b = 1;
var result = addNumbers(a, b);
expect(result).toEqual(3);
});
});
However, you said that you are using your code on the front-end. Well in this case you simply check if the module object exists. If it exists that means that your file is required by mocha for unit testing.
function addNumbers(a, b){
return a+b;
}
if (module && module.exports) {
module.exports = addNumbers;
}
If you want to get rid of this nasty if's, you can bundle your modules using browserify. Browserify helps you code on the front-end using the Nodejs's module system. So your code will remain the same.

Related

How does Mocha handle imports?

I'm writing some test scripts and noticed that when I import a specific module and execute a specific function within that module, Mocha runs the entire module plus the one I have specified.
In test.js
const myModule = require('../someModule');
describe('Test',function(){
it('Should run a function in mu module',funciton(){
myModule.someFunction(test);
};
}
In myModule.js
module.exports = { someFunction };
function someFunction(someInput){
return true;
}
Now say I include a console log within my module as shown below:
module.exports = { someFunction };
console.log('Loging inside the module');
function someFunction(someInput){
return true;
}
When I run my Mocha test it will run my funciton but will also run my console.log
Can someone please explain this?

ES6 + Babel + Gulp + Browserify, Uncaught ReferenceError [duplicate]

I am new to nodejs and browserify. I started with this link .
I have file main.js which contains this code
var unique = require('uniq');
var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];
this.LogData =function(){
console.log(unique(data));
};
Now I Install the uniq module with npm:
npm install uniq
Then I bundle up all the required modules starting at main.js into a single file called bundle.js with the browserify command:
browserify main.js -o bundle.js
The generated file looks like this:
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var unique = require('uniq');
var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];
this.LogData =function(){
console.log(unique(data));
};
},{"uniq":2}],2:[function(require,module,exports){
"use strict"
function unique_pred(list, compare) {
var ptr = 1
, len = list.length
, a=list[0], b=list[0]
for(var i=1; i<len; ++i) {
b = a
a = list[i]
if(compare(a, b)) {
if(i === ptr) {
ptr++
continue
}
list[ptr++] = a
}
}
list.length = ptr
return list
}
function unique_eq(list) {
var ptr = 1
, len = list.length
, a=list[0], b = list[0]
for(var i=1; i<len; ++i, b=a) {
b = a
a = list[i]
if(a !== b) {
if(i === ptr) {
ptr++
continue
}
list[ptr++] = a
}
}
list.length = ptr
return list
}
function unique(list, compare, sorted) {
if(list.length === 0) {
return []
}
if(compare) {
if(!sorted) {
list.sort(compare)
}
return unique_pred(list, compare)
}
if(!sorted) {
list.sort()
}
return unique_eq(list)
}
module.exports = unique
},{}]},{},[1])
After including bundle.js file into my index.htm page, how do I call logData function ??
The key part of bundling standalone modules with Browserify is the --s option. It exposes whatever you export from your module using node's module.exports as a global variable. The file can then be included in a <script> tag.
You only need to do this if for some reason you need that global variable to be exposed. In my case the client needed a standalone module that could be included in web pages without them needing to worry about this Browserify business.
Here's an example where we use the --s option with an argument of module:
browserify index.js --s module > dist/module.js
This will expose our module as a global variable named module.
Source.
Update:
Thanks to #fotinakis. Make sure you're passing --standalone your-module-name. If you forget that --standalone takes an argument, Browserify might silently generate an empty module since it couldn't find it.
Hope this saves you some time.
By default, browserify doesn't let you access the modules from outside of the browserified code – if you want to call code in a browserified module, you're supposed to browserify your code together with the module. See http://browserify.org/ for examples of that.
Of course, you could also explicitly make your method accessible from outside like this:
window.LogData =function(){
console.log(unique(data));
};
Then you could call LogData() from anywhere else on the page.
#Matas Vaitkevicius's answer with Browserify's standalone option is correct (#thejh's answer using the window global variable also works, but as others have noted, it pollutes the global namespace so it's not ideal). I wanted to add a little more detail on how to use the standalone option.
In the source script that you want to bundle, make sure to expose the functions you want to call via module.exports. In the client script, you can call these exposed functions via <bundle-name>.<func-name>. Here's an example:
My source file src/script.js will have this:
module.exports = {myFunc: func};
My browserify command will look something like this:
browserify src/script.js --standalone myBundle > dist/bundle.js
And my client script dist/client.js will load the bundled script
<script src="bundle.js"></script>
and then call the exposed function like this:
<script>myBundle.myFunc();</script>
There's no need to require the bundle name in the client script before calling the exposed functions, e.g. <script src="bundle.js"></script><script>var bundled = require("myBundle"); bundled.myFunc();</script> isn't necessary and won't work.
In fact, just like all functions bundled by browserify without standalone mode, the require function won't be available outside of the bundled script. Browserify allows you to use some Node functions client-side, but only in the bundled script itself; it's not meant to create a standalone module you can import and use anywhere client-side, which is why we have to go to all this extra trouble just to call a single function outside of its bundled context.
I just read through the answers and seems like nobody mentioned the use of the global variable scope? Which is usefull if you want to use the same code in node.js and in the browser.
class Test
{
constructor()
{
}
}
global.TestClass = Test;
Then you can access the TestClass anywhere.
<script src="bundle.js"></script>
<script>
var test = new TestClass(); // Enjoy!
</script>
Note: The TestClass then becomes available everywhere. Which is the same as using the window variable.
Additionally you can create a decorator that exposes a class to the global scope. Which is really nice but makes it hard to track where a variable is defined.
Read README.md of browserify about --standalone parameter
or google "browserify umd"
Minimal runnable example
This is basically the same as: https://stackoverflow.com/a/43215928/895245 but with concrete files that will allow you to just run and easily reproduce it yourself.
This code is also available at: https://github.com/cirosantilli/browserify-hello-world
index.js
const uniq = require('uniq');
function myfunc() {
return uniq([1, 2, 2, 3]).join(' ');
}
exports.myfunc = myfunc;
index.html
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Browserify hello world</title>
</head>
<body>
<div id="container">
</body>
</div>
<script src="out.js"></script>
<script>
document.getElementById('container').innerHTML = browserify_hello_world.myfunc();
</script>
</html>
Node.js usage:
#!/usr/bin/env node
const browserify_hello_world = require('./index.js');
console.log(browserify_hello_world.myfunc());
Generate out.js for browser usage:
npx browserify --outfile out.js --standalone browserify_hello_world index.js
Both the browser and the command line show the expected output:
1 2 3
Tested with Browserify 16.5.0, Node.js v10.15.1, Chromium 78, Ubuntu 19.10.
To have your function available from both the HTML and from server-side node:
main.js:
var unique = require('uniq');
function myFunction() {
var data = [1, 2, 2, 4, 3];
return unique(data).toString();
}
console.log ( myFunction() );
// When browserified - we can't call myFunction() from the HTML, so we'll externalize myExtFunction()
// On the server-side "window" is undef. so we hide it.
if (typeof window !== 'undefined') {
window.myExtFunction = function() {
return myFunction();
}
}
main.html:
<html>
<head>
<script type='text/javascript' src="bundle.js"></script>
<head>
<body>
Result: <span id="demo"></span>
<script>document.getElementById("demo").innerHTML = myExtFunction();</script>
</body>
</html>
Run:
npm install uniq
browserify main.js > bundle.js
and you should get same results when opening main.html in a browser as when running
node main.js
Whole concept is about wrapping.
1.) Alternative - Object "this"
for this purpose I'll assume you have "only 1 script for whole app {{app_name}}" and "1 function {{function_name}}"
add function {{function_name}}
function {{function_name}}(param) { ... }
to object this
this.{{function_name}} = function(param) { ... }
then you have to name that object to be available - you will do it add param "standalone with name" like others advised
so if you use "watchify" with "browserify" use this
var b = browserify({
...
standalone: '{{app_name}}'
});
or command line
browserify index.js --standalone {{app_name}} > index-bundle.js
then you can call the function directly
{{app_name}}.{{function_name}}(param);
window.{{app_name}}.{{function_name}}(param);
2.) Alternative - Object "window"
add function {{function_name}}
function {{function_name}}(param) { ... }
to object window
window.{{function_name}} = function(param) { ... }
then you can call the function directly
{{function_name}}(param);
window.{{function_name}}(param);
You have a few options:
Let plugin browserify-bridge auto-export the modules to a generated entry module. This is helpful for SDK projects or situations where you don't have to manually keep up with what is exported.
Follow a pseudo-namespace pattern for roll-up exposure:
First, arrange your library like this, taking advantage of index look-ups on folders:
/src
--entry.js
--/helpers
--- index.js
--- someHelper.js
--/providers
--- index.js
--- someProvider.js
...
With this pattern, you define entry like this:
exports.Helpers = require('./helpers');
exports.Providers = require('./providers');
...
Notice the require automatically loads the index.js from each respective sub-folder
In your subfolders, you can just include a similar manifest of the available modules in that context:
exports.SomeHelper = require('./someHelper');
This pattern scales really well and allows for contextual (folder by folder) tracking of what to include in the rolled-up api.
You can also call your function from the html file like this:
main.js: (will be in bundle.js)
window.onload = function () {
document.getElementById('build-file')
.addEventListener('click', buildFile)
}
function buildFile() {
...
}
index.html:
<button id="build-file"">Build file</button>
window.LogData =function(data){
return unique(data);
};
Call the function simply by LogData(data)
This is just a slight modification to thejh's answer but important one
For debugging purposes I added this line to my code.js:
window.e = function(data) {eval(data);};
Then I could run anything even outside the bundle.
e("anything();");

Importing other .js files in Buster.js tests

I'm making my first attempt at Javascript testing, with Buster.js
I've followed the instructions at the Buster site to run "states the obvious" test. However, I haven't been able to import any of my existing .js files into the tests.
For instance, I have a file js/testLibrary.js, containing:
function addTwo(inp) {
return inp+2;
}
and a file test/first-test.js, containing:
// Node.js tests
var buster = require("buster");
var testLibrary = require("../js/testLibrary.js");
var assert = buster.referee.assert;
buster.testCase("A module", {
"Test The Library": function() {
result = addTwo(3);
console.log(result);
assert(true, 'a message for you');
}
});
Running buster-test gives:
Error: A module Test The Library
ReferenceError: addTwo is not defined
[...]
Replacing result = addTwo(3); with result = testLibrary.addTwo(3); gives:
Error: A module Test The Library
TypeError: Object #<Object> has no method 'addTwo'
[...]
I'm probably missing something really basic, but at present, I'm completely stumped. Can someone point me in the right direction?
That is because you are not exporting this function from the module.
Take a look at that:
http://nodejs.org/api/modules.html#modules_module_exports

Is there a Java classpath-like feature for server-side Javascript?

When using JUnit and Maven in Java, one can have separate property files for src/main and src/test. This allows different configuration for code and tests, having Maven to manage the resources by using Java classpath.
Is there a similar way in Javascript code run by Node.js? I use Mocha for unit-testing and Grunt for task management.
Code example for script.js:
var config = require('./config/dev/app.js');
exports.getFileName = function() {
return config.fileName; // returns 'code.txt'
}
What I need is to make the script.js use different config file when being required in a test.js unit test like this:
var assert = require('assert');
var s = require('./script.js');
describe('Test', function () {
it('should use different config file', function() {
assert.equal('test.txt', s.getFileName());
});
});
Is there a way to use different configuration ./config/test/app.js in the script.js without having to alter the code of script.js? What I really try to avoid is to adjust the code to support unit tests. Instead, I want to achieve similar functionality such as mentioned Java classpath.
Please try this code.
Script.js
var config;
if(process.env.dev===true){
config = require('./config/dev/config.js');
}
if(process.env.prod===true){
config = require('./config/prod/config.js');
}
exports.getFileName = function() {
return config.fileName; // returns 'code.txt'
}
test.js
//set the environment here
process.env.dev = true;
var assert = require('assert');
var s = require('./script.js');
describe('Test', function () {
it('should use different config file', function() {
assert.equal('test.txt', s.getFileName());
});
});
I have not found any elegant solution out there on the web so I have implemented and published my own.
Check it out here: https://npmjs.org/package/app-config
Using the app-config plugin, only the script.js needs to get changed this way:
var config = require('app-config').app;
exports.getFileName = function() {
return config.fileName; // returns 'code.txt'
}
The app needs to be run this way for example
NODE_ENV=dev node script.js
NODE_ENV=unitTest mocha test.js
Depending on the NODE_ENV environmental variable, the right set of configuration files will be loaded by the app-config plugin.

Why do I see "define not defined" when running a Mocha test with RequireJS?

I am trying to understand how to develop stand-alone Javascript code. I want to write Javscript code with tests and modules, running from the command line. So I have installed node.js and npm along with the libraries requirejs, underscore, and mocha.
My directory structure looks like this:
> tree .
.
├── node_modules
├── src
│   └── utils.js
└── test
└── utils.js
where src/utils.js is a little module that I am writing, with the following code:
> cat src/utils.js
define(['underscore'], function () {
"use strict";
if ('function' !== typeof Object.beget) {
Object.beget = function (o) {
var f = function () {
};
f.prototype = o;
return new f();
};
}
});
and test/utils.js is the test:
> cat test/utils.js
var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});
requirejs(['../src/utils'], function(utils) {
suite('utils', function() {
test('should always work', function() {
assert.equal(1, 1);
})
})
});
which I then try to run from the top level directory (so mocha sees the test directory):
> mocha
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Calling node's require("../src/utils") failed with error: ReferenceError: define is not defined
at /.../node_modules/requirejs/bin/r.js:2276:27
at Function.execCb (/.../node_modules/requirejs/bin/r.js:1872:25)
at execManager (/.../node_modules/requirejs/bin/r.js:541:31)
...
So my questions are:
Is this the correct way to structure code?
Why is my test not running?
What is the best way to learn this kind of thing? I am having a hard time finding good examples with Google.
Thanks...
[sorry - momentarily posted results from wrong code; fixed now]
PS I am using requirejs because I also want to run this code (or some of it) from a browser, later.
Update / Solution
Something that is not in the answers below is that I needed to use mocha -u tdd for the test style above. Here is the final test (which also requires assert) and its use:
> cat test/utils.js
var requirejs = require('requirejs');
requirejs.config({nodeRequire: require});
requirejs(['../src/utils', 'assert'], function(utils, assert) {
suite('utils', function() {
test('should always work', function() {
assert.equal(1, 1);
})
})
});
> mocha -u tdd
.
✔ 1 tests complete (1ms)
The reason your test isn't running is because src/utils.js is not a valid Node.js library.
According to the RequireJS documentation, in order to co-exist with Node.js and the CommonJS require standard, you need to add a bit of boilerplate to the top of your src/utils.js file so RequireJS's define function is loaded.
However, since RequireJS was designed to be able to require "classic" web browser-oriented source code, I tend to use the following pattern with my Node.js libraries that I also want running in the browser:
if(typeof require != 'undefined') {
// Require server-side-specific modules
}
// Insert code here
if(typeof module != 'undefined') {
module.exports = whateverImExporting;
}
This has the advantage of not requiring an extra library for other Node.js users and generally works well with RequireJS on the client.
Once you get your code running in Node.js, you can start testing. I personally still prefer expresso over mocha, even though its the successor test framework.
The Mocha documentation is lacking on how to set this stuff up, and it's perplexing to figure out because of all the magic tricks it does under the hood.
I found the keys to getting browser files using require.js to work in Mocha under Node: Mocha has to have the files added to its suites with addFile:
mocha.addFile('lib/tests/Main_spec_node');
And second, use beforeEach with the optional callback to load your modules asynchronously:
describe('Testing "Other"', function(done){
var Other;
beforeEach(function(done){
requirejs(['lib/Other'], function(_File){
Other = _File;
done(); // #1 Other Suite will run after this is called
});
});
describe('#1 Other Suite:', function(){
it('Other.test', function(){
chai.expect(Other.test).to.equal(true);
});
});
});
I created a bootstrap for how to get this all working: https://github.com/clubajax/mocha-bootstrap
You are trying to run JS modules designed for browsers (AMD), but in the backend it might not work (as modules are loaded the commonjs way). Because of this, you will face two issues:
define is not defined
0 tests run
In the browserdefine will be defined. It will be set when you require something with requirejs. But nodejs loads modules the commonjs way. define in this case is not defined. But it will be defined when we require with requirejs!
This means that now we are requiring code asynchronously, and it brings the second problem, a problem with async execution.
https://github.com/mochajs/mocha/issues/362
Here is a full working example.
Look that I had to configure requirejs (amd) to load the modules, we are not using require (node/commonjs) to load our modules.
> cat $PROJECT_HOME/test/test.js
var requirejs = require('requirejs');
var path = require('path')
var project_directory = path.resolve(__dirname, '..')
requirejs.config({
nodeRequire: require,
paths: {
'widget': project_directory + '/src/js/some/widget'
}
});
describe("Mocha needs one test in order to wait on requirejs tests", function() {
it('should wait for other tests', function(){
require('assert').ok(true);
});
});
requirejs(['widget/viewModel', 'assert'], function(model, assert){
describe('MyViewModel', function() {
it("should be 4 when 2", function () {
assert.equal(model.square(2),4)
})
});
})
And for the module that you want to test:
> cat $PROJECT_HOME/src/js/some/widget/viewModel.js
define(["knockout"], function (ko) {
function VideModel() {
var self = this;
self.square = function(n){
return n*n;
}
}
return new VideModel();
})
Just in case David's answer was not clear enough, I just needed to add this:
if (typeof define !== 'function') {
var define = require('amdefine')(module);
}
To the top of the js file where I use define, as described in RequireJS docs ("Building node modules with AMD or RequireJS") and in the same folder add the amdefine package:
npm install amdefine
This creates the node_modules folder with the amdefine module inside.
I don't use requirejs so I'm not sure what that syntax looks like, but this is what I do to run code both within node and the browser:
For imports, determine if we are running in node or the browser:
var root = typeof exports !== "undefined" && exports !== null ? exports : window;
Then we can grab any dependencies correctly (they will either be available already if in the browser or we use require):
var foo = root.foo;
if (!foo && (typeof require !== 'undefined')) {
foo = require('./foo');
}
var Bar = function() {
// do something with foo
}
And then any functionality that needs to be used by other files, we export it to root:
root.bar = Bar;
As for examples, GitHub is a great source. Just go and check out the code for your favorite library to see how they did it :) I used mocha to test a javascript library that can be used in both the browser and node. The code is available at https://github.com/bunkat/later.

Categories

Resources