OpenEDX RequireJS error when overriding factory with AWS setting - requirejs

I'm having an issue with OpenEDX when deploying to a server as opposed to devstack. On devstack the override works perfectly, although on dev it fails to load.
I am overriding the student_account/account_settings.html as well as student_account/views/account_settings_factory.js and student_account/views/account_settings_view.js.
When loading the account section of the LMS, the following error is produced on production, but not on dev:
Mismatched anonymous define() module: function(gettext, $, _, Backbone, Logger, UserAccountModel, UserPreferencesModel,
AccountSettingsFieldViews, AccountSettingsView, StringUtils) {
return function(
fieldsData,
ordersHistoryData,
authData,
passwordResetSupportUrl,
userAccountsApiUrl,
userPreferencesApiUrl,
accountUserId,
platformName,
contactEmail,
allowEmailChange
) {
var accountSettingsElement, userAccountModel, userPreferencesModel, aboutSectionsData,
accountsSectionData, ordersSectionData, accountSettingsView, showAccountSettingsPage,
showLoadingError, orderNumber, getUserField, userFields, countryDropdownField, emailFieldView;
accountSettingsElement = $('.wrapper-account-settings');
userAccountModel = new UserAccountModel();
userAccountModel.…
The define in my factory looks like the following:
(function(define, undefined) {
'use strict';
define([
'gettext', 'jquery', 'underscore', 'backbone', 'logger',
'js/student_account/models/user_account_model',
'js/student_account/models/user_preferences_model',
'js/student_account/views/account_settings_fields',
'academy/js/student_account/views/account_settings_view',
'edx-ui-toolkit/js/utils/string-utils'
], function(gettext, $, _, Backbone, Logger, UserAccountModel, UserPreferencesModel,
AccountSettingsFieldViews, AccountSettingsView, StringUtils) {
As stated, works flawlessly in development, but production throws the error. Hopefully someone knows a solution to this issue.

The issue was because in the AWS paver settings for some reason the custom factory is expected to be optimized, which can be done by overriding the build.js file for the lms. This issue isn't really clear anywhere in the docs and was therefore a bit difficult to reach this conclusion.

Related

Using aws-sdk.js with require.js in a browser

I'm trying to figure out how to use the browser-based aws-sdk.js with require.js when building a web app.
If I try to build a class and include aws-sdk in the require.js define, once I try to create an instance and reference the AWS class, it says it is undefined.
For example, I have a function that checks to see if the credentials are an instance of AWS.Credentials and if not, it tries to initialize it with an STS token it retrieves via Rest.
The problem is, the code dies on the if(this.credentials instanceof AWS.Credentials) saying AWS is undefined. It even dies on my simple check of the needsRefresh.
This is what my define looks like - I'll include the 'needsRefresh' wrapper for an example of the sort of thing that is throwing the Undefined error:
define(['require','aws-sdk','jquery'],
function (require, AWS, $) {
// Aws helper class
function AwsHelper() { };
AwsHelper.prototype = {
credentials: null,
tokenNeedsRefresh: function () {
//////////////////////////////////////////////////////////////////
// errors out on the following line with: //
// TypeError: Cannot read property 'Credentials' of undefined //
//////////////////////////////////////////////////////////////////
if(this.credentials instanceof AWS.Credentials) {
return this.credentials.needsRefresh();
} else return true;
}
};
return AwsHelper;
}
);
I also tried the following format at the top of the file:
define(function (require) {
var AWS = require("aws-sdk"),
$ = require("jquery");
/* .. */
If I remove all onLoad references to the refresh code running, it will load and I can create an instance. But as soon as I call any function that references the AWS class, it dies.
How do I make sure that AWS class definition is still in global space once an instance is spawned?
Dunno what difference the paths will make (it's finding and loading the code just fine - I can see AWS Class in namespace in the debugger as it's loading but it's not in the namespace on the function call), but added on request:
requirejs.config({
baseUrl: '/js',
paths: {
lib: 'lib',
ImageUploader: 'ImageUploader'
}
});
I decided to try to play with this again and seemed to have figured out how I was going about it incorrectly. I have yet to integrate it back into my existing code setup, but I think I have a working solution.
The thing I was doing wrong was I was trying to set up the AWS class so I could load it as a module (thus why I tried wrapping it as the require.js suggested).
Playing with it this time around, I noticed something I hadn't before. I had an AWS that was undefined in the local scope and an other AWS that held the class definition in the global scope. So it was trying to specify AWS in my define that was creating the local 'null' version:
define(
["jquery","aws-sdk","dropzone","app/MyUtilities"],
function ($, AWS, Dropzone, MyUtilities) {
"use strict";
function MyClass() {};
return MyClass;
}
);
jquery and dropzone have whatever is needed to make sure they load that way, but aws-sdk seems to do some of it's own asynchronous loading. Thus the scope variable in the function is undefined.
Technically, it seems the only thing I needed defined as a module in the function wrapper is my own utilities module. So by switching it to:
define(
["app/MyUtilities","jquery","aws-sdk","dropzone"],
function (MyUtilities) {
"use strict";
function MyClass() {};
return MyClass;
}
);
... it seems $ and jquery are defined as needed, Dropzone is defined as needed and AWS is defined as needed. (and I don't get my errors when accessing the static AWS.config or AWS.Credentials definitions as I did before)

Durandal optimization with Gulp and Gulp-Durandal not working

We are building an application with Durandal which is quite big at the moment and we currently looking into bundling all JS files located in the App folder into a main-built.js file. Pretty basic and usual stuff I guess.
I'm using Gulp with the Gulp-Durandal extension. Here our gulpfile :
var gulp = require('gulp');
var durandal = require('gulp-durandal');
gulp.task('build-portal', function () {
durandal({
baseDir: 'app',
main: 'main.js',
output: 'main-built.js',
almond: false,
minify: false
}).pipe(gulp.dest('app'));
});
And here's a snippet of our main.js file
require.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions'
},
shim: {
},
waitSeconds: 0
});
define('jquery', [], function () { return jQuery; });
define('knockout', [], function () { return ko; });
define('ga', function () { return ga; });
define(
["require", "exports", "durandal/app", "durandal/viewLocator", "durandal/system", "plugins/router", "services/logger", "modules/knockout.extensions", "modules/knockout.validation.custom"],
function (require, exports, __app__, __viewLocator__, __system__, __router__, __logger__, __koExtensions__, __koValidationCustom__) {
var app = __app__;
var viewLocator = __viewLocator__;
var system = __system__;
var router = __router__;
As you can see in the gulpfile, we do not want to use Almond but RequireJs instead, for some reasons almond isn't workin with our project and anyhow, we prefer RequireJs whether its bigger than almond at the end. That's where it look to brake. Running the command to build the main-built.js file took sometime but at the end I get the file built with everything in it.
The problem is that when I try to load the application, it is stuck to the loading screen. It doesn't go any further and there's no errors at all in the browser console.
I created a new project on the side to test if our code was somewhat faulty and found that it might not. You can found that project here :
https://github.com/maroy1986/DurandalGulpBundling
If I build that project with almond option to true, everything works fine but if I switch almound off to tell gulp to use RequireJs, I got the same behavior as our app. You got stuck at the loading screen, without any errors.
So here I am, I do read a lot on the subject but didn't found anything to solve this. Hope someone here already encounter these behavior and have a solution to share.
Thanks!
I had the same requirement and issue. It seems require.js wasn't calling the main module which will startup the Durandal app, that's why it's stuck in the loading screen. I was able to resolve it by implicitly calling the main module:
gulp.task("durandal", function() {
return durandal({
baseDir: "app",
main: "main.js",
output: "main-built.js",
almond: false,
minify: true,
rjsConfigAdapter: function(config) {
//Tell requirejs to load the "main" module
config.insertRequire = ["main"];
return config;
}
})
.pipe(gulp.dest("dist"));
});
I downloaded your project and tried building it with the latest versions of gulp and durandal. Initially it didn't build and gave me the following error:
TypeError: Cannot read property 'normalize' of undefined
This is a problem with the text-plugin of rjs and you can solve this by adding the following to your gulp-file (next to the almond, minify, output... properties):
rjsConfigAdapter : function(rjsConfig){
rjsConfig.deps = ['text'];
return rjsConfig;
}
Once I did that, the build finished and I could build with or without minify, almond and require and the application works fine.

intern custom reporter dependency is loaded as a different module instance

I thought I'd post this as I stumbled around for a while before noticing what's going on. I have a test suite that uses CouchDB as its logging / recording database. I discovered you can write custom reporters in intern, so thought I could move a lot of my manual 'recordSuccess()'/'recordFailure()' calls out of my test script, and into a custom reporter responding to test pass and fail events.
My main test script still wants to do a little couchdb interaction, so I factored out the couchdb connection and reporting functions into a module, then tried to use that module from both the main test script, and the custom reporter module.
I find that the couchdb helper module is instantiated twice. This goes against the expectation that AMD/RequireJS require() will only execute a module once, and cache the result for use the next time the module is required. If I put a 'debugger' statement in its main body of code, it is clearly executed twice. The upshot, for me, is that the couchdb reference is undefined when called from the reporter.
Directory structure:
runTest.js # helper script to run intern test from this dir
src/MainTest.js
src/CouchHelper.js
src/CouchDBReporter.js
src/intern.js # intern config
runTest.js
node node_modules/.bin/intern-client config=src/intern suites=mypackage/WINTest --envConfig=src/test/dev.json
i.e. MainTest.js:
define([ 'CouchHelper' ], function (CouchHelper) {
.. test startup ..
CouchHelper.connect(username, password, etc);
CouchDBReporter.js:
define([ 'CouchHelper' ], function (CouchHelper) {
return {
'/test/fail': function (test) {
// Presume the couchdb is connected at this point
CouchHelper.recordFailure(test);
}
}
intern.js:
... blah blah ..
loader: {
// Packages that should be registered with the loader in each testing environment
packages: [
'node',
'nedb',
'nodemailer',
{ 'mypackage', 'src' }
],
reporters: [ 'console', 'src/CouchDBReporter' ]
CouchHelper.js:
define([
'intern/dojo/node!node-couchdb'
], function (Couchdb) {
debugger; // this is hit twice
var instance = 0;
function CouchHelper() {
this.couchdb = undefined;
this.instance = instance++;
console.log('Created instance ' + this.instance);
}
CouchHelper.prototype = {
connect: function () { this.couchdb = Couchdb.connect(blah); },
recordFailure: function (test) { this.couchdb.insert(blah); }
}
}
On startup, the console logs:
Created instance 0
Created instance 0
When the reporter calls recordFailure, it calls into a different instance of CouchHelper than the MainTest.js file called connect() on .. so this.couchdb is undefined, and the script crashes. I can call recordSuccess/recordFailure from in MainTest.js just fine, and this.couchdb is valid in CouchHelper, but from the CouchDBReporter the CouchHelper instance is clearly different.
Is this behaviour expected, and if so, what's the recommended way to share data and resources between the main test code, and code in a custom reporter? I see that in 3.0 the reporters config can take an object which might help mitigate this problem, but it feels like one would have to instantiate the reporter programatically rather than define it in config.
Nick
As suggested by Colin, the path to the answer lay in my loader map configuration. This means that my intern.js file, referenced as config on the command line, has a loader section where one can define the mappings of paths to AMD module (see https://theintern.github.io/intern/#option-loader). Typically I just define a list of package names, for example I know my test requires nedb, nodemailer, and my own src package:
loader: {
packages: [ 'node', 'nedb', 'nodemailer', 'src' ]
}
For some reason, I had defined my src package as being available by the name mypackage:
loader: {
packages: [ 'node', 'nedb', 'nodemailer',
{ name: 'mypackage', location: 'src' }
]
}
I had no good reason to do this. I then specified my custom reporter be loaded by intern using the 'src' package name:
intern.js:
reporters: [ 'console', 'src/CouchDBReporter' ]
And, here's the tricky bit, I referenced my helper module, CouchHelper, in two different ways, but both times by using a relative module path ./CouchHelper:
MainTest.js:
require([
'./CouchHelper',
...
], ...
CouchDBReporter.js:
require([
'./CouchHelper',
...
], ...
And on the command line, you guessed it, specified the test to be run as mypackage/MainTest.js. This conflicts with my specification of src/CouchDBReporter in intern.js's reporter section.
The result was that mypackage/MainTest.js required ./CouchHelper which resolved as mypackage/CouchHelper, and src/CouchDBReporter required ./CouchHelper, which resolved as src/CouchHelper. This loaded the CouchHelper module code twice, working around the usual guarantee with an AMD style loader that a module is only ever loaded once.
It has certainly been a good lesson in AMD module paths, and one implication of using relative paths.

How to generate multiple reports with mocha?

I want to have the following reports:
coverage
spec
xunit
all running in a single mocha execution from my grunt
Currently - I have to run the tests 3 times, each time to generate a different report(!).
So I use grunt-mocha-test with 2 configuration where only the reporter is different (once xunit-file and once spec).
And then I have grunt-mocha-istanbul that runs the tests yet again,and generates the coverage report.
I tried using
{
options: {
reporters : ['xunit-file', 'spec']
}
}
for grunt-mocha-test at least to bring it down to 2, but that doesn't work as well.
reading grunt-mocha-istanbul documentation, i can't seem to find any info about reporter configuration.
How can I resolve this?
Maybe this can help:
https://github.com/glenjamin/mocha-multi
AFAIK this is not supported in Mocha yet, but it is on its way:
https://github.com/mochajs/mocha/pull/1360
Hope this helps,
György
I ran into the same problem recently, and found nothing after looking around SO as well as GH issues. It seems that topic of officially supporting multiple reporters are getting postponed over and over.
Having said that having a custom solution is quite easy, assuming the reporters you want to combine already exist. What I did is to create a small and naive custom reporter, and used the reporter in .mocharc.js config.
// junit-spec-reporter.js
const mocha = require("mocha");
const JUnit = require("mocha-junit-reporter");
const Spec = mocha.reporters.Spec;
const Base = mocha.reporters.Base;
function JunitSpecReporter(runner, options) {
Base.call(this, runner, options);
this._junitReporter = new JUnit(runner, options);
this._specReporter = new Spec(runner, options);
return this;
}
JunitSpecReporter.prototype.__proto__ = Base.prototype;
module.exports = JunitSpecReporter;
// .mocharc.js
module.exports = {
reporter: './junit-spec-reporter.js',
reporterOptions: {
mochaFile: './tests-results/results.xml'
}
};
The example above shows how to use both spec and junit reporter.
More info on custom reporter: https://mochajs.org/api/tutorial-custom-reporter.html
Note that this is just a proof of concept and can be made prettier and more robust using more generic approach (and TypeScript).
Update 14.9.2021
I have created a utility package for this: https://www.npmjs.com/package/#netatwork/mocha-utils
For simultaneously reporting for spec and x-unit, there's also an NPM package called spec-xunit-file.
In grunt:
grunt.initConfig({
mochaTest: {
test: {
options: {
reporter: 'spec-xunit-file',
...
},
...
}
}
...
});

r.js optimizer resolving configured deps files

I try requireJS optimizer to pack all my scripts into one file and I cannot overcome one issue.
My requireJs configuration is
var require = {
// 'baseUrl': 'static/scripts',
'paths': {
'external': 'global/external'
},
'waitSeconds': 2,
// 'enforceDefine': true,
'deps': ['external/jquery-1.7.2'],
'config': {
}
};
requireJs will load everything that is in deps before it starts loading any other scripts. since jquery wraps itself with define function and with name jquery I can load it to my scripts simply by calling
var var $ = require('jquery');
This works great when code is not optimized.
PROBLEM:
when I run r.js (with node - but this I think is irrelevant) optimizer prints error that it cannot resolve jquery dependency.
There is nothing in requireJs optimizer faq on that. I tried play with configuring 'path' property but it didnt fix anything.
I removed deps property and added new element to paths
var require = {
// 'baseUrl': 'static/scripts',
'paths': {
'external': 'global/external'
'jquery': 'global/external/jquery-1.7.2'
},
'waitSeconds': 2,
...
};
it didnt play before because I tried to setup path to jquery like
'jquery': 'external/jquery-1.7.2'
thinking that external should evaluate to
'global/external/jquery-1.7.2'
then I just set path.jquery in build script (or as argument to r.js) once again and it worked

Resources