Hi i tried to do a NavigationModule to acces to my content in geb.page, but when i want to instance from this navigation 'module' cannot be resolved by intellij
class NavigationModule extends Module{
static content = {
homeLink { $("a", title:"Home") }
contactLink { $("a", title:"Contact Us") }
}
}
class HomePage extends Page{
static url = "http://www.websitetest.com"
static at={
assert $("h1").text() == "Test website speed and performance"
}
static content = {
navBar {module NavigationModule}
//loginLink { $("a", text: "login")[0]}
}
}
and also I can't access from my script
void test() {
Browser.drive() {
to HomePage
navBar.
}
}
someone know what happen? I spent a lot of time searching in google but i don't find anything
thanks in advance
The Geb doc (http://www.gebish.org/manual/current/ide-and-typing.html#strong_typing) recommends to expecitly define Types to have a better IDE support.
With this example code completion works for me.
class HomePage extends Page {
static url = "http://www.websitetest.com"
static at={
assert $("h1").text() == "Test website speed and performance"
}
static content = {
navBar {module NavigationModule}
//loginLink { $("a", text: "login")[0]}
}
// explicitly define getter to give IntelliJ more type information
NavigationModule getNav() {
navBar
}
}
Test script:
void test() {
Browser.drive() {
// assign to page in order to have code completion on page
page = to HomePage
// code completin for homeLink works
navBar.homeLink
}
}
Related
I'm trying to implement parallel execution of autotests using JUnit 5 and GEB. At the moment, the tests are already running in parallel. The problem is that every page element must be visible at the time the page object is created. If the object was not displayed on the page, then when you try to access it, a new browser object is created with a new page, starting an extra thread. How can this be avoided?
package tests
import geb.Browserimport geb.Pageimport geb.junit5.GebReportingTest
import org.junit.jupiter.api.AfterEachimport org.junit.jupiter.api.BeforeEachimport org.junit.jupiter.api.Testimport org.junit.jupiter.api.extension.ExtendWithimport io.github.bonigarcia.seljup.SeleniumJupiterimport org.openqa.selenium.chrome.ChromeDriver;import pages.CbsLoginPageimport static org.assertj.core.api.Assertions.*
#ExtendWith(SeleniumJupiter.class)class LoginToCbsTest extends GebReportingTest {public Browser browserpublic CbsLoginPage page
#BeforeEach
public void classLevelSetup() {
browser = new Browser()
browser.setDriver(new ChromeDriver())
page = browser.createPage(CbsLoginPage.class)
}
#AfterEach
public void teardown() {
browser.quit()
}
#Test
void loginFailsWhenPasswordIsWrong() {
// When
page.fillCredentialsForm("username", "123_Wrong_password")
page.clickLoginButton()
// Then
verifyLoginErrorIsDisplayed()
}
#Test
void loginFailsWhenUsernameIsWrong() {
// When
page.fillCredentialsForm("Wrong_username", "password")
page.clickLoginButton()
// Then
verifyLoginErrorIsDisplayed()
}
package pages
import geb.Pageimport modules.CbsLoginPageModule
import static geb.Browser.drive
class CbsLoginPage extends Page {static at = { title == "Log in to Application" }
static content = {
loginForm { module(CbsLoginPageModule) }
}
void fillCredentialsForm(String username, String password) {
drive(getBrowser(), {
getBrowser().to(this)
loginForm.loginField.value(username)
loginForm.passwordField.value(password)
})
}
void clickLoginButton() {
drive(getBrowser(), {
getBrowser().at(this)
loginForm.loginButton.click()
})
}
void getErrorMessage() {
drive(getBrowser(), {
getBrowser().at(this)
page
waitFor { $("div", innerHTML: contains("Invalid username or password.")) //This element is not visible when page was created}
})
}
}
package modules
import geb.Module
class CbsLoginPageModule extends Module {
static content = {form { $("form") }
loginField { form.$(id: "name") }
passwordField { form.$(id: "password") }
loginButton { form.$(name: "login") }
}
}
/*This is the Geb configuration file.
See: http://www.gebish.org/manual/current/#configuration
*/
import org.openqa.selenium.chrome.ChromeDriver
waiting {timeout = 2}
environments {
driver = { new ChromeDriver() }
}reportsDir = new File("target/runtime_reports_dir")baseUrl = "url"
plugins {id "idea"id "groovy"}
repositories {mavenCentral()}
dependencies {testImplementation 'io.github.bonigarcia:selenium-jupiter:4.0.1'testImplementation 'org.seleniumhq.selenium:selenium-java:4.1.2'testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'testImplementation 'org.gebish:geb-junit5:5.1'testImplementation 'org.assertj:assertj-core:3.22.0'}
task chromedriverTest(type: Test) {useJUnitPlatform()}
task chromeheadlessTest(type: Test) {useJUnitPlatform()}
test {useJUnitPlatform()testLogging {events "passed", "skipped", "failed"}
systemProperty("junit.jupiter.execution.parallel.enabled" , "true")
systemProperty("junit.jupiter.execution.parallel.config.strategy", "fixed")
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
systemProperty("junit.jupiter.execution.parallel.config.fixed.parallelism", 2)
}
I use Orchard CMS 1.10.1. I have created a content type, now I want to have a section menu in admin page to have specific links for this content type. I want it include New link and content item list for this content type.
How can i achieve this? preferably with no editing in the code.
You can't do this without code, at the same time you will need a small code chunk to achieve this, like the following code:
public class AdminMenu : INavigationProvider {
public Localizer T { get; set; }
public string MenuName {
get { return "admin"; }
}
public void GetNavigation(NavigationBuilder builder) {
builder
.Add(T("Your Content Type Display Name"), "1", menu => menu
.Action("List", "Admin", new { area = "Contents", id = "YourContentTypeName" }));
}
}
The controller is in /Areas/ShoppingCart/Controllers/
I've tried to let the controller return the PartialView which in /Views/Shared folder.
The Code as follows:
namespace MVCIIITourism.Areas.shoppingcart.Controllers
{
public class CartController : Controller
{
public ActionResult GetCart()
{
return PartialView("../../Shared/Views_Cartpatail.cshtml");
}
public ActionResult AddToCart(int id)
{
var currentCart = Operation.GetCurrentCart();
currentCart.AddProduct(id);
return PartialView("../../Shared/Views_Cartpatail.cshtml");
}
}
}
But the chrome shows the error message that is
Not Found PartialView in /Areas/ShoppingCart/Controllers/
How should I fix the problem?
If your partial is in the shared folder you don`t have to pass the entire path
Shared folder it`s access by all controllers
Simple use:
return PartialView("Views_Cartpatail.cshtml");
I'm creating my own IntelliSense Presenter, since Visual Studio2012 support change theme, so I want my background color of the presenter can be auto-changed when the theme been changed. Is there a way to track the theme changes event, or get the current color theme of the Visual Studio?
Yes, this is possible. I had to solve a similiar issue with one of my extensions...
The current theme is stored in the Windows Registry; so I implemented the following utility class.
public enum VsTheme
{
Unknown = 0,
Light,
Dark,
Blue
}
public class ThemeUtil
{
private static readonly IDictionary<string, VsTheme> Themes = new Dictionary<string, VsTheme>()
{
{ "de3dbbcd-f642-433c-8353-8f1df4370aba", VsTheme.Light },
{ "1ded0138-47ce-435e-84ef-9ec1f439b749", VsTheme.Dark },
{ "a4d6a176-b948-4b29-8c66-53c97a1ed7d0", VsTheme.Blue }
};
public static VsTheme GetCurrentTheme()
{
string themeId = GetThemeId();
if (string.IsNullOrWhiteSpace(themeId) == false)
{
VsTheme theme;
if (Themes.TryGetValue(themeId, out theme))
{
return theme;
}
}
return VsTheme.Unknown;
}
public static string GetThemeId()
{
const string CategoryName = "General";
const string ThemePropertyName = "CurrentTheme";
string keyName = string.Format(#"Software\Microsoft\VisualStudio\11.0\{0}", CategoryName);
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName))
{
if (key != null)
{
return (string)key.GetValue(ThemePropertyName, string.Empty);
}
}
return null;
}
}
Okay; this just helps to figur out the current settings... listening for the theme changed notification is a bit trickier. After your package is loaded, you must obtain an IVsShell instance via the DTE; once you have this object you can utilize the AdviceBroadcastMessages method to subscribe for event notifications. You have to provide an object whose type implements the IVsBroadcastMessageEvents interface...
I don´t want to post the whole implementation, but the following lines might illustrate the key scenario...
class VsBroadcastMessageEvents : IVsBroadcastMessageEvent
{
int IVsBroadcastMessageEvent.OnBroadcastMessage(uint msg, IntPtr wParam, IntPtr lParam)
{
const uint WM_SYSCOLORCHANGE = 0x15;
if (msg == WM_SYSCOLORCHANGE)
{
// obtain current theme from the Registry and update any UI...
}
}
}
Consider implementing IDisposable on that type as well, in order to be able to unsubscribe from the event source, when the package gets unloaded.
This is how I subscribe for event notifications...
class ShellService
{
private readonly IVsShell shell;
private bool advised;
public ShellService(IVsShell shellInstance)
{
this.shell = shellInstance;
}
public void AdviseBroadcastMessages(IVsBroadcastMessageEvents broadcastMessageEvents, out uint cookie)
{
cookie = 0;
try
{
int r = this.shell.AdviseBroadcastMessages(broadcastMessageEvents, out cookie);
this.advised = (r == VSConstants.S_OK);
}
catch (COMException) { }
catch (InvalidComObjectException) { }
}
public void UnadviseBroadcastMessages(uint cookie)
{
...
}
}
Keep the value of the cookie parameter; you´ll need it to successfully unsubscribe.
Hope that helps (-:
Just wanted to put an update just in case anyone else comes along.. #Matze and #Frank are totally right.. However in VS 2015.. they added a easy way to detect the theme change. So you need to include PlatformUI an dyou get a super easy event
using Microsoft.VisualStudio.PlatformUI;
....
//Then you get an event
VSColorTheme.ThemeChanged += VSColorTheme_ThemeChanged;
You should make sure your control is disposable so you can unsubscribe from the event...
BONUS!
It also give you easy access to the colors.. even if the user has changed them from the default .. so you can do stuff like this in when set your colors
var defaultBackground = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowBackgroundColorKey);
var defaultForeground = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowTextColorKey);
For VS 2015 this has changed, the solution #Matze has still works but you need to update the GetThemeId() function to check for the version and if it's 14.0 (VS2015) look in a different place in the registry. The way the value is stored has changed also, it's still a string but now contains other values seperated by a '*'. The theme guid is the last value in the list.
if (version == "14.0")
{
string keyName = string.Format(#"Software\Microsoft\VisualStudio\{0}\ApplicationPrivateSettings\Microsoft\VisualStudio", version);
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyName))
{
if (key != null)
{
var keyText = (string)key.GetValue("ColorTheme", string.Empty);
if (!string.IsNullOrEmpty(keyText))
{
var keyTextValues = keyText.Split('*');
if (keyTextValues.Length > 2)
{
return keyTextValues[2];
}
}
}
}
return null;
}
I have a WebApi project and I am trying to add an area to it.
Is there something different that needs to be done when adding a new area to a webapi project vs a mvc4 application?
I have a simple area registration like
public class MobileAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Mobile";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Mobile_default",
"Mobile/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
A controller like
public class BusinessDetailsController : BaseController
{
public string Index()
{
return "hello world";
}
public HttpResponseMessage Get()
{
var data = new List<string> {"Store 1", "Store 2", "Store 3"};
return Request.CreateResponse(HttpStatusCode.OK, data);
}
}
However I can never reach the api. Am I doing something stupid or is there an extra step with the webapi that needs to be done?
Your code registers an MVC route for the Area, not a Web API route.
To do that use the MapHttpRoute extension method (you'll need to add a using statement for System.Web.Http).
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapHttpRoute(
name: "AdminApi",
routeTemplate: "admin/api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
However, Areas are not really supported OOTB in ASP.NET Web API and you'll get an exception if you have two controllers with the same name (regardless of whether they are in different areas).
To support this scenario you need to change the way that controllers are selected. You'll find an article that covers how to do this here.