Dynamics CRM Model-Driven Apps: Setup Testing Environment with chai, Mocha, xrm-mock, and SinonJS

As Developer, we suppose adapt ourselves to a better working framework or mindset. Following Test-Driven Development (TDD) mindset, for example, enable us to work more effectively in the long run, compare to not using it. Hence making unit tests is has become a crucial part (at least for me), and this post will explain how to set up our project to enable unit testing in our Model-Driven-Apps front-end development. This post is a continuation of this blog post. If you did not yet check that, you need to go there to get the context (also the zip file).

After you open the project, you can run this command to install some packages:

npm install chai mocha ts-node @types/chai @types/mocha sinon @types/sinon xrm-mock --save-dev

These are the information of the npm packages that we are install:

Npm PackagesDescription
chaiChai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.
mochaMocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on GitHub.
SinonJSStandalone test spies, stubs and mocks for JavaScript.
Works with any unit testing framework.
xrm-mockxrm-mock is a fake implementation of the Dynamics 365 Client API and Xrm object model. Written in TypeScript against @types/xrm definitions.
NPM Packages

First, we need to configure our package.json file to enable the test command:

{
  "name": "basic-crm-typescript",
  "version": "1.0.0",
  "description": "Sample of how to implement TypeScript for Dynamics CRM",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "test": "mocha -r ts-node/register '**/*.spec.ts'"
  },
  "keywords": [
    "powerapps",
    "dynamics-crm",
    "model-driven-apps",
    "microsoft",
    "typescript"
  ],
  "author": "Temmy",
  "license": "ISC",
  "devDependencies": {
    "@types/chai": "^4.2.14",
    "@types/mocha": "^8.2.0",
    "@types/sinon": "^9.0.9",
    "@types/xrm": "^9.0.31",
    "chai": "^4.2.0",
    "mocha": "^8.2.1",
    "sinon": "^9.2.2",
    "terser-webpack-plugin": "^5.0.3",
    "ts-loader": "^8.0.11",
    "ts-node": "^9.1.1",
    "typescript": "^4.1.2",
    "webpack": "^5.10.0",
    "webpack-cli": "^4.2.0",
    "xrm-mock": "^3.4.21"
  }
}

The highlight syntax in the top (mocha -r ts-node/register ‘**/*.spec.ts’) meaning we will only register all files as long as the file format is *.spec.ts.

Because from last post we already have implementation code, now we will create the test file for it (src/new_customdocument/form.spec.ts):

import { expect } from 'chai';
import { XrmMockGenerator } from 'xrm-mock';
import { initFormCreate } from './form';
import * as sinon from 'sinon';

describe('new_customdocument form tests', () => {
    beforeEach(() => {
        XrmMockGenerator.initialise();
        XrmMockGenerator.Attribute.createString('new_name');
        XrmMockGenerator.Attribute.createDate('new_documentdate');
    });

    describe('on form update', () => {
        beforeEach(() => {
            sinon.stub(XrmMockGenerator.getFormContext().ui, 'getFormType').
                returns(XrmEnum.FormType.Update);
        });

        it('initFormCreate skip set', () => {
            initFormCreate(XrmMockGenerator.getEventContext());

            var formContext = XrmMockGenerator.getFormContext();

            expect(formContext.getAttribute('new_name').getValue()).to.empty;
            expect(formContext.getAttribute('new_documentdate').getValue()).to.undefined;
        });
    });

    describe('on form create', () => {
        beforeEach(() => {
            sinon.stub(XrmMockGenerator.getFormContext().ui, 'getFormType').
                returns(XrmEnum.FormType.Create);
        });

        it('initFormCreate set name and document date', () => {
            initFormCreate(XrmMockGenerator.getEventContext());

            var formContext = XrmMockGenerator.getFormContext();

            expect(formContext.getAttribute('new_name').getValue()).to.equal('Form TypeScript UI');
            expect(formContext.getAttribute('new_documentdate').getValue()).to.not.null;
        });
    });
});

As you can see, we use sinon to return mock the value return when we call formContext.ui.getFormType().

To run the test, we can run it using this command:

npm run test

This is the result:

Result testing in command prompt

Summary

Until this step, you already have a better environment than before. You can reduce typing error (using TypeScript) and you already can apply your unit testing using xrm-mock as its Xrm object replacement. And all of this is production-ready!

You can download the source code here.

Related Post

4 thoughts on “Dynamics CRM Model-Driven Apps: Setup Testing Environment with chai, Mocha, xrm-mock, and SinonJS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.