Testcafe: Provide the capability to add custom actions to the test controller

Created on 14 Jun 2017  Â·  8Comments  Â·  Source: DevExpress/testcafe

Provide the capability to add custom actions to the test controller or chain methods that contain a test controller chain.

Custom Actions

Suppose the following test code:

const appPage = new AppPage();
test('log in', async t => {
    await t
        .typeText(appPage.loginInput, 'MyLogin')
        .typeText(appPage.passwordInput, 'Pa$$word')
        .click(appPage.signInButton)
        .expect(appPage.logInMsg.textContent).eql('Logged In');
});

With custom actions, you will be able to rewrite this test as follows:

test('log in', async t => {
    await t
        .logIn(appPage)
        .expect(appPage.logInMsg.textContent).eql('Logged In');
});

(from here: https://testcafe-discuss.devexpress.com/t/use-custom-actions-on-test-controller/228)

Chain Page Model Methods

Assume the following page model:

import { Selector, t } from 'testcafe';

export class Shop {
    constructor() {
        this.coffeeElement = 'a.coffee';
        this.teaElement = 'a.tea';
    }

    async makeCoffee() {
        await t.click(Selector(this.coffeeElement));
    }

    async makeTea() {
        await t.click(Selector(this.teaElement));
    }
}

In test code, you will be able to call these methods in a chain.

const shop = new Shop();

await shop
    .makeCoffee()
    .makeTea();

(from here: https://testcafe-discuss.devexpress.com/t/how-to-chain-pagemodel-methods/313)

server level 2 API enhancement

Most helpful comment

It's already possible with function composition :) You can use smth like this:

test('can login', pipe(
  attemptsTo(login('[email protected]', '1234567')),
  expectsTo(see(Dashboard.container))
))

All 8 comments

Might a simpler alternative be to add a apply() action that takes a function as its argument, and then calls that function with the controller as its argument? Then there would be no risk of polluting the controller's API, and we could all factor out whatever we'd like into separate functions, at least provided we only want to do sync calls.

It's already possible with function composition :) You can use smth like this:

test('can login', pipe(
  attemptsTo(login('[email protected]', '1234567')),
  expectsTo(see(Dashboard.container))
))

Just thinking out loud here but it looks like a custom action could be implemented as a subset of the current Role behaviour where a chain of actions are applied when using .useRole(roleX).

Let's imagine we have a similar .useAction(customAction) function and the custom actions would look something like this

const customAction = Action( async(t) => { 
    await t
        .expect(something).ok(…)
        .click(Selector(x))
        .typeText('xyz')
        …
}
// Or just
async function(t){ 
    await t …
}

This would provide consistency with current API and wouldn't clutter the t object with our custom methods while still providing good facilities to execute them in the chain.

I could so how in a more mature project an internal library of actions could be procured so the individual tests are much higher level.

Any updates on this?

Once we get any results, we will post them here.

Bumping this, we've been looking for a way to do this with our testcafe suite @wistia, and we'd love to see this merged! If there's anything we can do to help here, let us know!

Is there any update on this since feature?

@Benyon, We have no updates at the moment.

Was this page helpful?
0 / 5 - 0 ratings