Automation, C#, Java, Selenium

How to Automate a Live Chat App With Multiple Users (C#, Java)

Posted by Kerry

DIFFICULTY: Easy

For most automation purposes, a single, solitary browser instance per test will serve you pretty well.

But think about scenarios when it’s pertinent to verify the behavior of two (or more) unique instances of an application communicating together. Such scenarios can include verifying a multi-threaded logging system, a community forum, or in our instance here, a live chat feature.

How Can We Do This?

OPTION 1: One WebDriver instance on a single browser window.

While using one singular browser on a single Driver instance is definitely an option, it isn’t the best option. This method comes with some significant trade-offs to consider.

To do this, you will most likely need to sign in as one user, perform an action, sign out, sign in as a second user, perform an action, sign out, sign in as the first user… Doesn’t this sound exhausting? This sounds exhausting.

It also sounds like it will take you forever to run your tests, and introduce flakiness, don’t use this method if you can avoid it!

OPTION 2: One WebDriver instance on multiple browser windows.

This is a slightly better option, but not by much, due to one glaring problem: If your application uses credentialing to sign your users in, you are going to share that session between both window instances.

At best, this means you will be exercising a non-real world scenario. More likely, though, your sessions will clash and you’ll experience failures as a result.

OPTION 3: Multiple WebDriver instances on multiple browsers.

Spoiler alert: This is our winner.

In this case, we can ensure each Driver instance carries its own session data, which means you can have multiple separate browser instances with multiple separate users interacting with one another.

This method also most closely resembles a real world scenario, and you can validate interaction between different browser types, too!

Ok, Got It. Let’s Automate!

To test live chat functionality between two Driver instances, we are going to be using the free chat web application Chatzy.

Step 1: Clone the Repository

I will be walking through the code using C#/NUnit, but I have provided the repository for the Java/JUnit code below as well.

Step 2: Create our Homepage Page Model

Chatyz’s homepage contains only a select few elements we need to interact with in order to start a chat, which are the highlighted elements below:

Chaty's home page and elements

So, in our Homepage.cs (or Homepage.java) classes, we are going to create our Homepage class with locators for the above elements and a method to perform the sign in function.

    public class Homepage:BasePageClass
    {
        private readonly IWebDriver _driver;

        public Homepage(IWebDriver Driver):base(Driver)
        {
            _driver = Driver;
        }

        private By Name = By.Id("X8712");
        private By Subject = By.Id("X7728");
        private By CreateChatButton = By.CssSelector(".X8501 input");

        public void SignIn(string name)
        {
            _driver.FindElement(Name).SendKeys(name);
            _driver.FindElement(Subject).SendKeys("chat title");
            _driver.FindElement(CreateChatButton).Click();
        }
    }

Step 3: Create our ChatRoom Page Model

On successful login with our first user, you’ll notice there is a welcome popup we must handle.

Additionally, the only elements we care about at this time are the chat input field, chat message received, and the send chat button.

Chatzy screen upon successful login of the first user.
public class ChatRoom : BasePageClass
{
    private readonly IWebDriver _driver;

    public ChatRoom(IWebDriver Driver):base(Driver)
    {
        _driver = Driver;
    }

    private By RoomCreatedOk = By.CssSelector(".X8501 input");
    private By ChatInputField = By.Id("X9225");
    private By ChatSendButton = By.Id("X1117");
    private By ChatMessage(string user, string message)
    {
        return By.XPath($"//*[text()='{user}']/parent::*[contains(text(),\"{message}\")][last()]");
    }

    public bool ChatMessageExists(string user, string message)
    {
        try
        {
            wait.Until(ExpectedConditions.ElementIsVisible(ChatMessage(user, message)));
            return true;
        }
        catch
        {
            return false;
        }
    }

    //Popup can be finicky and will sometimes throw a stale reference exception. 
    //This will handle the exception gracefully.
    internal void AcceptPopup()
        {
        try{
            wait.Until(ExpectedConditions.ElementToBeClickable(RoomCreatedOk)).Click();
        }    
        catch (StaleElementReferenceException)
        {
            wait.Until(ExpectedConditions.ElementToBeClickable(RoomCreatedOk)).Click();
        }
    }

    public void SendChat(string text)
    {
        _driver.FindElement(ChatInputField).SendKeys(text);
        _driver.FindElement(ChatSendButton).Click();
    }
}

You’ll notice that we implemented methods to handle SendChat, which will fill out the input field and send the text to the chat room. You may also have noticed something interesting about our ChatMessage locator property:

 private By ChatMessage(string user, string message)
    {
        return By.XPath($"//*[text()='{user}']/parent::*[contains(text(),\"{message}\")][last()]");
    }

Here, we are accepting the user who sends the message, as well as their message text value as properties for the By locator.

We are also using the last() xpath function to obtain the very last instance of it in the chat, ensuring we only get the most recent instance of a chat message.

Step 4: Update our Homepage Page Model

We have signed in with a single user who initiated the chat and have implemented methods to handle that flow, but what about our second (or third or fourth!) chat user?

If you copy the chat URL and open it a new browser (either a different browser type, or the same browser in private browsing mode), the new user gets a different sign-in experience:

Additional chat users login screen

So what we need to do is add a method for our new user(s) to log in, but also add a line for our first user to handle the chat pop-up message that displayed in Step 3.

Below is our new, full Homepage class with the updates highlighted.

public class Homepage:BasePageClass
{
    private readonly IWebDriver _driver;

    public Homepage(IWebDriver Driver):base(Driver)
    {
        _driver = Driver;
    }

    private By Name = By.Id("X8712");
    private By Subject = By.Id("X7728");
    private By CreateChatButton = By.CssSelector(".X8501 input");
    private By EnterRoomButton = By.Id("X6668");

    public void SignIn(string name)
    {
        _driver.FindElement(Name).SendKeys(name);
        _driver.FindElement(Subject).SendKeys("chat title");
        _driver.FindElement(CreateChatButton).Click();
        new ChatRoom(_driver).AcceptPopup();
    }

    public void JoinChat(string name)
    {
        _driver.FindElement(Name).SendKeys(name);
        _driver.FindElement(EnterRoomButton).Click();
    }
}

Step 5: The Tests!

In the below test, we are instantiating two browser instances, one for each user, as well as their own Homepage and ChatRoom instances.

We will send a chat using one user’s driver instance, and then verify the receipt of the chat using the second user’s driver instance.

PLEASE NOTE: While we are explicitly creating two browser instances and page models in our test class, this is for the sake of clarity in the demo. It would definitely benefit you to make use of a Driver factory and implement methods to more elegantly handle the multiple windows.

    [TestFixture]
    public class ChatRoomTests 
    {
        //This object will contain all drivers so we can dispose them easily
        public IList<IWebDriver> drivers = new List<IWebDriver>();

        private string applicationPath = "https://www.chatzy.com";
        private string firstUser = "George Harris";
        private string secondUser = "Janet Solis";

        //Instantiate both chat drivers
        private IWebDriver firstDriver;
        private IWebDriver secondDriver;

        //Instantiate page models for both chat drivers
        private ChatRoom firstUserChat;
        private ChatRoom secondUserChat;

        private Homepage firstHomePage;
        private Homepage secondHomePage;

        [SetUp]
        public void SetUp()
        {
            //Initialize first chat driver and accompanying page models
            firstDriver = new ChromeDriver();
            drivers.Add(firstDriver);

            firstUserChat = new ChatRoom(firstDriver);
            firstHomePage = new Homepage(firstDriver);

            firstDriver.Navigate().GoToUrl(applicationPath);
        }

       [TearDown]
       public void TearDown()
       {
           foreach(var driver in drivers)
           {
              driver.Quit();
           }
       }
        [Test]
        public void Validate_Users_Chat_Messages()
        {
            firstHomePage.IsAt();

            //Initialize the second driver and accompanying page models
            secondDriver = new ChromeDriver();
            drivers.Add(secondDriver);
            secondUserChat = new ChatRoom(secondDriver);
            secondHomePage = new Homepage(secondDriver);

            //Sign in as the first user
            firstHomePage.SignIn(firstUser);
            firstUserChat.IsAt();

            //Sign in as the second user using the first user's chat url
            var chatRoomUrl = firstDriver.Url;
            secondDriver.Navigate().GoToUrl(chatRoomUrl);
            secondHomePage.IsAt();
            secondHomePage.JoinChat(secondUser);
            secondUserChat.IsAt();

            //Send chat as first user and verify second user sees the chat notification
            firstUserChat.SendChat("Hello Janet");
            Assert.IsTrue(secondUserChat.ChatMessageExists(firstUser, "Hello Janet"));

            //Send response as second user and verify first user sees the chat notification
            secondUserChat.SendChat("Hi George, what's up?");
            Assert.IsTrue(firstUserChat.ChatMessageExists(secondUser, "Hi George, what's up?"));
        }
    }

And just like that, you’ve automated a live chat function using two separate browsers and sessions!

+3

Related Post

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.