Access module.exports from external file - javascript

I would like to view the contacts of a function from an external file.
MarionetteJS app.js file:
module.exports = functionToAccess = (function(superClass) {
extend(functionToAccess, superClass);
function functionToAccess() {
this.doSomething = bind(this.doSomething, this);
return functionToAccess.__super__.constructor.apply(this, arguments);
}
functionToAccess.prototype.defaults = {
someProperty: 'some value',
anotherProperty: 'another value',
canAccessThis: false,
wouldIlikeTo: true
};
[...]
return functionToAccess;
})(Wrapper);
In an external PHP file, I am trying to alert or console.log the contents of anything from the above file, but preferably the functionToAccess function.
External JS script inside PHP file:
// Using the RequireJS CDN here resolves 'require is undefined'
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js" type="text/javascript"></script>
var testFileLoad = require(['path/to/app'], function() {
});
console.log(testFileLoad);
This returns a localRequire function. How can I instead return functionToAccess?

You need to declare a variable in the callback function, which is where you will have access to your path/to/app code. Try something like this:
require(['path/to/app'], function(functionToAccess) {
functionToAccess(); // is available here
});

Related

Object is not defined when stubbing with Jasmine

I am very new to Jasmine. I am intending to use it for with vanilla javascript project. The initial configuration was a breeze but I am receiving object not defined error while using spyOn.
I have downloaded the version 3.4.0 Jasmine Release Page and added the files 'as is' to my project. I then have changed jasmine.json file accordingly and see the all the example tests passing. However when try spyOn on a private object, I am getting undefined error,
if (typeof (DCA) == 'undefined') {
DCA = {
__namespace: true
};
}
DCA.Audit = {
//this function needs to be tested
callAuditLogAction: function (parameters) {
//Get an error saying D365 is not defined
D365.API.ExecuteAction("bu_AuditReadAccess", parameters,
function (result) { },
function (error) {
if (error != undefined && error.message != undefined) {
D365.Utility.alertDialog('An error occurred while trying to execute the Action. The response from server is:\n' + error.message);
}
}
);
}
}
and my spec class
describe('Audit', function(){
var audit;
beforeEach(function(){
audit = DCA.Audit;
})
describe('When calling Audit log function', function(){
beforeEach(function(){
})
it('Should call Execute Action', function(){
var D365 = {
API : {
ExecuteAction : function(){
console.log('called');
}
}
}
// expectation is console log with say hello
spyOn(D365.API, 'ExecuteAction').and.callFake(() => console.log('hello'));
var params = audit.constructActionParameters("logicalName", "someId", 'someId');
audit.callAuditLogAction(params);
})
})
})
As you can see my spec class does not know about actual D365 object. I was hoping to stub the D365 object without having to inject it. Do I need to stub out whole 365 library and link it to my test runner html?
I got it working after some pondering. So the library containing D365 should still need to be added to my test runner html file. after that I can fake the method call like below,
it('Should call Execute Action', function(){
spyOn(D365.API, 'ExecuteAction').and.callFake(() => console.log('hello'));
var params = audit.constructActionParameters("logicalName", "someId", 'someId');
audit.callAuditLogAction(params);
})
it is now working.

Packaging JavaScript Functions

I'm working to create a shared package of JavaScript functions. At this time, I'm trying to use them like this:
/app/index.js
const myPackage = require('../myPackage');
myPackage.function1();
myPackage.myScope.function2();
The above successfully loads myPackage. However, when I attempt to run function1, I receive an error that says: "TypeError: myPackage.function1 is not a function". My code in the "package" is organized like this:
/myPackage
index.js
root
function1.js
myScope
function2.js
The code looks like this:
index.js
require('./root/function1.js');
require('./myScope/function2.js');
function1.js
exports.function1 = function() {
console.log("Doing stuff in function1");
}
function2.js
exports.function2 = function() {
console.log("Doing stuff for function2");
}
I could understand function2 not working because, there's nothing putting it in myScope, which I don't know how to do. However, I don't understand why function1 isn't running. What am I doing wrong?
To elaborate bergi's answer, you need to have the following in your index.js file:
// file: index.js
exports.function1 = require('./root/function1.js').function1;
exports.myScope2 = {
function2: require('./myScope/function2.js').function2,
};
Because require('./root/function1.js') == exports object in function1.js. So if you
have multiple functions in your function1.js, you have to go like this:
// file: index.js
exports.function1 = require('./root/function1.js').function1;
exports.function11 = require('./root/function1.js').function11;
exports.function111 = require('./root/function1.js').function111;
...
A shortcut of that can be:
// file: index.js
Object.assign(exports, require('./root/function1.js'));
On the other hand: you can set the exports object to be your function:
// file: function1.js
module.exports = function() {
console.log("Doing stuff in function1");
}
Then you can have the following in your index.js file:
// file: index.js
exports.function1 = require('./root/function1.js');
exports.myScope2 = {
function2: require('./myScope/function2.js'),
};
Here require('./root/function1.js') == function1 from function1.js. Hope that explains
the issue.
Your index.js doesn't export anything. You will have to do
Object.assign(exports, require('./root/function1.js'));
exports.myScope = require('./myScope/function2.js');
Or maybe better have your function1.js and function2.js modules export the function itself (module.exports = function() { … };) instead of creating a property, then use
exports.function1 = require('./root/function1.js');
exports.myScope = {
function2: require('./myScope/function2.js'),
};

How do I use SystemJS Builder buildStatic?

I am trying to do a simple example using SystemJS Builder by building a SFX bundle, but I cannot get it to work. I cannot figure out how to call exported functions that were in the bundle. Am I missing something obvious?
index.html
<html>
<head>
<script src="app.bundle.js"></script>
<script>
all();
</script>
</head>
<body>
</body>
</html>
gulpfile.js
var path = require('path');
var gulp = require('gulp');
var Builder = require('systemjs-builder');
gulp.task('default', function(cb) {
var builder = new Builder('.', './jspm.config.js');
builder.buildStatic('src/app.js', 'dist/app.bundle.js').then(cb());
});
app.js
import { hello } from 'src/app/hello';
export function all() {
hello();
}
hello.js
export function hello() {
console.log("hello");
};
When I try to load index.html, it loads the app.bundle.js file correctly, but I can't seem to figure out how to call all() and I get Uncaught ReferenceError: all is not defined in Chrome.
The bundle file looks reasonable, I think:
// ... Some minified SystemJS content...
(["1"], [], function($__System) {
$__System.register("2", [], function (_export) {
"use strict";
_export("hello", hello);
function hello() {
console.log("hello");
}
return {
setters: [],
execute: function () {
;
}
};
});
$__System.register('1', ['2'], function (_export) {
'use strict';
var hello;
_export('all', all);
function all() {
hello();
}
return {
setters: [function (_) {
hello = _.hello;
}],
execute: function () {}
};
});
})
(function(factory) {
if (typeof define == 'function' && define.amd)
define([], factory);
else if (typeof module == 'object' && module.exports && typeof require == 'function')
module.exports = factory();
else
factory();
});
Exporting the all function does not mean it's accessible by the global object (window in the browser).
It just means that it can be imported using a module loaded (e.g. systemjs).
When creating a self-executing bundle you should just load the bundle file in the browser (as you already do) and do all bootstrapping also in the js files that are going to be in the bundle.
If you really need to access the all function in that script tag you must add the function to the global object.
in your app.js
window.all = all;
But i don't think this is the way its intended to be used.

Loading external file from Karma/Jasmine test

I'm trying to accomplish a Jasmine test (using Karma and IntelliJ 13) to validate JSON files. Ideally, my test would simply load a JSON file into a data object, then let me parse through to check for valid formatting and data. I don't need to validate functions before or after, nor do I need to test against a server.
My basic setup is like this:
it("should load an external file", function(){
var asyncCallComplete, result,
_this = this;
// asyncCallComplete is set to true when the ajax call is complete
asyncCallComplete = false;
// result stores the result of the successful ajax call
result = null;
// SECTION 1 - call asynchronous function
runs(function() {
return $.ajax('/test/config.json', {
type: 'GET',
success: function(data) {
asyncCallComplete = true;
result = data;
},
error: function() {
asyncCallComplete = true;
}
});
});
// SECTION 2 - wait for the asynchronous call to complete
waitsFor(function() {
return asyncCallComplete !== false;
}, "async to complete");
// SECTION 3 - perform tests
return runs(function() {
return expect(result).not.toBeNull();
});
}
The problem is that no matter what path I use, I get a 404 error and the file won't load. I've tried loading an external JSON result from a remote server using this test service:
http://date.jsontest.com/
And this works.
My test file is named /test/mySpec.js and my karma.conf.js file is on the root. I have moved around the JSON file to all of these locations with no luck. What am I doing wrong?
UPDATE WITH ANSWER:
Per the answer below, I added this to my karma.conf.js:
// fixtures
{ pattern: 'test/*.json',
watched: true,
served: true,
included: false
}
Then, I wrote my test this way:
var json:any;
it("should load a fixture", function () {
jasmine.getFixtures().fixturesPath = "base/test/"
var f = readFixtures("registration.json");
json = JSON.parse(f);
expect(json).toBeDefined();
})
it("should have a title", function () {
expect(json.title).toNotBe(null);
})
etc...
And it passes.
Are you serving the JSON file via karma.config.js?
You can serve JSON files via fixture:
files: [
// angular
'angular.min.js',
'angular-route.js',
'angular-mocks.js',
// jasmine jquery helper
'jquery-1.10.2.min.js',
'jasmine-jquery.js',
// app
'../../public/js/app.js',
// tests
'*-spec.js',
// JSON fixture
{ pattern: '/test/*.json',
watched: true,
served: true,
included: false }
],
Serving JSON via the fixture is the easiest but because of our setup we couldn't do that easily so I wrote an alternative helper function:
Install
bower install karma-read-json
Usage
Put karma-read-json.js in your Karma files, Example:
files = [
...
'bower_components/karma-read-json/karma-read-json.js',
...
]
Make sure your JSON is being served by Karma, Example:
files = [
...
{pattern: 'json/**/*.json', included: false},
...
]
Use the readJSON function in your tests. Example:
var valid_respond = readJSON('json/foobar.json');
$httpBackend.whenGET(/.*/).respond(valid_respond);
If you are trying to load a HTML file and want to avoid using jasmine-jquery, you may take advantage of the karma-ng-html2js-preprocessor.
In your karma.conf.js :
// generate js files from html templates
preprocessors: {
'resources/*.html': 'ng-html2js'
},
files: [
...
'resources/*.html'
],
plugins: [
...
'karma-ng-html2js-preprocessor'
],
In your jasmine spec :
beforeEach(module('resources/fragment.html'));
var $templateCache;
beforeEach(inject(function (_$templateCache_) {
$templateCache = _$templateCache_;
}));
describe('some test', function () {
it('should do something', function () {
// --> load the fragment.html content from the template cache <--
var fragment = $templateCache.get('resources/fragment.html');
expect(fragment).toBe(...);
});
});
Have you tried simply requiring the json file and storing it as a global variable in your test?
I'm developing an Angular2 project right now (using the Angular CLI), and with this setup it works:
// On the very beginning of the file
let mockConfig = require('./test/config.json');

method won't trigger when using requireJS

I have some issue with some requireJS setup. I posted a question before but the scope of the latest changed now.
I have some
requirejs.config({
paths: {
'tmpl': 'vendor/upload/tmpl.min'
}
});
require({
paths: {
'videoupload': 'vendor/upload/jquery.ui.videoupload'
}
}, ['js/main_video.js'], function (App) {
App.initial_video_upload();
});
and finally in main_video.js :
define(['tmpl', 'videoupload'], function () {
function initial_video_upload(tmpl, videoupload) {
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
This code works perfectly if I don't use requireJS (loading classically each file). In fact, when this code is triggered, I keep on having a message Uncaught TypeError: Object [object Object] has no method 'tmpl', this method is defined in tmpl.min.js. And this method is invoked in vendor/upload/jquery.ui.videoupload, as so
$.widget('videoupload', {
//...
_renderVideo: function (video) {
this._templateElement().tmpl({
id: video.id,
name: video.title
}).appendTo(this._listElement()).find(
this.options['delete-selector']
);
return this;
},
//...
How can I manage that ? (I had earlier an error time out message for this method tmpl, but it disappeared now, so I don't think this is it)
In the configuration object, the path is not the full path to the JS file BUT the path to the directory containing the JS file, so you may want to do something like this in the main_video.js file:
requirejs.config({
paths:{
'upload': 'vendor/upload'
}
});
define(['upload/tmpl','upload/jquery_videoupload'],function(tmpl, videoupload) {
function initial_video_upload(tmpl,videoupload){
'use strict';
$('#videoupload').videoupload({
//...some code
});
}
return{
initial_video_upload: initial_video_upload
}
}
);
And in the main app:
requirejs.config({
paths:{
'js': 'path/to/your/js/folder'
}
});
require(['js/main_video'], function(App) {
App.initial_video_upload();
});
There's a problem in the questions code, so this:
define(['tmpl', 'videoupload'], function () {
should become this:
define(['tmpl', 'videoupload'], function (tmpl, videoupload) {
The first one doesn't expose loaded dependencies to local variables of closure function, so that's might be a problem, although it's not very clear if it's the only one, from the provided code.
I would also like to mention, that it's not a good thing to use multiple requre.js configs, if you're intended to use optimizer. The configs will be overwritten by the last one, so it's a good idea actually to have only one config for the whole project.
Like this:
requirejs.config({
paths: {
'tmpl': 'vendor/upload/tmpl.min',
'videoupload': 'vendor/upload/jquery.ui.videoupload'
}
});

Categories

Resources