Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seleno: Using strongly typed controller action expressions to navigate to the page via routing. #239

Open
wijdenchebbi opened this issue Feb 4, 2016 · 11 comments

Comments

@wijdenchebbi
Copy link

Hi,
I am a software engineer, my task is to realise an test acceptance for ASP.net MVC C# project.
I want to generate the page object by specifying navigation by selecting a controller and action (rather than a Url string). this is my code:

_EditCustomerPage = BrowserHost.Instance.NavigateToInitialPage<ClientController,  EditCustomerPage>(x => x.Edit(10)); 

And i add an instance of seleno host:

  Instance.Run("Project", 13050, configure =>
 {      configure.WithRouteConfig(RouteConfig.RegisterRoutes);
 });

And the link generated is wrong:http://localhost:13050/fr/?Controller=Client&Action=Edit&id=22
Can you help me? Thanks

@robdmoore
Copy link
Member

You need to use the appropriate configuration overload to register a route table that contains the routes from your mvc project.

Let me know if you want me to dig up an example code snippet from our example projects.

On 5 Feb 2016, at 1:06 am, wijdenchebbi [email protected] wrote:

Hi,
I am a software engineer, my task is to realise an test acceptance for ASPnet MVC C# project
I want to generate the page object by specifying navigation by selecting a controller and action (rather than a Url string) this is my code:
_EditCustomerPage = BrowserHostInstanceNavigateToInitialPage(x => xEdit(10));
And i add an instance of seleno host:
InstanceRun("Project", 13050, configure =>
{ configureWithRouteConfig(RouteConfigRegisterRoutes);
});
And the link generated is wrong:http://localhost:13050/fr/?Controller=Client&Action=Edit&id=22
Can you help me? Thanks


Reply to this email directly or view it on GitHub.

@mwhelan
Copy link
Member

mwhelan commented Feb 5, 2016

Hi @wijdenchebbi. Here is an example from our docs, where RouteConfig.RegisterRoutes would be the method that configures the routes in your web application:

 public static class Host
 {
     public static readonly SelenoHost Instance = new SelenoHost();

     static Host()
     {
         Instance.Run("Name.Of.Your.Web.Project", 12346, c => c
             .UsingLoggerFactory(new ConsoleFactory())
             // If you are using MVC then do this where RouteConfig is the class that registers your routes in the "Name.Of.Your.Web.Project" project
             // If you aren't using MVC then don't include this line
             .WithRouteConfig(RouteConfig.RegisterRoutes)
         );
     }
 }

You can read more about it here.

@wijdenchebbi
Copy link
Author

Thanks for getting back so quickly.

i used the appropriate route table, when i used a static URL ,it works correctly, but when i used the controller and action it doesn't work.

@robdmoore
Copy link
Member

Can you paste in your configuration code?

And the navigation code?

On 5 Feb 2016, at 7:08 pm, wijdenchebbi [email protected] wrote:

Thanks for getting back so quickly.

i used the appropriate route table, when i used a static URL ,it works correctly, but when i used the controller and action it doesn't work.


Reply to this email directly or view it on GitHub.

@wijdenchebbi
Copy link
Author

To have an instance on seleno host i make the class BrowserHost

public static class BrowserHost
{

    public static readonly SelenoHost Instance = new SelenoHost();
    static BrowserHost()
    {
            Instance.Run("BigBrother.MVC.Intranet", 13050, configure => configure
            .WithRouteConfig(BigBrother.MVC.Intranet.MvcApplication.RouteConfig.RegisterRoutes)
            .WithMinimumWaitTimeoutOf(System.TimeSpan.FromSeconds(3))
          );
    }
}

the navigation code used in a method in the class EditCustomerStory.cs

  private void AndIAmOnTheEditAdministrativeInfosPage()
    {
        _EditCustomerPage = BrowserHost.Instance.NavigateToInitialPage<ClientController, EditCustomerPage>(x => x.Edit(22)); 
    }

EcitCustomerPage.cs is the page object
ClientController.cs is the controller in my project

@wijdenchebbi
Copy link
Author

Hi,

when i use a static URL:
_EditCustomerPage = BrowserHost.Instance.NavigateToInitialPage("/fr/Client/Edit/22");
Sometimes it works and sometimes it doesn't, i don't know what to do.
Can you help me

@robdmoore
Copy link
Member

Re: your first problem, if you use Navigate.To<Clientcontroller, EditCustomerPage>(c => c.Edit(22)); within a page object (i.e. ignoring NavigateToInitialPage for now) does that work? I'm trying to ascertain if there is a bug in NavigateToInitialPage using the controller syntax or if there is still a configuration issue on your side. I know for a fact that Navigate.To works because we use that in our acceptance tests.

Re: your second problem when you say "sometimes it doesn't" work what do you mean? Do you get an exception? Does the page change, but to the wrong URL? Does nothing happen? ...

Thanks :)

@wijdenchebbi
Copy link
Author

Thanks for your response,
I tried to use Navigate.to:
_EditCustomerPage = BrowserHost.Instance.Navigate.To<ClientController, EditCustomerPage>(x => x.Edit(22));
but i get this error: TestStack.Seleno.Configuration.SelenoHost' does not contain a definition for 'Navigate' and no extension method 'Navigate' accepting the first argument.
And when I used NavigateToInitialPage, the url generated is wrong:
http://localhost:13050/en/?Controller=Client&Action=Edit&id=22
In my second prob:When i used a static URL, the seleno navigate to wrong url like: localhost:13050/fr/Account/LogOn?ReturnUrl=%2ffr%2fClient%2fCreate

@mwhelan
Copy link
Member

mwhelan commented Feb 16, 2016

Hi @wijdenchebbi . Your second problem looks like the URL you are trying to navigate to requires authorization and so it is redirecting you to the login page. You will have to login earlier in the test before making that call.

With regards to your Navigate.To method, you need to add the generic arguments to the call.

It's quite hard to know what is happening with the NavigateToInitialPage method. Could you possibly provide a small sample of code that I can download and look at more closely? You might also want to install MvcRouteTester and try the same controller/action combinations you are trying here and see if you get the results you expect. (Our code is generating URL from the route table in a similar way to MvcRouteTester).

@wijdench
Copy link

Hi,
In my test, i verify the login issue in the first step in my scenario.
For my code:
BrowserHost.cs
`using BigBrother.MVC.Intranet;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using TestStack.Seleno.Configuration;
using TestStack.Seleno.Configuration.WebServers;
namespace BigBrother.MVC.Intranet.UITests
{
public static class BrowserHost
{

    public static readonly SelenoHost Instance = new SelenoHost();
    static BrowserHost()
    {
            Instance.Run("BigBrother.MVC.Intranet", 13050, configure =>
           {
            configure.WithRouteConfig(BigBrother.MVC.Intranet.MvcApplication.RouteConfig.RegisterRoutes);
            configure.WithMinimumWaitTimeoutOf(System.TimeSpan.FromSeconds(3));
           });
    }
}

}
The page object: EditCustomerPage.csusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium;
using TestStack.Seleno.PageObjects;
namespace BigBrother.MVC.Intranet.UITests
{
class EditCustomerPage : Page
{
//*********** Test on attributes
public EditCustomerPage EnterName(string Name)
{
Find.Element(By.Id("Name")).Clear();
Find.Element(By.Id("Name")).SendKeys(Name);

        return this;
    }

    //*********** Test on error messages
    public bool IsNameErrorMessageVisible
    {
        get
        {
            return Find.Element(By.ClassName("field-validation-error")).Displayed;
        }
    }

    public T SubmitApplication<T>() where T : UiComponent, new()
    {
        return Navigate.To<T>(By.Id("save"));

    }


}

}
For the story:EditCustomerStory.csusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BigBrother.MVC.Intranet;
using NUnit.Framework;
using TestStack.BDDfy;
using TestStack.Seleno.PageObjects.Locators;
using BigBrother.MVC.Intranet.Controllers;
using TestStack.Seleno.Configuration;
namespace BigBrother.MVC.Intranet.UITests
{
[TestFixture]
[Story(AsA = "As a administrator",
IWant = "I want to modify the administrative information of a client",
SoThat = "So that I can save the modifications",
Title = "Acceptance Tests related to Edit Administrative Information page")]
public class EditCustomerStory
{

    private LoginPage _loginPage;
    private EditCustomerPage _EditCustomerPage;
    private const string userLogin = "[email protected]";
    private const string userPwd = "Montreal2015";
    private const string clientName = "";



    [Test]
    public void EditCustomerErrorMessageVisible()
    {
        this.Given(x => GivenIAmLoggedIn())
            .And(x => AndIAmOnTheEditAdministrativeInfosPage())
            .And(x => AndTheFieldNameIsEmpty())
            .When(x => WhenISaveWithAnEmptyNameField())
            .Then(x => ThenIShouldSeeAnErrorMessage())
            .BDDfy();
    }


    private void GivenIAmLoggedIn()
    {
        _loginPage = BrowserHost.Instance.NavigateToInitialPage<LoginPage>();
        var testlogin = _loginPage.IsLoggedIn();

        if (testlogin)
        {
            _loginPage.Disconnect<LoginPage>();
            _loginPage = BrowserHost.Instance.NavigateToInitialPage<LoginPage>();
            _loginPage.EnterLogin(userLogin)
           .EnterPwd(userPwd)
           .SubmitApplication<LoginPage>();
        }
        else
        {
            _loginPage = BrowserHost.Instance.NavigateToInitialPage<LoginPage>();
            _loginPage.EnterLogin(userLogin)
           .EnterPwd(userPwd)
           .SubmitApplication<LoginPage>();
        }
    }

    private void AndIAmOnTheEditAdministrativeInfosPage()
    {
        _EditCustomerPage = BrowserHost.Instance.NavigateToInitialPage<EditCustomerPage>("/fr/Client/Edit/22");
    }

    private void AndTheFieldNameIsEmpty()
    {
        _EditCustomerPage.EnterName(clientName);
    }

    private void WhenISaveWithAnEmptyNameField()
    {
        _EditCustomerPage.SubmitApplication<EditCustomerPage>();
    }

    private void ThenIShouldSeeAnErrorMessage()
    {
        var isNameErrorMessageVisible = _EditCustomerPage.IsNameErrorMessageVisible;

        Assert.That(isNameErrorMessageVisible, Is.True);
    }
}

}
`
For the UITest, the version of Selenium.WebDriver installed is 2.47.0 and the version of TestStack.Seleno installed is 0.9.11.

@mwhelan
Copy link
Member

mwhelan commented Feb 17, 2016

Hi @wijdenchebbi . It looks like you are using Areas in your URL. If that's the case then you need to use the overload of Navigate (of NavigateToInitialPage and navigation within page objects) that takes a dictionary of route values. I wrote a bit of background about that here.

Another point I would make is that NavigateToInitialPage is only designed to be called once to get you the first page object. From that point on the methods in the page objects should return page objects using the UIComponent Navigate.To method. When using BDDfy methods like you are you will need to have page objects fields that get set by the first method and then the second method will use the same field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants