Get help with testing, discuss unit testing strategies etc.


Post by aratcliffe »

Hi,

Do you have some recommendations for sequencing asynchronous code to avoid test cases becoming too deeply nested? An example is the test case below:
StartTest(function (t) {

    t.requireOk([
        'SyncClient.model.Search',
        'SyncClient.store.Sources'
    ], function () {
        var panel, list, store;

        // The sources list expects to reference the 'Sources' store registered with the StoreManager. Normally
        // this would be set up in the app controller, for testing purposes do this manually before instantiating
        // the list.
        Ext.create('SyncClient.store.Sources', {
            storeId: 'Sources'
        });

        panel = Ext.create('SyncClient.view.source.List', {
            renderTo: Ext.getBody(),
            width: 300,
            height: 200
        });

        list = panel.down('dataview');
        store = list.getStore();

        store.load();
        
        t.wait('loadSources');

        // When list is built test that all records were rendered and the correct content was rendered
        list.on('refresh', function () {
            t.is(store.getCount(), list.getNodes().length, 'Rendered all data in store ok');

            t.is(list.getNode(0).firstChild.nodeValue, store.first().get('name'), 'Found name in first row');

            // Add a new editable record to the store
            store.add(Ext.create('SyncClient.model.Search', {
                name: 'New Search',
                editable: true
            }));
                        
            // Verify that the record was added
            t.is(store.getCount(), list.getNodes().length, 'Editable record was added to the store ok');
            
            // Check that context menu is displayed when right-clicking on the new item
            t.rightClick(list.getNode(2), function () {
                t.isStrict(panel.contextMenu.isVisible(), true, 'Context menu was displayed');

                // Reorder list items
                t.dragTo(list.getNode(0), list.getNode(1), function () {
                    t.is(store.findExact('name', 'Incoming'), 1, 'Incoming search was moved to 2nd position in store');
   
                    t.is(list.getNode(1).firstChild.nodeValue, 'Incoming', 'Incoming search was moved to 2nd position in list');
             
                    // Reset the proxy state for a clean run next time
                    store.getProxy().clear();
                    
                    t.endWait('loadSources');
                });

            });
        }, this, {single: true});      
    });    
});


Regards
Adam

Post by mats »

We're going to add an easier way to deal with async code, it'll come in a near release, to avoid too nested code. One improvement suggestion would be to use waitForStoresToLoad:
        StartTest(function (t) {

        t.requireOk([
            'SyncClient.model.Search',
            'SyncClient.store.Sources'
        ], function () {
            var panel, list, store;

            // The sources list expects to reference the 'Sources' store registered with the StoreManager. Normally
            // this would be set up in the app controller, for testing purposes do this manually before instantiating
            // the list.
            Ext.create('SyncClient.store.Sources', {
                storeId: 'Sources'
            });

            panel = Ext.create('SyncClient.view.source.List', {
                renderTo: Ext.getBody(),
                width: 300,
                height: 200
            });

            list = panel.down('dataview');
            store = list.getStore();
            store.load();
           
            t.waitForStoresToLoad(store, function() {

                // When list is built test that all records were rendered and the correct content was rendered
                list.on('refresh', function () {
                    t.is(store.getCount(), list.getNodes().length, 'Rendered all data in store ok');

                    t.is(list.getNode(0).firstChild.nodeValue, store.first().get('name'), 'Found name in first row');

                    // Add a new editable record to the store
                    store.add(Ext.create('SyncClient.model.Search', {
                        name: 'New Search',
                        editable: true
                    }));
                           
                    // Verify that the record was added
                    t.is(store.getCount(), list.getNodes().length, 'Editable record was added to the store ok');
               
                    // Check that context menu is displayed when right-clicking on the new item
                    t.rightClick(list.getNode(2), function () {
                        t.isStrict(panel.contextMenu.isVisible(), true, 'Context menu was displayed');

                        // Reorder list items
                        t.dragTo(list.getNode(0), list.getNode(1), function () {
                            t.is(store.findExact('name', 'Incoming'), 1, 'Incoming search was moved to 2nd position in store');
       
                            t.is(list.getNode(1).firstChild.nodeValue, 'Incoming', 'Incoming search was moved to 2nd position in list');
                 
                            // Reset the proxy state for a clean run next time
                            // SHOULD NOT BE NEEDED, each test is sandboxed
                            store.getProxy().clear();
                        });

                    });
                }, this, {single: true});     
            });   
        });   
    });

Post by aratcliffe »

Thanks for your advice Mats :) I found that once using waitForStoresToLoad() I was able to remove the call to explicitly load the store and the clearing of the proxy. The test code must have been running out of sequence previously.

Post Reply