Mocking Requests and Data for the Ignite UI igGrid

Craig Shoemaker / Thursday, March 28, 2013

Sometimes when you are working on a new feature of an application the server and client are either in development at different stages or maybe you just want to work out the particulars of a view in isolation from the server. To make this possible there are a few JavaScript libraries that makes it very easy to mock not only data used in the grid, but also Ajax requests to the server.

The following screenshot is the igGrid filled with random data generated with mockJSON and is served to the grid using the client-side Mockjax library.

When you use an approach like this you are easily able to separate out all mocking behavior so when it’s time to work with the real server you can simply remove the reference to the mocks and then the scripts and grid will work just like normal. The code for the grid remains unchanged whether or not you are using mocked requests and data or not.

Code Download

If you would like to take a look at the source files use for this example, please download them here.

Mocking Requests and Data

In order to truly isolate the client from the server you need to first intercept on the client the requests made to the server. Once the requests are handled locally, then you can construct a mocked response to the page and return it back to the grid.

Mocking requests is handled by the Mockjax library. What’s nice about this library is that as you define routes in the configuration script, any matching requests to the server are intercepted by Mockjax on the client. Even while the client has control of the request, its able to return a response to the page which identical to what the server would provide to the client.

Mocking data is handled by the mockJSON library which uses a template to generate a series of randomized data to send in the response as provided by the Mockjax library.

The following is a sample of a mockJSON template to generate some very simple employee objects:

var data = $.mockJSON.generateFromTemplate({
    "employees|1-5": [{
        "id|+1": 1,
        "firstName": "@MALE_FIRST_NAME",
        "lastName": "@LAST_NAME"
    }]
});

You’ll notice some additional characters in what seems like a normal object literal definition. The | character is a delimiter to tell mockJSON there are some commands included in the template definition. The value that follows directly after the root element (employees) and delimiter is a setting that tells mockJSON how many instances of the mock object to create. The numbers represent a range of random numbers which determine how many objects to create.

The next command in the template is found just after the id label. The +1 command tells mockJSON to increment the value by 1 each time a new object is created. This allows each object to have a unique id.

The template uses keywords (words preceded by an@symbol) to act as placeholders where random data is injected into generated JSON objects. There are many built-in keywords and you can even create your own keywords with custom values available for data generation.

Loading Scripts

To get started, the script loader is configured with known paths to the required JavaScript and CSS files and brings in all the igGrid features used in this example. The comment inside the ready event handler is a placeholder for the code in the next section which is concerned with setting up the grid on the page.

$.ig.loader({
    scriptPath: 'http://localhost/ig_ui/js/',
    cssPath: 'http://localhost/ig_ui/css/',
    resources: "igGrid,igGrid.Filtering,igGrid.GroupBy,igGrid.Paging,igGrid.Sorting",
    ready: function () {

       // setup grid here...

    }
});

Loading the Grid

Now that the page is ready and the scripts are loaded, you can setup the grid on the page. The data for the grid is made available after a JSON response is recognized from the server. Then the columns and features are setup.

$.getJSON('api/employees', function (data) {

    var grid = $("#grid").igGrid({

        autoGenerateColumns: false,
        defaultColumnWidth: "180px",
        dataSource: data,

        columns: [
            { headerText: "ID", key: "id", dataType: "number", width: "80px" },
            { headerText: "First", key: "firstName" },
            { headerText: "Last", key: "lastName" },
            { headerText: "Email", key: "email" },
            { headerText: "Title", key: "title" },
            { headerText: "Active", key: "active", dataType: "bool", format: "checkbox" },
            { headerText: "Workshop Day", key: "workshopDay" }
        ],

        features: [
            { name: "Filtering", columnSettings: [{ columnKey: "id", allowFiltering: false }], mode: "simple" },
            { name: "GroupBy" },
            { name: "Paging", pageSize: 20, pageSizeList: [5, 8, 10, 20, 50] },
            { name: "Sorting" }
        ]
    });
});

This is all the code the page needs to operate. Notice how there is zero mention of mocks in the loader or grid code. There are no flags to alternate data source locations and there is no conditional logic required for the page or the control to differentiate between a “real” scenario and a “fake” scenario. This is the power of working with mocking frameworks – interaction with the mocks is completely abstracted away from the page.

Data Schema

Before diving into the details of the data that is generated for the page, first take a look at a single sample data item that is close to what is generated for the grid.

{
    "id" : 1,
    "firstName" : "Henry",
    "lastName" : "Smith",
    "title" : "Customer Service Rep.",
    "email" : "smith@company.com",
    "active" : true,
    "workshopDay" : "Wednesday"
}

The data generated represents typical information commonly found in an employee database. The next section details how to generate a series of data items structured just like this example.

Adding Mock Support

In order for the page to use the mocking libraries all you need to do is create a new file and add the mock definitions to the file and reference it from the web page. In this example the additional script reference is:


The contents of mock.data.js begin with a self-executing anonymous function.

(function () {

    // add mocks here

})();

The first items added inside the anonymous function are some custom keywords. The first is the &WEEKDAY keyword which is an array of each week day.

    $.mockJSON.data.WEEKDAY = [
        'Monday',
        'Tuesday',
        'Wednesday',
        'Thursday',
        'Friday'
    ];

The next keyword is a list of job titles.

    $.mockJSON.data.TITLE = [
        'Director of Product Engineering',
        'Vice President',
        'Senior Accountant',
        'Accountant',
        'Customer Service Rep.',
        'Sales',
        'Support Engineer',
        'Greeter',
        'Division Manager'
    ];

Then, I added a list of the values for the active flag.

Now, you may be inclined, as I was, to attempt to add some logic into the template. Be forewarned this will not work as you expect. The template is indeed a template and is extracted from the method once and then used to generate each instance of a mock object. In the end, the template is a string and cannot include executing code. (Initially I tried to add a conditional statement to return a random Boolean value, but in the end formatting this value as a keyword is the approach that accomplished what I was trying to do.)

    $.mockJSON.data.ACTIVE = [
        true,
        false
    ];

The following code listing defines a route that is intercepted by Mockjax. When a request to api/employees is made a response is generated on the client and returns as text/json response back to the caller.

    $.mockjax({
        url: 'api/employees',
        contentType: 'text/json',
        response: function () {
            var employees = generateEmployees();
            this.responseText = employees;
        }
    });

The generateEmployees function uses mockJSON to create exactly 54 customer objects. (When you don’t provide a range mockJSON will use the amount you pass in.)

    var generateEmployees = function () {
        var data = $.mockJSON.generateFromTemplate({
            "employees|54-54": [{
                "id|+1": 1,
                "firstName": "@MALE_FIRST_NAME",
                "lastName": "@LAST_NAME",
                "title": "@TITLE",
                "email": "@EMAIL",
                "active": "@ACTIVE",
                "workshopDay" : "@WEEKDAY"
            }]
        });

        return data.employees;
    }

Lastly, the template uses both custom and built-in keywords to provide random data into the objects. The @TITLE, @WEEKDAY and @ACTIVE are all custom keywords and the rest are provided by mockJSON.

Full Mocking Script

Just so you can see it working all together in context, here is the full mocking script.

(function () {

    $.mockJSON.data.WEEKDAY = [
        'Monday',
        'Tuesday',
        'Wednesday',
        'Thursday',
        'Friday'
    ];

    $.mockJSON.data.TITLE = [
        'Director of Product Engineering',
        'Vice President',
        'Senior Accountant',
        'Accountant',
        'Customer Service Rep.',
        'Sales',
        'Support Engineer',
        'Greeter',
        'Division Manager'
    ];

    $.mockJSON.data.ACTIVE = [
        true,
        false
    ];

    // mock requests to employees
    $.mockjax({
        url: 'api/employees',
        contentType: 'text/json',
        response: function () {
            var employees = generateEmployees();
            this.responseText = employees;
        }
    });

    var generateEmployees = function () {
        var data = $.mockJSON.generateFromTemplate({
            "employees|54-54": [{
                "id|+1": 1,
                "firstName": "@MALE_FIRST_NAME",
                "lastName": "@LAST_NAME",
                "title": "@TITLE",
                "email": "@EMAIL",
                "active": "@ACTIVE",
                "workshopDay" : "@WEEKDAY"
            }]
        });

        return data.employees;
    }
})();

Conclusion

Working with mocking libraries gives you ultimate flexibility in being able to test and develop your views independent of the server. When the mock data definitions are present, the page uses mocked data and requests. When references to the mocks are removed, the page works against the server just like normal.