Require file on runtime & unit test issue - javascript

I use require.js to load files at runtime like following
This is working as expected when I run the file in the right context(I mean when the call is coming from the right path.)
module1.js
define(["otherModule"], function(otherModule) {
working!!!
....
Now I want to create some unit test to this file (module1) from
other context (from folder of tests which is found in diffrent location in the project) and I get error
require.js:145 Uncaught Error: Script error for: otherModule
Since it tries to run the get on this path during the Unit Test
which is located in diffrent project structure ...
https://app/path1/path2/path3/otherModule.js
And in runtime which works (from different context) it find it in the path
https://app/path1/path2/path3/path4/path5/otherModule.js
There is additional path4 & path5 in the request that works,
How should I solve it to work on both cases (UT/Runtime) ?
http://requirejs.org

I think you should be able to get it working by applying a RequireJS configuration file, so that the module name is abstracted from its path:
E.g. in the test context, call something like this as initialization step:
require.config({
baseUrl: "/path1/path2/path3"
});
Alternatively, you can also remap single modules like so (this can also be used to inject a different implementation of a specific module for testing etc.):
require.config({
paths: {
"otherModule": "/path1/path2/path3/otherModule"
}
});
See here: http://requirejs.org/docs/api.html#config

Related

Run intern functional tests against static web app on localhost

I have a static web app. Html, JS (requirejs modules), and some CSS.
Currently the 'serverUrl' is being set through a property module, which i can 'require' and use values from it:
define({
serverUrl: 'https://some.api/path/'
})
I have Intern setup to run functional tests in the browser using src/index.html as the entry point.
return this.remote
.get(require.toUrl('src/index.html'))
Given the serverUrl is hardcoded in the properties file, I'm trying to find a way to run tests against the web app where serverUrl is pointing to localhost:1234/someFakeServer so I can test error scenarios and such.
I've trawled the web but can't find anyone doing anything remotely similar to me, which makes me think I'm doing something obviously wrong. There's solutions for NODE apps, using config modules, but because I never 'start' my web app - its just files, these won't work for me.
Some solutions I've thought about, but can't figure out how to achieve:
Intern is proxying the files on :9000, so if I can somehow 'build' an application with another properties file pointing to localhost, all is good. But I've no idea how to do that - I've looked at webpack and similar but they don't seem to do what I want.
I've looked at Interns 'Setup' config item, which allows a function to be run before the tests are started - so I thought about modifying the properties file in there, but seems too hacky and not sure how I'd put it back...
Assuming the properties file is accessible to Intern, you could simply have Intern load the properties file and pull the server URL out of it. If you have multiple potential properties files, the one being used can be set in the Intern config or passed in as a custom command line variable (which would be used to set a property in the Intern config). The test module can get the name of the properties file from Intern's config and then load the relevant file. It could look something like this (untested):
// intern config
define({
// ...
propertiesFile: 'whatever',
})
// test file
define([ 'intern', ... ], function (intern, ...) {
registerSuite({
// ...
'a test': function () {
var did = this.async();
var remote = this.remote;
require([
intern.config.propertiesFile
], dfd.callback(function (props) {
return remote.get(props.url)
.otherStuff
});
}
});
});

How can I make Mocha load a helper.js file that defines global hooks or utilities?

I have a file named test/helper.js that I use to run Mocha tests on my Node.js apps. My tests structure looks like:
test/
test/helper.js # global before/after
test/api/sometest.spec.js
test/models/somemodel.spec.js
... more here
The file helper.js has to be loaded because it contains global hooks for my test suite. When I run Mocha to execute the whole test suite like this:
mocha --recursive test/
the helper.js file is loaded before my tests and my before hook gets executed as expected.
However, when I run just one specific test, helper.js is not loaded before the test. This is how I run it:
mocha test/api/sometest.spec.js
No global before called, not even a console.log('I WAS HERE');.
So how can I get Mocha to always load my helper.js file?
Mocha does not have any notion of a special file named helper.js that it would load before other files.
What you are trying to do works when you run mocha --recursive because of the order in which Mocha happens to load your files. Because helper.js is one level higher than the other files, it is loaded first. When you specify an individual file to Mocha, then Mocha just loads this file and, as you discovered, your helper.js file is not loaded at all.
So what you want to do is load a file such that it will set top level ("global") hooks (e.g. before, after, etc.). Options:
You could use Mocha programmatically and feed it the files in the order you want.
You could force yourself to always specify your helper file on the command line first before you list any other file. (I would not do this, but it is possible.)
Another option would be to organize your suite like I've detailed in this answer. Basically, you have one "top level" file that loads the rest of the suite into it. With this method you'd lose the ability of running Mocha on individual files, but you could use --grep to select what is being run.
You cannot use the -r option. It loads a module before running the suite but, unfortunately, the loaded module does not have access to any of the testing interface that Mocha makes available to your tests so it cannot set hooks.
What I do is create a test/test_helper.js file, which exports all the helpers I create:
// test/test_helper.js
module.exports = {
MyHelper: require('./helpers/MyHelper')
}
Then I require the helper on any test I need to use it:
// test/spec/MySpec.js
var helper = require('../test_helper');
// Or if you need just "MyHelper"
var myHelper = require('../test_helper').MyHelper;
describe('MySpec', function () {
// Tests here...
});
I prefer the above approach because its easy to understand and flexible. You can see it in action here in my demo: https://github.com/paulredmond/karma-browserify-demo/tree/master/test
First, I would definitely use mocha.opts so that you don't have to include the options you want every time. As pointed out, one option is to use --grep, but I am not a huge fan of that personally. It required you name everything in an overly simplistic way. If the before hook is NOT async you can use --require in your mocha.opts. e.g.
#mocha.opts
--recursive
--require test/helpers.js
It sounds like this wouldn't work for you because you want global after hook as well. What I have done is I just call the full test suite every time, but if I am in the middle of deving and only want to test one suite, or even one specific test, I use the exclusivity feature, only https://mochajs.org/#exclusive-tests. You can make it it.only('... or describe.only('... If you do this it looks through all tests and sets up exactly like your full test harness would, but then only executes the test or suite you have specified.
Now you can include those global hooks no problem. #Louis mentions that your helpers.js are loading in the proper order only coincidently. That is not true. If you place any hooks outside of a describe block, it automatically becomes a global hook. This can be accomplished by either putting it in its own file
// helpers.js
before(function() { console.log('testing...'); });
or within a test file
// some.spec.js
before(function() { console.log('testing...'); });
describe('Something', function() {
it('will be tested', function() {
...
});
});
Obviously, I think putting it in its own file is cleaner. (I called it hooks.js). Point is, this is not a result of the order in which files were loaded.
Just one gotcha that might be obvious to other but I struggled with briefly -- hooks not placed in a describe block are ALL global. They are not directory specific. So if you copy helpers.js into a sub-directory of tests, the before and after hook will now fire twice. Also, if you place a beforeEach hook in there, it will fire before every single test, not just those tests in that directory.
Anyway, I know this post is a bit old, but hopefully this will help others having similar issues.
Late addition to the answer:-
Mocha (v7.0.0 as of writing) support specifying file as an option:-
As per the docs
--file Specify file(s) to be loaded prior to root suite
execution
.mocharc.json
{
"watch-files": [
"test/**/*.js"
],
"recursive": true,
"file": "test/setup"
}
./test/setup.js
const request = require('supertest');
const app = require('../app'); // express app
global.request = request(app);
A Worthy Mention:
I found that the above setup loaded all .js files anyway, probably because of the mocha config extension which is set to js by default. Since I had the convention of naming all tests file with .spec.js, I can ignore other files by adding "ignore": ["test/**/!(*.spec.js)"]
I came to this question after trying all sorts of things to get my tests to connect once to a database before subsequently running a bunch of crud tests on my models.
Then I found mocha-prepare which solved my problems.
In your helper.js file you can just define a prepare function.
prepare(done => {
console.log('do something asynchronously here')
done()
}, done => {
console.log('asynchronously clean up after here')
done()
})
works a treat.
In our project, we are using helpers somewhat like this:
clientHelper = require("../../../utils/clientHelper")
You need to configure relative path of your helper properly.
And then calling it like this:
clientHelper.setCompanyId(clientId)

Include dependencies in Karma test file for Angular app?

I am trying to get started with Karma tests, adding them to an existing Angular app.
This is my main app definition file:
angular
.module('myApp', [
'ngRoute',
'moduleAdherence'
]);
This is my controller file:
angular
.module('moduleAdherence', [])
.controller('AdherenceCtrl', ['$scope', function ($scope) {
$scope.awesomeThings = [1,2,3,4];
}]);
This is my first stab at a file:
describe('Controller: AdherenceCtrl', function () {
beforeEach(module('myApp'));
var MainCtrl,
scope;
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('AdherenceCtrl', {
$scope: scope
});
}));
it('should attach a list of awesomeThings to the scope', function () {
expect(scope.awesomeThings.length).toBe(4);
});
});
When I try to run this with grunt test, it fails with the following error:
Uncaught Error: [$injector:nomod] Module 'd3' is not available!
You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies
as the second argument.
http://errors.angularjs.org/1.2.0/$injector/nomod?p0=d3
at /Users/me/Dropbox/projects/myapp/app/bower_components/angular/angular.js:1498
I don't understand this, because this controller does not Use D3. I do use D3 elsewhere in the app, in a directive, but I'm not registering it with the module (I use the external D3 file).
Why is Karma noticing D3? Shouldn't it be able to test this controller without D3?
In karma configuration file (karma.conf.js) you need to define all libraries.
etc.
// list of files / patterns to load in the browser
files: [
'app/lib/angular/angular.js',
'app/lib/angular-route/angular-route.js',
'test/lib/angular-mocks.js',
'app/app.js',
'app/controllers/*.js',
'app/services/*.js',
'app/*',
'test/spec/**/*.js'
],
Had a similar problem and my solution (inspired someway by #danba comment) was to load the scripts in the files in the exact same order as they were loaded in the index.html.
In my case globbing patterns like app/scripts/**/*.js were causing trouble to karma which constantly threw errors.
Maybe not the most elegant solution to copy all the scripts definitions but worked in the end so my test could finally get back running. Hope it helps.
EDIT: Editing this because today I probably (and hopefully) got the hang of what was going wrong here. So it seems that Karma does not like globbing patterns when the same module is defined in one file and used in many different files. Let's say that your folder structure is like this:
Suppose that in AuthService.js you have your module definition for all your services in that folder, so that that file starts with:
angular.module('myApp.services', [
'myApp.urls',
'ngCookies'
])
Then in all the other files you're just attaching other services to that same module. In the picture tokenService.js would start with:
angular.module('myApp.services');
If everything stays this way everything will probably work. But if by any chance I define the module the other way round, so the module definition is not anymore in the first file of that folder but on another that Karma reads after AuthService then it will throw an error and refuse to complete the tests.
Solution 1
A solution might be to put the module definition in its own file, starting with an underscore. Finally, let all the siblings files depend on that one(s). So the above folder structure should be:
Solution 2
Another - probably better - solution is to mark the files where the modules are defined with a common suffix/extension for example service.module.js while the files that depend on it could be named normally like authService.js, tokenService.js.
The Karma configuration at that point will become something like:
// list of files / patterns to load in the browser
files: [
'app/lib/angular/angular.js',
'test/lib/angular-mocks.js',
'app/app.js',
'app/**/*.module.js', // <-- first the module definitions...
'app/**/*.js', // <-- ..then all the other files
'test/spec/**/*.js'
],
This way karma will load the modules definitions first and then those file that depend on them.
I also had the same issue, in my case problem occured because there were several files per module which is a bad practice since we can point to not initialized module. Solved this by including just one file per module.
Always load the non minified version of angular into karma.
it will display errors and help you better to find out what to change.
In your case, it's the order of the files being loaded by karma.
Check your index.html that you don't include something by a script tag like.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5angular-resource.js"
All your Javascript file need to be in your karma.config.js
Here's a simple solution that worked for me, based on above Solution #1 by #Nobita, AND #danba's comment.
In karma.conf.js, explicitly load the prerequisite file above the pattern that pulls in the rest:
files: [
...
'app/module.js',
'app/*.js'
]
Karma does not seem to mind that the pattern also matches 'module.js'.

Require.js optimizer and variables in paths

I have a problem getting r.js to work the way we need it to.
I have the following problem: We have 2 domains (e.g. foo.de and bar.de) and different environments. Depending on what environment and what domain they are running on they need to load a different file from their origin servers. My initial solution was this:
// channelDomain and environmentPath get defined above this script
require.config({
paths: {
'fooscript': channelDomain+environmentPath
}
}
Testing this in the browser unoptimized works exactly as it should but the nightly build complained with:
[Error: Error: The config in mainConfigFile /absolute/path/app/public/js/main.js
cannot be used because it cannot be evaluated correctly while running in the
optimizer. Try only using a config that is also valid JSON, or do not use
mainConfigFile and instead copy the config values needed into a build file or
command line arguments given to the optimizer.
Source error from parsing: /absolute/path/app/public/js/main.js: ReferenceError:
channelDomain is not defined
I tried doing lots of things but I'm running out of ideas. I tried doing the empty: thing in the build file but that didn't work either. I'd be glad if someone could point me into the right direction.
Use two require.config in the same file. The optimizer will only read the first one, as James says here https://github.com/jrburke/r.js/issues/270#issuecomment-13112859, and it will work in the browser after optimization.
So at the end you will have something like this in main.js:
require.config({
//only configurations needed for the transpiler's optimization
});
require.config({
paths: {
'fooscript': channelDomain+environmentPath
}
});

Is it possible to set not module *.js file as a dependency using require.js

We do not use require.js for implementing modules on js source, but I want to use it for tests. And there is a problem: I couldn't implement raw *.js file as a dependency for other modules. Is it possible?
I mean: load some *.js file and modules after it (to test it).
How define works
I use require.js for both implementation and tests. You can load any JavaScript file as a dependency before the execution of the module function using define.
define(["test/myTest.js", "test/anotherTest.js"], function(test1, test2) {
// perform your tests
});
How to use requirejs with asyncTests
You can also load code after the dependencies are loaded inside the module function using require. I use it with QUnit. Here is an example from my code.
First, make sure QUnit test runner is stopped by default (this will be similar with other test frameworks). This way, you can define when tests are going to run (that is after you loaded the relevant code).
QUnit.config.autostart = false
Second, you define your test as a module. The module loads the dependencies, then defines the tests, then loads the code to be tested. This will only be necessary when the code is self-executing and can not be load beforehand (in which case you could just go with define and be done with it). Here is my example using the Chaplin library (written in CoffeeScript).
define(['chaplin'], function(chaplin) {
asyncTest("publish startup complete event", function() {
chaplin.mediator.subscribe("startup~complete", function() {
ok(true, "startup~complete event fired");
});
return requirejs(['modules/startup/startup'], function() {
start();
});
});
});
The important part is the last requirejs call. It loads the code to be tested after the tests are defined.
dynamically loading dependencies
EDIT: Responding to comment
Assuming there exists a module called config that contains the configuration data. I am also assuming a certain format, so if your format is different you may make some minor changes. The principles holds true though.
define(["config"], function(config) {
// assuming config.modules is an array of all development modules,
// config.devPath is the base bath to development modules,
requirejs(
config.modules.map(function(module){
return config.devPath + module
})
, function() {
// all modules loaded, now go on
// however, no reference to modules left, so need to work with `arguments` array
});
});
However, you should know you lose the reference to your modules in the callback function.

Categories

Resources