How to use the autoLogin plugin

:thinking:i was connfused when i watched the guide on the official website.
i dont know how to configure it.
i should add the sample to where?
and my case is that i need a sms code and picture code to login

here is the guide url : https://codecept.io/plugins#autologin

I followed the guide and still don’t quite understand how it works. I added a ‘login’ function to the actor({}) object returned in the function in steps_file.js. I still just keep getting Object of type login is not defined in container

I think a more concrete example would be helpful here.

Scouring the net for answers as we speak

If you are using autoLogin plugin then, you will need a config placed in the plugins section specifically for your autoLogin.

Example:

autoLogin: {
            enabled: true,
            saveToFile: true,
            inject: 'loginAs', // use `loginAs` instead of login
            users: {
                admin: {
                    login: (I) => {
                        I.amOnPage('/login-menu');
                        I.fillField('#login_email', cfg.personas.Admin.username);
                        I.fillField('#login_password', cfg.personas.Admin.pwd);
                        I.click('#login_login');
                    },
                    check: (I) => {
                        I.seeInCurrentUrl('/admin/');
                    },
                },
                servicePro: {
                    login: (I) => {
                        I.amOnPage('/login-menu');
                        I.fillField('#login_email', cfg.personas.servicePro.username);
                        I.fillField('#login_password', cfg.personas.servicePro.pwd);
                        I.click('#login_login');
                    },
                    check: (I) => {
                        I.seeInCurrentUrl('/service-pro/new-service-requests');
                    },
                },
                consumer: {
                    login: (I) => {
                        I.amOnPage('/login-menu');
                        I.fillField('#login_email', cfg.personas.consumer.username);
                        I.fillField('#login_password', cfg.personas.consumer.pwd);
                        I.click('#login_login');
                    },
                    check: (I) => {
                        I.seeInCurrentUrl('/consumer/my-projects');
                    },
                },
            },
        },

Then in your test you call it as follows:

Given('I login as a Service Pro', async () => {
    await loginAs('servicePro');
});

If you are using the Actor approach this is a bit different.
Actor Example:

module.exports = function () {
    return actor({

        // Define custom steps here, use 'this' to access default methods of I.
        // It is recommended to place a general 'login' function here.
        async login() {
            this.amOnPage(`/?sba_transferToken=${conf.testAccount.ssoTransferToken}`);
            const balance = await this.grabTextFrom(loginComponent.headerBar);
            if (typeof balance !== 'string') {
                output.error('Balance not found, login failed');
            }
            console.log(`Logged in as user: ${conf.testAccount.userName}`);
        },
    });
};

In your tests you use it like this:

Before(async () => {
    await I.login();
});
2 Likes

Hello and thanks for the example.

Why do you use:

check: (I) => {
  I.seeInCurrentUrl('/admin/');
},

Instead of:

check: (I) => {
  I.waitForVisible(''selector');
},

I am trying to use the second approach by checking if a UI-element exists, and the test passes even thought I it shouldn’t login because of wrong credentials.

This is my autoLogin plugin configuration and I expect it not to pass as soon as I have put invalid credentials. So the check should not pass

autoLogin: {
  enabled: true,
  saveToFile: true,
  inject: 'LoginAs',
  users: {
    admin: {
      // loginAdmin function is defined in `steps_file.js`
      login: async (I) => await I.loginAdmin(),
      // if we see `Admin` on page, we assume we are logged in
      check: (I) => {
        I.waitForVisible('#navItem_1204785325 > a > div');
      }
    }
  }
}

Oh that was mainly an example, I prefer using a lot more robust solutions for checks. After login in my case, the check has multiple validations to ensure everything worked as expected. I consider waiting for URL change not enough or not a good enough practice to rely solely on it.
As a recommendation I would suggest not using locators like this #navItem_1204785325 > a > div because they increase flakiness of tests. if the a element disappears from the chain your locator will fail and thus your test with it. However a more robust and reliable locator that would work even with UI elements being removed or added is either

  • targeting the div directly with some specific attributes if it has them
  • if the div does not have extra attributes you can add them yourself or ask the devs to do it for you
  • use something like this instead #navItem_1204785325 div it works exactly the same without the reliance on the existence of the a element.

I usually go for options 2 or 3

1 Like