Page 1 of 1

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

Posted: Sun Sep 08, 2019 6:39 pm
by klodoma
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:
  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:
            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!

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

Posted: Mon Sep 09, 2019 10:16 am
by nickolay

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

Posted: Mon Sep 09, 2019 11:08 am
by klodoma
I tried that, but the scope(this in the function) is not correct if I use that.

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

Posted: Mon Sep 09, 2019 12:32 pm
by mats
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

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

Posted: Mon Sep 09, 2019 4:50 pm
by klodoma
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:
            
            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:
    
    
//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

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

Posted: Mon Sep 09, 2019 5:14 pm
by nickolay
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:
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
})

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

Posted: Mon Sep 09, 2019 5:25 pm
by klodoma
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!