Skip to content

Latest commit

 

History

History
 
 

unit-testing

SuiteCloud Unit Testing

npm-unit-testing

Suitecloud Unit Testing allows you to use unit testing with Jest for your SDF projects.

Features

  • Provides a default configuration to run unit tests with Jest in SDF projects.
  • Supports unit testing for SuiteScript 2.X files.
  • Provides SuiteScript 2.X stubs for the following SuiteScript modules:
    • N/http
    • N/https
    • N/record
    • N/search
  • Allows you to create custom stubs for SuiteScript 2.X or custom modules.
  • Supports code coverage capabilities through Jest.

Prerequisites

  • Node.js version 12.14.0 LTS or greater
  • An SDF project

Getting Started

If you use SuiteCloud CLI for Node.js, you can install SuiteCloud Unit Testing when running the project:create command by following the questions prompted. This way, your project is initialized with SuiteCloud Unit Testing, and all the dependencies are being taken care of.

⚠ SuiteCloud Unit Testing is installed as a devDependency.

However, if you want to configure SuiteCloud Unit Testing manually, do the following:

  1. Inside of your SDF project folder, create a src folder.
  2. Move your project files inside of the src folder.
  3. To initialize the NPM package, from the root of your SDF project folder, run npm init.

💡 A package.json file is created in your SDF project folder.

  1. In your package.json file, add the following code:
{
  "scripts": {
    "test": "jest"
  }
}
  1. From the root of your SDF project folder, run the followig command:
npm install --save-dev @oracle/suitecloud-unit-testing jest
  1. Create a __tests__ folder, inside of the root of your SDF project folder.
  2. Create a sample-test.js file, inside of the __tests__ folder, with the following content:
describe('Basic jest test with simple assert', () => {
    it('should assert stings are equal', () => {
        const a = 'foobar';
        const b = 'foobar';
        expect(a).toMatch(b);
    });
});
  1. From the root of your SDF project folder, run npm test to run your test. You should see an output similar to following:
PASS  __tests__/sample-test.js
  Basic jest test with simple assert
    √ should assert stings are equal (2ms)

💡 If you want to run tests with coverage, from the root of your SDF project folder, run npm test --coverage.

You successfully ran your first test for an SDF project!

Additional Configuration

To properly run your tests against the SuiteScript 2.X files of your SDF project, create a jest.config.js file inside of the root of your SDF project folder.

The jest.config.js file must follow a specific structure. Depending on your SDF project type, check one of the following examples:

  • For Account Customization Projects:
const SuiteCloudJestConfiguration = require("@oracle/suitecloud-unit-testing/jest-configuration/SuiteCloudJestConfiguration");

module.exports = SuiteCloudJestConfiguration.build({
  projectFolder: 'src', //or your SDF project folder
  projectType: SuiteCloudJestConfiguration.ProjectType.ACP,
});
  • For SuiteApps:
const SuiteCloudJestConfiguration = require("@oracle/suitecloud-unit-testing/jest-configuration/SuiteCloudJestConfiguration");

module.exports = SuiteCloudJestConfiguration.build({
  projectFolder: 'src', //or your SDF project folder
  projectType: SuiteCloudJestConfiguration.ProjectType.SUITEAPP,
});

SuiteCloud Unit Testing Examples

Here you can find two examples on how to use SuiteCloud Unit Testing with an SDF project.

The first example covers testing for the N/record module, which is fully mocked in SuiteCloud Unit Testing. Whereas the second example covers the testing of a module that is not mocked in SuiteCloud Unit Testing, by using a custom stub.

💡 You can manually mock any module that is still not supported in SuiteCloud Unit Testing.

N/record Module Example

This example follows the structure presented below:

myAccountCustomizationProject
├── __tests__
│   └── sample-test.js
├── node_modules
├── src
│   ├── AccountConfiguration
│   ├── FileCabinet
│       ├── SuiteScripts
│           └── Suitelet.js
│   ├── Objects
│   ├── Translations
│   ├── deploy.xml
│   └── manifest.xml
├── jest.config.js
├── suitecloud.config.js
├── package-lock.json
├── package.json
└── project.json

See below the content of the SuiteCloud Unit Testing files:

  • jest.config.js file
const SuiteCloudJestConfiguration = require("@oracle/suitecloud-unit-testing/jest-configuration/SuiteCloudJestConfiguration");

module.exports = SuiteCloudJestConfiguration.build({
	projectFolder: 'src',
	projectType: SuiteCloudJestConfiguration.ProjectType.ACP,
});
  • Suitelet.js file
/**
 * @NApiVersion 2.x
 * @NScriptType Suitelet
 * @NModuleScope SameAccount
 */
define(["N/record"], function(record) {
    return {
        onRequest: function(context) {
            if (context.request.method === 'GET') {
                const salesOrderId = context.request.parameters.salesOrderId;
                let salesOrderRecord = record.load({id: salesOrderId});
                salesOrderRecord.setValue({fieldId: 'memo', value: "foobar"});
                salesOrderRecord.save({enableSourcing: false});
            }
        }
    };
});
  • Suitelet.test.js file
import Suitelet from "SuiteScripts/Suitelet";

import record from "N/record";
import Record from "N/record/instance";

jest.mock("N/record");
jest.mock("N/record/instance");

beforeEach(() => {
    jest.clearAllMocks();
});

describe("Suitelet Test", () => {
    it("Sales Order memo field has been updated", () => {
        // given
        const context = {
            request: {
                method: 'GET',
                parameters: {
                    salesOrderId: 1352
                }
            }
        };

        record.load.mockReturnValue(Record);
        Record.save.mockReturnValue(1352);

        // when
        Suitelet.onRequest(context);

        // then
        expect(record.load).toHaveBeenCalledWith({id: 1352});
        expect(Record.setValue).toHaveBeenCalledWith({fieldId: 'memo', value: 'foobar'});
        expect(Record.save).toHaveBeenCalledWith({enableSourcing: false});
    });
});

Custom Stub Example

This example follows the structure presented below:

myAccountCustomizationProject
├── customStubs
│   └── http.js
├── __tests__
│   └── http.test.js
├── node_modules
├── src
│   ├── AccountConfiguration
│   ├── FileCabinet
│       ├── SuiteScripts
│       ├── Templates
│       ├── Web Site Hosting Files 
│   ├── Objects
│   ├── Translations
│   ├── deploy.xml
│   └── manifest.xml
├── jest.config.js
├── suitecloud.config.js
├── package-lock.json
├── package.json
└── project.json

See below the content of the SuiteCloud Unit Testing files:

  • jest.config.js file
const SuiteCloudJestConfiguration = require("@oracle/suitecloud-unit-testing/jest-configuration/SuiteCloudJestConfiguration");

module.exports = SuiteCloudJestConfiguration.build({
		projectFolder: 'src',
		projectType: SuiteCloudJestConfiguration.ProjectType.ACP,
		customStubs: [
			{
				module: "N/http",
				path: "<rootDir>/customStubs/http.js"
			}
		]
});
  • http.js file: This is the stub file. It partially mocks NetSuite's N/http module.

💡 The JSDoc annotations are copied from NetSuite's N/http module, but are not required to run SuiteCloud unit testing.

define([], function() {
    /**
     * @namespace http
     */
    var http = function() {};

    /**
     * Send a HTTP GET request and return a reponse from a server.
     *
     * @governance 10 units
     * @restriction Server SuiteScript only
     *
     * @param {Object} options
     * @param {string} options.url the HTTP URL being requested
     * @param {Object} options.headers (optional) The HTTP headers
     * @return {ClientResponse}
     *
     * @throws {SuiteScriptError} SSS_MISSING_REQD_ARGUMENT if a required argument is missing
     * @throws {SuiteScriptError} SSS_INVALID_URL if an incorrect protocol is used (ex: http in the HTTPS module)
     *
     * @since 2015.2
     */
    http.prototype.get = function(options) {};

    /**
     * @exports N/http
     * @namespace http
     */
    return new http();
});
  • http.test.js file
import http from 'N/http';

jest.mock('N/http');

beforeEach(() => {
    jest.clearAllMocks();
});

describe('Sample test with user defined http module stub', () => {
    it('should call http get method', () => {
        // given
        const clientResponseMock = {
            code: 200,
            body: {
                data: 'foobar'
            }
            // more properties and functions here if needed
        };
        http.get.mockReturnValue(clientResponseMock);

        const options = {
            url: 'https://netsuite.com'
        };

        // when
        const clientResponse = http.get(options);

        // then
        expect(http.get).toHaveBeenCalledWith(options);
        expect(clientResponse).toMatchObject({
            code: 200,
            body: {
                data: 'foobar'
            }
        });
    });
});

Suitecloud Unit Testing is an open source project. Pull Requests are currently not being accepted. See CONTRIBUTING for details.

Copyright (c) 2020 Oracle and/or its affiliates The Universal Permissive License (UPL), Version 1.0.