Search code examples
automated-testse2e-testingweb-testingtestcaferendr

Can I use Testcafe to execute a Rendr App function?


I'm investigating TestCafe to use as my test automation framework, and I've hit a bit of a stumbling block in regards to executing a function using the Rendr App on my AUT. With Cypress.io, Protractor and Puppeteer etc I'm able to run the same command... so I'm not too sure where I'm going wrong with TestCafe.

Essentially what I'm trying to execute is: window.App.get('currentUser').set('login_state', 'someLoginState');

Cypress

  cy.window().then((win) => {
    win.App.get('currentUser').set('login_state', 'someState');
  });

Protractor

  function changeUserState() {
    App.get('currentUser').set('login_state', 'someState');
  }

  browser.executeScript(changeUserState);

Puppeteer

  function changeUserState() {
    window.App.get('currentUser').set('login_state', 'someState');
  }

  await page.evaluate(changeUserState);

For TestCafe I've tried to use:

const changeUserState = ClientFunction((desiredState) => {
    return App.get('currentUser').set('login_state', desiredState);
});

fixture `User states`
    .page(url)
    .afterEach( async t => {
        await t
            logout();
    });

test('Change a users log in state', async t => {

    await loginForm.loginViaUrl(userEmail, userPassword);
    await changeUserState('SomeState');
    await checkUserState('SomeState');  // Just an example of what I would do next
}

When running this, it throws a ReferenceError: App is not defined error.

(I've also attempted the above options using 'window.App.get...': TypeError: Cannot read property 'get' of undefined - Adding a wait prior to the calling the ClientFunction doesn't affect the oucome)

UPDATE Based on comments, the t.eval(...) option shouldn't be used as I'm accessing client side functionality.


Solution

  • I think the problem is related to the fact that the App variable is not defined. So you should wait until it becomes available. You can use the wait action with the fixed waiting time or use the following selector to wait until an element appears on the page:

    await Selector('element that tells us that App exists')
    

    UPD: Having examined the test example you provided in your Github issue, we found a solution for you. It is necessary to wait until the App variable appears. Add the following code before the changeUserState function call:

    // first case
    const getPageUrl = ClientFunction(() => location.toString());
    
    await t.expect(getPageUrl()).eql('https://www.change.org/', { timeout: 5000 });
    // second case
    const isAppExists = ClientFunction(() => !!window.App);
    
    await t.expect(isAppExists()).ok({ timeout: 5000 });
    

    UPD from the GitHub comment:

    import { Selector, ClientFunction } from 'testcafe';
    
    fixture`Change User State`.page('www.change.org');
    
    const isAppExists = ClientFunction(() => !!window.App);
    
    const changeUserState = ClientFunction((desiredState) => {
        const initialState = App.get('currentUser').get('login_state');
        App.get('currentUser').set('login_state', desiredState);
        const currentState = App.get('currentUser').get('login_state');
        return { initialState, currentState };
    });
    
    test
        ('Start from homepage', async t => {
            await t
                .maximizeWindow()
                .navigateTo('/login_or_join')
                .typeText(Selector('#content input[type="email"]'), '*****')
                .typeText(Selector('#content input[type="password"]'), '*****')
                .click(Selector('#content input[type="submit"]'))
                .expect(isAppExists()).ok(); // wait for App
    
            console.log(await changeUserState('guest'));
    });
    

    Result:

    Running tests in:
    - Chrome 74.0.3729 / Windows 10.0.0
    
    Change User State
    { initialState: 'authenticated', currentState: 'guest' }
     √ Start from homepage
    
    
     1 passed (15s)