/nsmockup

:zap:Netsuite API Mockup:zap: :shell: Test your SuiteScripts before deploying to NetSuite :cloud:

Primary LanguageJavaScriptMIT LicenseMIT

nsmockup NPM version

Build Status Coveralls Status

Test your Suitescripts before deploying to NetSuite.

nsmockup is a tool to create NetSuite Suite Scripts unit tests.

You can test your code before deploy it to your NetSuite account. Do you develop NetSuite Suite Scripts? Well, then you know how complicated is to test your code! You need to upload it, configure your script, start the debbuger and, maybe, you can test that!

This further complicates in larger projects, where you reuse your code in several Suite Scripts.

To improve our development process SuitePlus idealized the nsmockup, so developers can:

  • Simulate NetSuite environment locally.
  • Create automated tests for your projects in a controlled environment.

Required

  • node.js 4+

Install Dependency Status devDependency Status

    npm install nsmockup --save-dev

Usage

nsmockup.init(opt, cb)

Param Type Description
opt.current.company string Define company of the current NetSuite user. Default NSMOCKUPVxxx.
opt.current.user.id number Define the ID of the current NetSuite user. Default -4 for anonymous. Default null.
opt.current.user.type string Define the type of the current NetSuite user, see options: "employee", "customer", "vendor" or "partner". Default "entity"
opt.general.currency string Set currency. Default $.
opt.general.dateFormat string Global Preferences: dateformat, default "MM/DD/YYYY".
opt.general.numberFormat.decimal string Set decimal format. Default ".".
opt.general.numberFormat.precision string Set number format precision. Default 2.
opt.general.numberFormat.thousand string Set thousand format. Default ",".
opt.general.timeFormat string Global Preferences: timeFormat, default "hh:mm A".
opt.general.lang string Global Preferences: lang, default "en".
opt.metadata [string] List of Records Types Metadata, generate that with ns-export.
opt.records [string] Data list of Records, generate that with ns-export.
opt.server boolean Set true and start server on port 3030. Used for Suitelet and RESTlet simulations.
cb function Callback Function.
var opt = {
    records: {
        "customrecord_my-record": __dirname + '/data/customrecord_my-record.json'
    },
    metadata: [
        __dirname + '/meta/metaData-customrecord_my-record.json'
    ],
    server: true
};
nsmockup.init(opt, function(err) {
    if (err) console.log('ERROR', err);
    else console.log('start Netsuite API simulation')
});

nsmockup.createSuitelet(cfg, cb)

Param Type Description
cfg.id string Custom ID of Suitelet.
cfg.name string Name of Suitelet.
cfg.function string Defines the function that should be called from the selected script file.
cfg.files [string] Path to JavaScripts files that contains your implementation.
cfg.params object Default parameters to run your implementation.
cb function Callback Function sent ctx (type: object) - the context and exec (type: function) invoke your code in side the context.
    nsmockup.createSuitelet({
        id: 'my_suitelet',
        name: 'My Suitelet',
        function: 'MySuitelet.main',
        files: [
            __dirname + '/lib/my-suitelet.js'
        ]
    }, (ctx, exec) => {
        // verify if function 'MySuitelet' was loaded
        if (!ctx.MySuitelet) throw 'not found MySuitelet'

        // invoke my RESTlet
        let url = nlapiResolveURL('SUTELET', 'my_suitelet'),
          res = nlapiRequestURL(url + 'message=hi');

        if (res.getBody() === 'hello') {
         console.log('Finish Suitelet');
        }
    });

nsmockup.createRESTlet(cfg, cb)

Param Type Description
cfg.id string Custom ID of RESTlet.
cfg.name string Name of RESTlet.
cfg.functions.get string Sets the script function that should execute as the HTTP GET method.
cfg.functions.post string Sets the script function that should execute as the HTTP POST method.
cfg.functions.put string Sets the script function that should execute as the HTTP PUT method.
cfg.functions.delete string Sets the script function that should execute as the HTTP DELETE method.
cfg.files [string] Path to JavaScripts files that contains your implementation.
cfg.params object Default parameters to run your implementation.
cb function Callback Function sent ctx (type: object) - the context and exec (type: function) invoke your code in side the context.
    nsmockup.createRESTlet({
        id: 'my_restlet',
        name: 'My RESTlet',
        functions: {
            get: 'MyRestlet.get',
            post: 'MyRestlet.post'
        },
        files: [
            __drname + '/lib/my-restlet.js'
        ]
    }, (ctx, exec) => {
         // verify if function 'MyRestlet' was loaded
         if (!ctx.MyRestlet) throw 'not found MyRestlet'

         // invoke my RESTlet
         let url = nlapiResolveURL('RESTLET', 'my_restlet'),
             res = nlapiRequestURL(url, {message: 'live?'}, null, 'POST');

         if (res.getBody() === 'yeap!') {
            console.log('Finish RESTlet');
         }
     });

nsmockup.createSchedule(cfg, cb)

Param Type Description
cfg.id string Custom ID of Schedule.
cfg.name string Name of Schedule.
cfg.function string Defines the function that should be called from the selected script file.
cfg.files [string] Path to JavaScripts files that contains your implementation.
cfg.params object Default parameters to run your implementation.
cfg.exec boolean If true, nsmockup will run de ScheduleScript before the callback function was called.
cb function Callback Function sent ctx (type: object) - the context and exec (type: function) invoke your code in side the context.
    nsmockup.createSchedule({
        id: 'my_schedule',
        name: 'My Schedule',
        function: 'MySchedule.main',
        files: [
            __dirname + '/lib/my-schedule.js'
        ],
        exec: false
    }, (ctx, exec) => {
        // verify if function 'MySchedule' was loaded
        if (!ctx.MySchedule) throw 'not found MySchedule'
        // execute 'MyOtherFunc.getJapo'
        // you can execute any function present in file '/lib/my-schedule.js'
        let japo = exec('MyOtherFunc.getJapo');

        if (japo.verifyFinishSchedule()) {
            console.log('Finished Schedule');
        }
    });

nsmockup.createUserEvent(cfg, cb)

Param Type Description
cfg.id string Custom ID of User Event.
cfg.name string Name of User Event.
cfg.functions.beforeLoad string Sets the script function that should execute whenever a read operation on a record occurs.
cfg.functions.beforeSubmit string Sets the function that should execute before the associated record is submitted
cfg.functions.afterSubmit string Sets the function that should execute after the associated record is submitted.
cfg.files [string] Path to JavaScripts files that contains your implementation.
cfg.params object Default parameters to run your implementation.
cfg.records [string] Apply this event in this records.
cb function Callback Function sent ctx (type: object) - the context and exec (type: function) invoke your code in side the context.
    nsmockup.createUserEvent({
        id: 'my_user-event',
        name: 'My User Event',
        functions: {
            beforeLoad: 'MyUserEvent.beforeLoad',
            beforeSubmit: 'MyUserEvent.beforeSubmit',
            afterSubmit: 'MyUserEvent.afterSubmit',
        },
        files: [
            __dirname + '/lib/my-user-event.js'
        ],
        record: 'customer'
    }, (ctx, exec) => {
        // verify if function 'MyUserEvent' was loaded
        if (!ctx.MyUserEvent) throw 'not found MySchedule'
        var should = require('should')

        let record = nlapiLoadRecord('customer', 219);
        record.setFieldValue('name', 'Muito Legal');

        nlapiSubmitRecord(record);

        let context = ctx.nlapiGetContext();
        should(context).be.ok();

        let beforeLoadType = context.getSessionObject('before-load-type');
        should(beforeLoadType).be.equal('view');

        let beforeSubmitType = context.getSessionObject('before-submit-type');
        should(beforeSubmitType).be.equal('edit');

        let afterSubmitType = context.getSessionObject('after-submit-type');
        should(afterSubmitType).be.equal('edit');
    });

nsmockup.destroy(cb)

Param Type Description
cb function Callback Function.
    nsmockup.destroy(function(err) {
        if (err) console.log('ERROR', err);
        else console.log('finish Netsuite API simulation')
    });

Example with Mocha

'use strict';
var nsmockup = require('nsmockup');
describe('<Unit Test - Netsuite API Simulation>', function () {

    before(function (done) {
        // map record types
        let metadata = [
                __dirname + '/record/meta/recordType-metaData-codeg.json',
                __dirname + '/record/meta/recordType-metaData-codeg_ids.json'
            ],
            records = {
                'customrecord_codeg': __dirname + '/record/data/recordType-codeg.json',
                'customrecord_codeg_ids': __dirname + '/record/data/recordType-codeg_ids.json'
            };

        // start database simulation
        nsmockup.init({records, metadata, server: true}, done);
    });

    it('simple load lib and execute function', function (done) {
        nsmockup.createReslet({
            name: 'my_restlet',
            functions: {
                get: 'MyRestlet.get',
                post: 'MyRestlet.post'
            },
            files: [
                __dirname + '/lib/my-restlet.js'
            ]
        }, (ctx, exec) => {
             // verify if function 'MyRestlet' was loaded
             if (!ctx.MyRestlet) throw 'not found MyRestlet'

             // invoke my RESTlet
             let url = nlapiResolveURL('RESTLET', 'my_restlet'),
                 res = nlapiRequestURL(url, {message: 'live?'}, null, 'POST');

             if (res && res.getBody() === 'yeap!') {
                console.log('Finish RESTlet');
             } else {
                throw new Error('invalid result');
             }
         });
     });

    after(function (done) {
        nsmockup.destroy(done);
    });
});