Defining Window for Testing in Mocha - coffeescript

I'm trying to integrate some testing into my current Backbone/CoffeeScript application.
I have created a module for my application baked into the window object, but running any mocha tests fail because window is undefined.
module = (name) ->
window[name] = window[name] or {}
module 'Cart'
Any direction as to how I can define window for mocha?
I did try using jsdom and creating a window that way, but it still threw the same error. Thanks in advance.
EDIT:
Using zombie.js is getting me further then using jsdom.
zombie = require 'zombie'
browser = new zombie.Browser
browser.window.location = 'http://local.cart'
I'm trying to figure out a way to access the DOMWindow and set a variable to one of its values.
It would be ideal if browser.window was the same object as returned from accessing window in Chrome console, but it isn't.
I can access what I'm looking for with
zombie.visit 'http://local.cart', (err, browser) ->
throw err if err
browser.window.Cart
Is there a way for me to set what this returns to a global variable I can use throughout all of my specs?
Can't seem to get what I want trying a beforeEach or setting the previous block to a method and setting a variable to that method.

I think you'll definitely want to mock window, as opposed to trying to pass around a real DOM window object in the node side of your app (mocha).
Try this pattern I just whipped up (sort of conforms to mocha tutorials I have read and uses the this context which changes when in browser (window) vs. run on node (exports):
/**
* My namespace is 'AV'
*/
(function(root) {
/**
* #namespace root namespace object
*/
root['AV'] = root['AV'] || {};
var AV = root['AV'];
AV.CoolThing = {
//...
};
// this will give you
// your "window" object
// which is actually
// module.exports
return root;
})(this);
Then, the test might look something like this (mine are in coffeescript too):
chai = require 'chai'
chai.should()
# exports / "window"
{ AV } = require '../src/AV.js'
describe 'Sample test with namespace', ->
it 'should be an object', ->
AV.should.be.an 'object'

Related

NetSuite SuiteScript - Constants And Inclusion

I have a NetSuite SuiteScript file (2.0) in which I want to include a small library of utilities I've built. I can do that fine, and access the functions in the included library. But I can't access the constants I've defined in that library - I have to re-declare them in the main file.
Here's the main file:
define(['N/record', 'N/search', './utils.js'],
function (record, search, utils) {
function pageInit(scriptContext) {
isUserAdmin = isCurrentUserAdmin(contextRecord);
if (isUserAdmin) {
alert('Administrator Role ID is ' + ADMINISTRATOR_ROLE);
// Do something for Admin users
}
return;
}
return {
pageInit: pageInit
};
});
You can see I include the file ./utils.js in it. Here's utils.js:
const ADMINISTRATOR_ROLE = 11;
function isCurrentUserAdmin(currentRecord) {
return ADMINISTRATOR_ROLE == nlapiGetRole();
}
That's the entire file - nothing else.
In the main file, the call to the function isCurrentUserAdmin works fine. It correctly tells me whether the current user is an admin. Note that I don't have to preface the call to isCurrentUserAdmin with utils. (utils.isCurrentUserAdmin doesn't work - it gives me the error JS_EXCEPTION TypeError utils is undefined). But when the code gets to the line that uses ADMINSTRATOR_ROLE, I get the error JS_EXCEPTION ReferenceError ADMINISTRATOR_ROLE is not defined. BTW, if I put the constant definition of ADMINISTRATOR_ROLE in the main file instead of utils.js, I get the same error when utils.js tries to use it. The only way I can get it to work is if I have the line defining the constant in both files.
Why does the inclusion work for the function, but not the constant? Am I including the library wrongly? I thought I'd have to use it as utils.isCurrentUserAdmin rather than just isCurrentUserAdmin, but to my surprise that's not the case, as I say above.
If you have utils.js like below, you can use utils.ADMINISTRATOR_ROLE and utils.isCurrentUserAdmin() in your main file.
/**
*#NApiVersion 2.0
*/
define ([],
function() {
const ADMINISTRATOR_ROLE = 11;
function isCurrentUserAdmin() {
// check here
}
return {
ADMINISTRATOR_ROLE: ADMINISTRATOR_ROLE,
isCurrentUserAdmin: isCurrentUserAdmin
};
});
Try
define(['N/record', 'N/search', 'SuiteScripts/utils']
You need to make sure any member you need to access in another module needs to be exported in the source module using the return statement

NetSuite Custom Module entry point error?

I have a simple custom module which posts messages to a server-side Suitelet.
/**
* test_app_client_module.js
* #NApiVersion 2.x
* #NScriptType ClientScript
* #NModuleScope SameAccount
*/
define(['N/ui/message'], function(message) {
var exports = {};
function showMessage(messageObject) {
message.create(messageObject).show();
};
exports.showMessage = showMessage;
return exports;
});
This module functions properly when used with form.ClientScriptModulePath and invoked from a file cabinet, excluding #NScriptType.
However, if I attempt to create a script record to define this module in a remote function, I get the following error.
SuiteScript 2.0 entry point scripts must implement one script type function.
Any suggestions?
As the error message states, you haven't implemented an entry point function. All Script modules need at least one entry point.
Add an empty pageInit function to your module.
exports.pageInit = function () {}

#JSGlobalScope in scala.js 1.0 (JavaScriptException, ReferenceError, var is not defined)

After migrating from scala.js 0.6.x to 1.0, I've got some code related to #JSGlobalScope broken.
My use case is like this:
there's a 3rd-party library that expects some global var to be set to a function
when loaded and ready, it calls this function (by name)
I set this function in global scope from scala.js
The code looks like this:
#js.native
#JSGlobalScope
object Globals extends js.Object {
var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
}
then I set this var like this:
Globals.callbackFunctionFor3rdPartyLib = () => {
// do things
}
and then I add the script into the DOM.
This was working with scala.js 0.6.x, but with 1.0 I'm getting an exception like the following:
scala.scalajs.js.JavaScriptException: ReferenceError: callbackFunctionFor3rdPartyLib is not defined
In the changelog for 1.0.0 there's a "Breaking changes" section that mentions this:
Accessing a member that is not declared causes a ReferenceError to be thrown
...
js.Dynamic.global.globalVarThatDoesNotExist = 42
would previously create said global variable. In Scala.js 1.x, it also throws a ReferenceError.
My question is:
what is the right way to do something like this (create a new global var) in scala.js 1.0?
If you know you'll always be in a browser context, you can use #JSGlobal("window") instead of #JSGlobalScope on your Globals, which will then be equivalent to doing window.myGlobalVarFor3rdPartyLib in JS. So that will work.
#js.native
#JSGlobal("window")
object Globals extends js.Object {
var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
}
If not, but you are using a script (so not a CommonJS nor an ES module), the best thing is actually to use
object Globals {
#JSExportTopLevel("myGlobalVarFor3rdPartyLib")
var foo: js.Function[Unit] = ...
}
Note that Globals is a normal Scala object now, not a JS one.
The #JSExportTopLevel creates a top-level var myGlobalVarFor3rdPartyLib at the top of the script, and then assigning Globals.foo will also assign that top-level var.
If you're not using a script nor know that you're going to always be in a browser, then you need to figure out the global object yourself. Scala.js 0.6.x tried to do that for you, but could fail, so we don't do that anymore. You can at least follow the "instructions" on the documentation of js.special.fileLevelThis to reproduce what Scala.js 0.6.x was doing. I repeat the instructions here:
Using this value should be rare, and mostly limited to writing code
detecting what the global object is. For example, a typical detection
code--in case we do not need to worry of ES modules--looks like:
val globalObject = {
import js.Dynamic.{global => g}
if (js.typeOf(g.global) != "undefined" && (g.global.Object eq g.Object)) {
// Node.js environment detected
g.global
} else {
// In all other well-known environment, we can use the global `this`
js.special.fileLevelThis
}
}
Note that the above code is not comprehensive, as there can be JavaScript
environments where the global object cannot be fetched neither through
global nor this. If your code needs to run in such an environment, it
is up to you to use an appropriate detection procedure.

Get newly created id of a record before redirecting page

I would like to retrieve the id of a newly created record using javascript when I click on save button and just before redirecting page.
Do you have any idea please ?
Thank you !
One way to do this in Sugar 7 would be by overriding the CreateView.
Here an example of a CustomCreateView that outputs the new id in an alert-message after a new Account was successfully created, but before Sugar gets to react to the created record.
custom/modules/Accounts/clients/base/views/create/create.js:
({
extendsFrom: 'CreateView',
// This initialize function override does nothing except log to console,
// so that you can see that your custom view has been loaded.
// You can remove this function entirely. Sugar will default to CreateView's initialize then.
initialize: function(options) {
this._super('initialize', [options]);
console.log('Custom create view initialized.');
},
// saveModel is the function used to save the new record, let's override it.
// Parameters 'success' and 'error' are functions/callbacks.
// (based on clients/base/views/create/create.js)
saveModel: function(success, error) {
// Let's inject our own code into the success callback.
var custom_success = function() {
// Execute our custom code and forward all callback arguments, in case you want to use them.
this.customCodeOnCreate(arguments)
// Execute the original callback (which will show the message and redirect etc.)
success(arguments);
};
// Make sure that the "this" variable will be set to _this_ view when our custom function is called via callback.
custom_success = _.bind(custom_success , this);
// Let's call the original saveModel with our custom callback.
this._super('saveModel', [custom_success, error]);
},
// our custom code
customCodeOnCreate: function() {
console.log('customCodeOnCreate() called with these arguments:', arguments);
// Retrieve the id of the model.
var new_id = this.model.get('id');
// do something with id
if (!_.isEmpty(new_id)) {
alert('new id: ' + new_id);
}
}
})
I tested this with the Accounts module of Sugar 7.7.2.1, but it should be possible to implement this for all other sidecar modules within Sugar.
However, this will not work for modules in backward-compatibility mode (those with #bwc in their URL).
Note: If the module in question already has its own Base<ModuleName>CreateView, you probably should extend from <ModuleName>CreateView (no Base) instead of from the default CreateView.
Be aware that this code has a small chance of breaking during Sugar upgrades, e.g. if the default CreateView code receives changes in the saveModel function definition.
Also, if you want to do some further reading on extending views, there is an SugarCRM dev blog post about this topic: https://developer.sugarcrm.com/2014/05/28/extending-view-javascript-in-sugarcrm-7/
I resolved this by using logic hook (after save), for your information, I am using Sugar 6.5 no matter the version of suitecrm.
Thank you !

How to invoke a Eclipse Clean-Up Profile programmatically?

Is there a way to invoke a specific Clean-Up profile (Source->Clean Up) programmatically?
I would like to invoke it on an iterable of ICompilationUnits.
I looked at the declarations in org.eclise.jdt.ui.
The relevant command ID is org.eclipse.jdt.ui.edit.text.java.clean.up and the implementation is org.eclipse.jdt.internal.ui.actions.AllCleanUpsAction. Unfortunately it is an internal action and the command does not support any parameters.
I can see three possible approaches:
create an AllCleanUpsAction and invoke ...run(new StructuredSelection(<compilation units>[])). Problem: the action is internal so you might want to create a fragment to access it...
open the package navigator view. Select the proper files corresponding to the compilation units. Execute the command ID via IHandlerService.executeCommand("org.eclipse.jdt.ui.edit.text.java.clean.up"). Problem: the package navigator is changed... and you might not have all compilation units in visible in the navigator.
set the current selection in your view to new StructuredSelection(<compilation units>[]). Then execute the command as above. Problem: I'm not sure the command is properly enabled..
You can use RefactoringExecutionStarter.startCleanupRefactoring which takes an array of ICompilationUnits to perform the clean up on as one of its parameters. This method also allows you to specify the ICleanUps that you want to perform and allows you to skip showing the clean up wizard if you want.
Here's an example which removes unnecessary parentheses:
ICleanUp[] cleanUps = new ICleanUp[]{new ExpressionsCleanUp(){
#Override
protected boolean isEnabled(String key){
switch(key){
case CleanUpConstants.EXPRESSIONS_USE_PARENTHESES:
case CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_NEVER:
return true;
case CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_ALWAYS:
return false;
default:
return super.isEnabled(key);
}
}
}};
ICompilationUnit[] icus = new ICompilationUnit[]{icu};
Shell shell = HandlerUtil.getActiveEditor(event).getSite().getShell();
try {
RefactoringExecutionStarter.startCleanupRefactoring(
icus, cleanUps, false, shell, false, ActionMessages.CleanUpAction_actionName);
} catch (InvocationTargetException e) {
throw new AssertionError(e);
}