Step Three: Identifying Test Cases

It can be tricky to identify which pieces of code make for a good test. You should first have a general understanding of what your script does and the expected output. Before you begin to identify test cases, you should be familiar with the concept of mocking. Mocking allows you to isolate a unit of code and mimic its behavior.

Mocking

Mocking is the process of creating arbitrary values to imitate the behavior of the script. In SuiteScript, we can mock all object and module members that are used in a script. This could include methods, objects, and properties.

We imitate the behavior of SuiteScript dependencies to provide context to Jest. To imitate this behavior, we use built in Jest functions that allow us to create a variation of outcomes.

Mocking SuiteScript Methods and Objects

To mock a SuiteScript method, you will need to use a Jest mock function to initiate a test. You should familiarize yourself with Jest mock functions to have a better understanding of mocking. For a complete list of Jest mock functions, see Jest Mock Functions.

Mocking Method Examples

The following code sample will mock the runtime.getCurrentScript() method with the mockReturnValue() Jest mock function. This mock function allows you to return an arbitrary value for this method. It is important to note that this method returns a runtime.Script object, so we will use this as the mock value to return. This object is represented as Script in the following example, because that is how it was defined. Note that you can name this object to your liking.

            import runtime from 'N/runtime'; // import runtime module
import Script from 'N/runtime/script'; // import script object from runtime module

describe('Mocking SuiteScript dependencies', () => {
   it('Should mock Suitescript method', () => {
      // given
      runtime.getCurrentScript.mockReturnValue(Script); //returns runtime.Script object 
 
      // then 
      expect(runtime.getCurrentScript).toHaveBeenCalled();
   });
}); 

          

The following code sample will mock the Script.getParameter(options) method with the mockImplementation() Jest mock function. This method returns any number, date, string, boolean, or null value depending on script logic. This example shows the number 15 as the value returned to represent an internal ID. It is important to note that you can set this value to any of the types mentioned in your test. You can use any random arbitrary value.

            import runtime from 'N/runtime'; // import runtime module from runtime.js stub file
import Script from 'N/runtime/script'; // import script object from Script.js stub file

describe('Mocking SuiteScript dependencies', () => {
   it('Should mock Suitescript method', () => {
       // given
       runtime.getCurrentScript.mockReturnValue(Script); 
       Script.getParameter.mockImplementation(options => options.name === 'custscript_example_test' && 15); // returns 15
 
       // then 
       expect(runtime.getCurrentScript).toHaveBeenCalled();
       expect(Script.getParameter).toHaveBeenCalledWith({name: 'custscript_example_test'});
       expect(Script.getParameter).toHaveReturnedWith(15);
   });
}); 

          

Mocking SuiteScript Properties

To mock a SuiteScript property, set the value of the property to an arbitrary value in your test file. For best practice, you should use a valid value type that is accepted for the SuiteScript property used. For example, the Record.type property accepts string values, so your mocked value should be a string.

            describe('Mocking SuiteScript dependencies', () => {
   it('Should mock Suitescript property', () => {
      // given
      record.create.mockReturnValue(Record);
      Record.type = 'salesorder';
   });
}); 

          

Handling Enums

SuiteScript enums must be defined in the test file as an object with the exact values that are used in the script file. It is not required to list every possible value of the enum. If you do not define the enum with the exact values, an error will occur in your test file.

            import script from "../src/FileCabinet/SuiteScripts/ue_exampleScript";

// import modules used
import record from 'N/recprd';
import Record from 'N/record/instance';
 
beforeEach(() => {
   jest.clearAllMocks();
});


record.Type = {
 SALES_ORDER: 'SALES_ORDER' // only define values used in your script
};

describe('Mocking SuiteScript dependencies', () => {
   it('Should do something', () => {
     // test code goes here  
   });
}); 

          

Mocking Entry Point Functions

A simple starting point for writing tests could be verifying the entry point functions. Each entry point function has required and optional parameters. We can format our test to ensure those parameters are assigned to the correct values and types. For more information about entry point functions, see SuiteScript 2.x Script Types and Entry Points.

The following example shows an object that represents a user event script that will execute on the beforeLoad(context) entry point. The properties of this object are the assigned parameters of the beforeLoad entry point.

User Event Script example:

            import runtime from 'N/runtime'; 
import Script from 'N/runtime/script'; 
import record from 'N/record';
import Record from 'N/record/instance';

const context = {
   UserEventType: { // beforeLoad entry point properties
      CREATE: 'CREATE',
      EDIT: 'EDIT',
      VIEW: 'VIEW'
   }
};

describe('Mocking SuiteScript dependencies', () => {
   it('Should do something', () => {

   });
}); 

          

Suitelet Example:

            import runtime from 'N/runtime'; 
import Script from 'N/runtime/script'; 
import record from 'N/record';
import Record from 'N/record/instance';

const scriptContext = {
   request: { 
     parameters: {
        record_id: 14,
        sales_order_id: 325
   }
};


describe('Mocking SuiteScript dependencies', () => {
   it('Should do something', () => {
      // test code goes here
   });
}); 

          

Testing Conditional Statements

You also want to be mindful of testing conditional statements. Conditional statements are automatically evaluated with Jest, so be sure to write tests that verify the conditional statement logic.

The following example writes a test to verify that a client script with the validateLine(scriptContext) entry point function is being called with the correct parameters and value types. The script evaluates the value of the scriptContext.sublistId parameter value in the conditional statement. With this information, we can structure the unit test by setting this parameter value to pass or fail the condition.

exampleScript.js:

            define(['N/record', 'N/runtime', 'N/log'], (record, runtime, log) => {
   function validateLine(scriptContext) {
      const recSalesOrder = scriptContext.currentRecord;
        if (scriptContext.sublistId === 'item') {
          const casePerPallet = recSalesOrder.getCurrentSublistValue({
             sublistId: 'item',
             fieldId: 'custcol_cases_per_pallet'
         });
          const quantity = recSalesOrder.getCurrentSublistValue({
              sublistId: 'item',
              fieldId: 'quantity'
         });
     }
 } 

          

exampleScript.test.js

In the example test file below, the condition will fail because the sublistId is incorrect. Therefore we can expect the CurrentRecord.getSublistValue(options) method to not be called.

            describe('Testing conditional statements', () => {
    it('Should test validateLine function parameters', () => {
        // given
        scriptContext.currentRecord = CurrentRecord; // CurrentRecordObj
        scriptContext.sublistId = 'name'; // condition fails

        // when
        script.validateLine(scriptContext);

        // then
        expect(CurrentRecord.getCurrentSublistValue).not.toHaveBeenCalled();  // function should not be called
    });
}); 

          

In the example test file below, the condition will pass because the sublistId is set to the correct value. Therefore we can expect the methods to be called twice.

            describe('Testing conditional statements', () => {
    it('Should test validateLine function parameters', () => {
        // given
        scriptContext.currentRecord = CurrentRecord; // CurrentRecordObj
        scriptContext.sublistId = 'item'; // condition passes

        // when
        script.validateLine(scriptContext);

        // then
        expect(CurrentRecord.getCurrentSublistValue).toHaveBeenCalledTimes(2); // function will be called
    }); 

          

General Notices