KarinaCampaharo / AutomationSelenium

0 stars 0 forks source link

An example to implement Singleton WebDriverFactory and BasePage in order to have shared driver instance #1

Open yasenltd opened 1 month ago

yasenltd commented 1 month ago

Hi again! In general, I suggest you to do this as a very basic step:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

public class WebDriverFactory
{
    private static IWebDriver _driver;

    public static IWebDriver GetDriver()
    {
        if (_driver == null)
        {
            _driver = new ChromeDriver();
            _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
        }
        return _driver;
    }

    public static void CloseDriver()
    {
        if (_driver != null)
        {
            _driver.Quit();
            _driver = null;
        }
    }
}
public abstract class BasePage
{
    protected readonly IWebDriver _driver;

    protected BasePage(IWebDriver driver)
    {
        _driver = driver;
    }

    // Common method to navigate to a page
    public void NavigateTo(string url)
    {
        _driver.Navigate().GoToUrl(url);
    }
}
public class LoginPage : BasePage
{
    private readonly WebDriverWait _wait;

    // Constructor that accepts the WebDriver instance and passes it to the base class
    public LoginPage(IWebDriver driver) : base(driver)
    {
        _wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10)); // Explicit wait for 10 seconds
    }

    // Elements located explicitly using By selectors
    private IWebElement UsernameField => _wait.Until(ExpectedConditions.ElementIsVisible(By.Id("username")));
    private IWebElement PasswordField => _wait.Until(ExpectedConditions.ElementIsVisible(By.Id("password")));
    private IWebElement LoginButton => _wait.Until(ExpectedConditions.ElementIsVisible(By.Id("loginButton")));

    // Methods to interact with the page
    public void EnterCredentials(string username, string password)
    {
        UsernameField.SendKeys(username);
        PasswordField.SendKeys(password);
    }
}
using TechTalk.SpecFlow;
using OpenQA.Selenium;

[Binding]
public class LoginSteps
{
    private readonly IWebDriver _driver;
    private readonly LoginPage _loginPage;
    private readonly DashboardPage _dashboardPage;

    public LoginSteps()
    {
        // Get the shared WebDriver instance from the factory
        _driver = WebDriverFactory.GetDriver();

        // Pass the shared WebDriver instance to the page objects
        _loginPage = new LoginPage(_driver);
        _dashboardPage = new DashboardPage(_driver);
    }

    [Given(@"I navigate to the login page")]
    public void GivenINavigateToTheLoginPage()
    {
        _loginPage.NavigateTo("https://example.com/login");
    }

    [When(@"I enter my credentials")]
    public void WhenIEnterMyCredentials()
    {
        _loginPage.EnterCredentials("testuser", "password123");
    }

    [When(@"I click the login button")]
    public void WhenIClickTheLoginButton()
    {
        _loginPage.ClickLogin();
    }

    [Then(@"I should see the dashboard")]
    public void ThenIShouldSeeTheDashboard()
    {
        Assert.IsTrue(_dashboardPage.IsDashboardVisible());
    }

    // AfterScenario hook to close WebDriver after the scenario is finished
    [AfterScenario]
    public void AfterScenario()
    {
        WebDriverFactory.CloseDriver();
    }
}
KarinaCampaharo commented 1 month ago

Hi @yasenltd, thank your help.

but I have some doubts: public abstract class BasePagee and public class WebDriverFactory

Should these two code snippets be in the same file?

and the private readonly DashboardPage variable _dashboardPage;

was not found anywhere, display error:

public class LoginSteps { private readonly IWebDriver _driver; private readonly LoginPage _loginPage; private readonly DashboardPage _dashboardPage; //???

public LoginSteps()
{
    // Get the shared WebDriver instance from the factory
    _driver = WebDriverFactory.GetDriver();

    // Pass the shared WebDriver instance to the page objects
    _loginPage = new LoginPage(_driver);
   //_dashboardPage = new DashboardPage(_driver);
}
yasenltd commented 1 month ago

public abstract class BasePage and public class WebDriverFactory should be two different classes. The "private readonly DashboardPage variable _dashboardPage;" is just an example page class that does not exist. My idea was to illustrate how to have multiple Page classes into a single Step class. You will create those PageObject classes. I have only schemed the LoginPage but you can have more with names of your application pages.

On Tue, 1 Oct 2024 at 14:59, KarinaCampaharo @.***> wrote:

Hi @yasenltd https://github.com/yasenltd, thank your help.

but I have some doubts: public abstract class BasePagee and public class WebDriverFactory

Should these two code snippets be in the same file?

and the private readonly DashboardPage variable _dashboardPage;

was not found anywhere, display error:

public class LoginSteps { private readonly IWebDriver _driver; private readonly LoginPage _loginPage; private readonly DashboardPage _dashboardPage; //???

public LoginSteps() { // Get the shared WebDriver instance from the factory _driver = WebDriverFactory.GetDriver();

// Pass the shared WebDriver instance to the page objects
_loginPage = new LoginPage(_driver);

//_dashboardPage = new DashboardPage(_driver); }

— Reply to this email directly, view it on GitHub https://github.com/KarinaCampaharo/AutomationSelenium/issues/1#issuecomment-2385587032, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJA7I5WD4BF4S7IIGVNIFMLZZKFCBAVCNFSM6AAAAABPFDD57CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGOBVGU4DOMBTGI . You are receiving this because you were mentioned.Message ID: @.***>

KarinaCampaharo commented 1 month ago

Okay, got it.

I was thinking about not creating a Login feature file. Just create a class and pass it on to other feature files for the test scenarios I want to run. Is it a good practice?

My question is how to be able to use login for other .feature files. I couldn't understand that.

yasenltd commented 1 month ago

By feature files you mean the Specflow classes in which Scenarios are placed or the step binding classes in which the logic behind the steps is described?

On Tue, 1 Oct 2024 at 16:19, KarinaCampaharo @.***> wrote:

Okay, got it.

I was thinking about not creating a Login feature file. Just create a class and pass it on to other feature files for the test scenarios I want to run. Is it a good practice?

— Reply to this email directly, view it on GitHub https://github.com/KarinaCampaharo/AutomationSelenium/issues/1#issuecomment-2385807304, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJA7I5SJGBEGKBYGS7HV2ZLZZKONPAVCNFSM6AAAAABPFDD57CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGOBVHAYDOMZQGQ . You are receiving this because you were mentioned.Message ID: @.***>