t.chain shorthand to call method within a specific scope and arguments

Get help with testing, discuss unit testing strategies etc.
Post Reply
User avatar
klodoma
Posts: 50
Joined: Thu Oct 01, 2015 11:55 am

t.chain shorthand to call method within a specific scope and arguments

Post by klodoma » Sun Sep 08, 2019 6:39 pm

I have the following running code.
I use methods of some custom classes that execute the cases. All good.

I would like to know if there is a short-hand for the chain method. The following code:

Code: Select all

  t.it('Test Delete trigger:event', function (t) {
                t.chain(
                    function (next) {
                        me.resetViewData(t, next);
                    },
                    function (next) {
                        me.waitForListMode(t, next);
                    },
                    { click: me.actionTargets.deleteClick },
                    { waitForMs: 10 },
                    function (next) {
                        me.view.fireEvent('callDelete');
                        next();
                    },
                    function (next) {
                        me.runDelete(t, next);
                    },
                    function (next) {
                        me.waitForListMode(t, next);
                    },
                    function (next) {
                        me.checkDeleteResult(t, next);
                    }
                );
            });
could look like:

Code: Select all

            t.it('Test Delete trigger:event', function (t) {
                t.chain(
                    { method: me.resetViewData, scope: me, args: [t] }, //next should be automatically passed as last argument
                    { method: me.waitForListMode, scope: me, args: [t] },
                    { method: me.resetViewData, scope: me, args: [t] },
                    { method: me.resetViewData, scope: me, args: [t] },
                    { waitForMs: 10 },
                    function (next) {
                        me.view.fireEvent('callDelete');
                        next();
                    },
                    { method: me.runDelete, scope: me, args: [t] },
                    { method: me.waitForListMode, scope: me, args: [t] },
                    { method: me.checkDeleteResult, scope: me, args: [t] }
                );
            });
Is this possible?

Thanks in advance!

User avatar
nickolay
Core Developer
Core Developer
Posts: 3383
Joined: Mon May 16, 2011 10:48 am

Re: t.chain shorthand to call method within a specific scope and arguments

Post by nickolay » Mon Sep 09, 2019 10:16 am

We offer training in both Ext JS and our products, read more here.
Read the API documentation

User avatar
klodoma
Posts: 50
Joined: Thu Oct 01, 2015 11:55 am

Re: t.chain shorthand to call method within a specific scope and arguments

Post by klodoma » Mon Sep 09, 2019 11:08 am

I tried that, but the scope(this in the function) is not correct if I use that.

User avatar
mats
Core Developer
Core Developer
Posts: 15358
Joined: Sat Dec 19, 2009 11:41 pm
Location: Sweden
Contact:

Re: t.chain shorthand to call method within a specific scope and arguments

Post by mats » Mon Sep 09, 2019 12:32 pm

Docs don't mention any 'scope', so cannot expect that to work. Just bind your methods instead? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
Tired of debugging javascript errors in web applications? Try our new error logging service RootCause, or read more on the Sencha blog

@bryntum
Facebook
API documentation

User avatar
klodoma
Posts: 50
Joined: Thu Oct 01, 2015 11:55 am

Re: t.chain shorthand to call method within a specific scope and arguments

Post by klodoma » Mon Sep 09, 2019 4:50 pm

mats wrote:
Mon Sep 09, 2019 12:32 pm
Docs don't mention any 'scope', so cannot expect that to work. Just bind your methods instead? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
Yes, this was my alternative in case the scope cannot be set.

Maybe it could be a feature request, something like this:

Code: Select all

            
            t.chain(
                { scope: me, defaultArgs: [t]},
                { method: me.method1},
                { method: me.method2},
                { method: me.method3},
            );
My main reasoning for this is is that in the tests one has to write quite some chain methods in order to achieve some behavior and these methods can be stored in some re-usable test-classes.

Here, I put a use-case that I would definitely use:

Code: Select all

    
    
//test-case    
let testHelper = new TestHelper({
    panel: panel,
    list: list
});

t.it("Item Edit Test", function(t){
    t.chain(
        { scope: testHelper, defaultArgs: [t] },
        //select the item
        { method: testHelper.selectItem, args: [item] }, //t, next are passed automatically (defaultArgs + next)
        //check that the panel is in read mode
        { method: testHelper.checkPanelReadMode },
        //hit edit
        { click: 'button[Edit]' },
        //check that edit mode is enabled
        { method: testHelper.checkPanelEditMode }
        ...
    );
}
    
//this is my testHelper
class testHelper {
    
    ...
    
    selectItem: function (selector, t, next) {
        const me = this;
        t.chain(
            { waitFor: 'ComponentVisible', me.list },
            { dblclick: selector },
            { waitForEvent: [me.list, 'item-selected'] },
            next
        );
    },

    checkPanelReadMode: function (t, next) {
        const me = this;
        t.pass('checkPanelStatus');
        t.is(me.panel.getHeader().isVisible(), true, 'Header visible');
        t.is(me.getEditorEl().isDisabled(), true, 'Editor should be disabled');
        //do some other checks - for read mode
        next();
    },

    checkPanelEditMode: function (t, next) {
        const me = this;
        t.pass('checkPanelStatus');
        t.is(me.panel.getHeader().isVisible(), true, 'Header visible');
        t.is(me.panel.getEditorEl().isDisabled(), false, 'Editor should be enabled');
        //do some other checks - for edit mode
        next();
    },

    ...
}
PS: I know I can achieve this with the current setup with binding and passing t as argument

User avatar
nickolay
Core Developer
Core Developer
Posts: 3383
Joined: Mon May 16, 2011 10:48 am

Re: t.chain shorthand to call method within a specific scope and arguments

Post by nickolay » Mon Sep 09, 2019 5:14 pm

The scope is always assumed to be an instance of the current test. It can be generalized to arbitrary function call as you suggest, but in that case "scope" will be required for every step (it won't be saved as an internal state of the `t.chain` call - thats too specific).

The test class is the intended place for the helper methods.

Also, the whole concept of chaining is obsolete with modern JS - one should just go for async/await:

Code: Select all

t.it('Some test', async t => {
    await t.click('target')

    const res   = await someHelper.method(arg1, arg2)

    if (res === 1) {
        await t.click('target')
    } else {
        for (let i = 0; i < 11; i++) {
            await t.click('target' + i)
        }
    }
    
    // etc etc
})
We offer training in both Ext JS and our products, read more here.
Read the API documentation

User avatar
klodoma
Posts: 50
Joined: Thu Oct 01, 2015 11:55 am

Re: t.chain shorthand to call method within a specific scope and arguments

Post by klodoma » Mon Sep 09, 2019 5:25 pm

nickolay wrote:
Mon Sep 09, 2019 5:14 pm
Also, the whole concept of chaining is obsolete with modern JS - one should just go for async/await:
Yeah, this is a very good point. Ok, give it a thought :) till then I'll use the binding.

Thanks for the feedback!

Post Reply