keep session after login - selenium - javascript

2020-06-25 04:13发布

问题:

I am trying to automate couple of pages using selenium web driver and node js . I was able to login , but after login I want to use same session initiated by web driver so that I can do automated testing on session protected page. This is my attempt

async function login(){
    Let  d =  await new Builder()
                        .forBrowser('chrome')
                        .build();
    await d.get('https://demo.textdomain.com/')
    await d.findElement(By.id('username')).sendKeys('admin ')
    await d.findElement(By.id('password')).sendKeys('admin');
    await d.findElement(By.css('button[type="submit"]')).click();
    d.getPageSource().then(function(content) {

            if(content.indexOf('Welcome text') !==-1 ) {
             console.log('Test passed');
             console.log('landing page');
             d.get('https://demo.textdomain.com/landingpage') //this is still going to login page as i cannot use the previous session 
            } else {
                console.log('Test failed');
                return false;
            }
            //driver.quit();
        });

}

login();

Am I accidentally discarding the browser after login.

回答1:

You might just be dealing with timing issues. Selenium moves very fast. Way faster than you can interact as a user. So it often acts in what seems like unpredictable ways. But that's only because Selenium is acting much faster than you would as a user. In order to work around this, you should make good use of Selenium's built-in driver.wait. For example:

const button = driver.wait(
  until.elementLocated(By.id('my-button')), 
  20000
);

button.click();

The above waits until the button with id my-button is present in the DOM, and then clicks it. It will wait for a maximum of 20000 milliseconds, but will finish as soon as the button becomes available.

So in your case, if there is something that becomes available after the user is successfully logged in, you could wait on that element before going to the new page in your code.

As an aside, I'm also not so sure why you are using getPageSource()? That seems like a very heavy-handed way to get what you are looking for. Isn't that content inside an element you could get the contents of?

I wrote an article about How to write reliable browser tests using Selenium and Node.js which might help you understand in more detail the code example above from the article, along with other techniques you can use to wait reliably for a variety of conditions in the browser.



回答2:

From a similar question on SQA StackExchange, you can store and restore the current session's cookies:

Using Javascript:

// Storing cookies:
driver.manage().getCookies().then(function (cookies) {
    allCookies = cookies;
}); 

// Restoring cookies:
for (var key in allCookies) {
    driver.manage().addCookie(key, allCookies[key]);
}


回答3:

I believe your problem is not properly waiting for the login to complete.

Selenium doesn't wait for asynchronous actions to be done, it moves to the next line, so when you ask for the page source, there is a good chance the login action didn't complete on the server and the result is not what you expect it to be.

you have to explicitly tell Selenium to wait, so you need to add some code between the login and the code that checks if the user is login, for the sake of this assumption, add a 10 seconds timeout.

if this works for you, you wouldn't want to just waste time, so you need to wait for certain elements on the page to change because of the login, for example, you need to wait for the presence (or visibility if it is already in the DOM) of the user photo in the header.

also, I'm not sure how the "getPageSource" function behaves, it can use the existing page, or it can ask for a fresh copy.

I would advise you to use other ways to test if the user is logged in, by inspecting the DOM.



回答4:

I suggest to re-use the session-cookie after first login in other web-driver instances.

First store the cookie:

var cookieValue = firstWebDriver.Manage().Cookies.GetCookieNamed(name:"cookie_name");

Then you can pass it by to any WebDriver instance, set it and drive the web-app as it would be the same user with different browser instances:

anotherWebDriver.Manage().Cookies.AddCookie(new Cookie(name:"cookie_name", value:cookieValue));

If you want to use the same browser instance, you have to synchronize them, because WebDriver invocations are in general not thread-safe and would probalby often lead to exceptions (e.g. stale because an element was changed or notfound, because one web-driver navigated to a different page).

Then I suggest to just use the window handle for the next instance, without caring about the session. The first one opens and the last one closes the session (count the referenced handles) and be sure only one driver uses this handle at a time. You can also create new browser windows and this will keep the session and give you a new handle:

var handle = firstWebDriver.CurrentWindowHandle;
otherWebDriver.SwitchTo().Window(handle);

I wrote the code in C# but should be easily adaptable to JavaScript.