How to submit a form in Geb (WebDriver) that has no submit button - testing

I'm building up a test in Geb (WebDriver) that has the need to work with a form that has no submit button. From the user's perspective, it is as simple to use as typing in the search term and hitting the enter key on their keyboard.
Using Geb in a purely script form I can get around this by appending the special key code to the text being typed in, as seen in the following:
import org.openqa.selenium.Keys
$('input[id=myInputField]') << "michael"+Keys.ENTER
That works fine. But if I want to use Geb's recommended Page Object pattern (http://www.gebish.org/manual/0.7.1/pages.html#the_page_object_pattern), I don't see what I should do. What do I define in the content section of my EmployeeSearchPage object to duplicate the missing searchButton and its "to" object reference that tells Geb how to handle the resulting page?
class EmployeeSearchPage extends Page {
static url = "http://localhost:8888/directory/"
static at = { title == "Employee Directory" }
static content = {
searchField { $("input[id=myInputField]") }
// THE FOLLOWING BUTTON DOESN'T EXIST IN MY CASE
searchButton(to: EmployeeListPage) { $("input[value='SUBMIT']") }
}
}
I realize that I could add a submit button to the form that I could for the test and use CSS to position it out of the user's view, but why should I have to adapt the app to the test? Things should work the other way around.
I've been evaluating a lot of web testing frameworks and find that this type of form presents a problem for many of them - at least as far as their documentation is concerned.
Any ideas? Thanks!

You don't need to use js integration to achieve what you want.
You can also define methods on your page class, not only content. You could implement a submit method that would do what you are looking for in the following way:
class EmployeeSearchPage extends Page {
static url = "http://localhost:8888/directory/"
static at = { title == "Employee Directory" }
static content = {
searchField { $("input[id=myInputField]")
}
void submitForm() {
searchField << Keys.ENTER
browser.page EmployeeSearchResultsPage
}
}
and then to use it:
to EmployeeSearchPage
searchField << 'michael' // searchField = 'michael' would have the same effect
submitForm()

Geb provides support to execute JavaScript in the context of the browser, details can be found here in the Geb documentation.
You could use this to submit the form exactly like you would submit it using JavaScript in the webapp itself. For example, if you are using jQuery it would be as simple as:
js.exec('$("#myForm").submit()')

Related

How to access components inside a custom ToolWindow from an action?

I have registered an action in the EditorPopupMenu (this is right click menu). I also have a bunch of components inside a ToolWindow (that I designed using the GUI Designer plugin) that I want to update the values of.
There have been some posts on the IntelliJ forums about this, and the typical answer seems to advice using the ToolWindow's ContentManager, and obtain the JPanel containing all your components. E.g. the following:
Project p = e.getProject();
ToolWindow toolWindow;
toolWindow = ToolWindowManager.getInstance(p).getToolWindow("My ToolWindow ID");
ContentManager contentManager = toolWindow.getContentManager();
JPanel jp = (JPanel) contentManager.getContent(0).getComponent();
This feels counterintuitive... Having to navigate inside JPanel's to find a bunch of components. What if I decided to put my components inside a different container? Suddenly the way I navigate to my components would break down.
Is it really the most practical way to constrain myself to the way my GUI is built? Can't I access these components in a different way?
I found a way to access my custom myToolWindow. This should help quite some people.
Make sure that your custom MyToolWindow extends the class SimpleToolWindowPanel.
In your custom myToolWindowFactory class, pass your custom MyToolWindow to ContentFactory.createContent() as the first argument. NOT one of the JPanel's inside MyToolWindow as is done in the ToolWindow examples given in the official IntelliJ documentation...
In your MyToolWindow constructor, call the method setContent(<YourJPanelContainingYourComponents>).
I found the answer by experimenting on example 5 from this link:
public JBTabbedTerminalWidget getTerminalWidget(ToolWindow window) {
window.show(null);
if (myTerminalWidget == null) {
JComponent parentPanel = window.getContentManager().getContents()[0].getComponent();
if (parentPanel instanceof SimpleToolWindowPanel) {
SimpleToolWindowPanel panel = (SimpleToolWindowPanel) parentPanel;
JPanel jPanel = (JPanel) panel.getComponents()[0];
myTerminalWidget = (JBTabbedTerminalWidget) jPanel.getComponents()[0];
} else {
NotificationUtils.infoNotification("Wait for Freeline to initialize");
}
}
return myTerminalWidget;
}

How can I provide a tag that would run my cucumber background once for all scenarios?

I am using cucumber-js
I have some slides within the same url. For my feature, I want to provide the tester a way to open a url, and then have multiple scenarios on the same url:
The problem with the solution below is that the url re-opens for every scenario, reseting the slide to the start. I can never test each slide step as a separate scenario.
Any help or suggestion appreciated: example:
Feature: Valuation slide user journey - pre-reqisite As a developer I want to open the url /valuation/
Background:
Given I open the url "/valuation/"
Scenario: Test valuation slide button
Given the element "valuationIntro" is visible
When I click on the button "valuationIntro.cta"
Then I expect that element "valuationSlide1" becomes visible
Scenario: Test valuation autocomplete
Given the element "valuationSlide1.cta" has the class "invalid"
When I set "jk5 7kj" to the inputfield "valuationSlide1.autocomplete"
Then I expect that element "valuationSlide1.cta" does not have the class "invalid"
I understand I can use tags, but not entirely sure how I can use a tag to run a background once.
var executed = false;
var myStepDefinitionsWrapper = function () {
this.Given(/^I open the url "([^"]*)"$/, function (url) {
if (!executed)
// do some work with url
executed = true;
});
};
module.exports = myStepDefinitionsWrapper;
Just a simplification to make a point. I would use singletons with state.

Web browser control, modal window/popup to STAY INSIDE web browser control for Visual Studio 2015/Visual Basic 2015

this is the first time I'm posting a question here; I have searched and searched and searched here and other places and I cannot seem to get any results. I'm using VISUAL BASIC 2015 in Visual Studio 2015. QUESTION: I need to have a modal window/popup from a particular website remain INSIDE the web browser control/window on my form (WebBrowser1); when a particular link is clicked, the modal window/popup jumps out of the form and directly to the user on their screen. I have to keep this popup inside because there are other links to be clicked on that popup, but if it jumps out of the web browser control, no code will work since it's outside WebBrowser1. What I have found is code for older versions, and not 2015; if anything I can even add WebBrowser2 to have the popups/modal windows appear there if possible, just as long as I can code them to keep clicking inside the form. PLEASE HELP! THANK YOU!
window.open (and a click on <a target="_blank"> etc) can be handled via the NewWindow2 event. Hans already pointed out how to do that in comments. NewWindow3 works too, but need at least Windows XP SP2.
As for window.showModalDialog, it is a bit tricky. IE has IDispatchEx (wrapped as IExpando in .Net) implemented on scripting objects so you replace the methods and properties with your own implementation. But window.showModalDialog shows a dialog that has arguments and return values, you need to override those properties in the modal dialog you create too. The code looks roughly like tis:
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//skip events from frames
if(WebBrowserReadyState.Complete!=webBrowser1.ReadyState) return;
if(FindLoginFormOnPage()) {DoLogin();return;}
if(IsWelcomePage()){NavigateToPage1();return;}
if(IsPage1()){SubmitFormOnPage1();return;}
if(IsPage1FormResult()){
var document=webBrowser1.Document.DomDocument as mshtml.ITMLDocument2;
var expando =(IExpando)document.parentWindow;
expando.RemoveMember(expando.GetMethod("showModalDialog"
,BindingFlags.Instance | BindingFlags.Public);
expando.AddMethod("showModalDialog"
,new ShowModalDialogDelegate(this.MyShowModalDialog));
}
......
}
object MyShowModalDialog(string url, object varArgIn, object options)
{
using(FromMyShowModalDialog myShowModalDialog
=new MyShowModalDialog())
{
myShowModalDialog.StartupUrl=url;
myShowModalDialog.DialogArguments=varArgIn;
//omit the code to parse options
//and set dialog height/width/topleft location etc
if(myShowModalDialog.ShowDialog()==DialogResult.OK)
{
//do something on the return value before passing to the scripts
......
return myShowModalDialog.ReturnValue;
}
return null;
}
}
and in the Load event handler of MyShowModalDialog you call something like webBrowser1.Navigate to show the page requested by the parent page.
Now you need to pass the arguments to the webbrowser control on the new form. Do the same as above but replace another property this time.
expando.RemoveProperty("dialogArguments");
expando.AddProperty("dialogArguments")
.SetValue(expando,this.DialogArguments);
This will let the web page access the value passed from MyShowModalDialog and stored in this.DialogArguments.
The earliest you can access the DOM is in webBrowser1_DocumentCompleted. By that time the scipts on the page that read window.dialogArguments are probably already executed and got nothing. After overriding window.dialogArguments, you need to study the script on the page to find out how to revert that. for example, if the page has
<head>
<script>
var oMyObject = window.dialogArguments;
var sFirstName = oMyObject.firstName;
var sLastName = oMyObject.lastName;
</script>
...
<span style="color: 00ff7f">
<script>
document.write(sFirstName);
</script>
</span>
you need to change the values of sFirstName and sLastName then change the innerText property of the span, probably identify via its relationship with a named div or table cell. You can write the necessary changes in a script and call it via HtmlDocument.InvokeScript.
If the page returns a value to its parent, you need to pass it on to your parent form too. Override window.returnValue so when the script writes to window.returnValue it writes to a variable you provided
......
expando.RemoveProperty("returnValue");
expando.AddProperty("returnValue").SetValue(expando,this.ReturnValue);

Window phone - How to redirect to page xaml form web browser control?

I have two page xaml contain web browser control to display html string.For example,
page1.xaml : Contain webbrowser control (will display html string to web browser control)
page2.xaml : Contain webbrowser control
Question is : When user click a tag hyperlink in page1.xaml and how to redirect to page2.xaml
you can simply use the java script function that call the your native C# function by this you can call the native function from web browser and redirect the page.
so please create the one html file inside the html use the Javascript function that call the native function or notify from there.
You need to inject Javascript in the HTML that will enumerate all a tags and wire up an onclick event. That event will call window.external.Notify which will in turn raise the ScriptNotify event of the WebBrowser, with the URL as a parameter.
Here is the code:
// Constructor
public MainPage()
{
InitializeComponent();
browser.IsScriptEnabled = true;
browser.ScriptNotify += browser_ScriptNotify;
browser.Loaded += browser_Loaded;
}
void browser_Loaded(object sender, RoutedEventArgs e)
{
// Sample HTML code
string html = #"<html><head></head><body><a href='http://www.google.fr'>Google</a></body></html>";
// Script that will call raise the ScriptNotify via window.external.Notify
string notifyJS = #"<script type='text/javascript' language='javascript'>
window.onload = function() {
var links = document.getElementsByTagName('a');
for(var i=0;i<links.length;i++) {
links[i].onclick = function() {
window.external.Notify(this.href);
}
}
}
</script>";
// Inject the Javascript into the head section of the HTML document
html = html.Replace("<head>", string.Format("<head>{0}{1}", Environment.NewLine, notifyJS));
browser.NavigateToString(html);
}
void browser_ScriptNotify(object sender, NotifyEventArgs e)
{
if (!string.IsNullOrEmpty(e.Value))
{
// Navigate to Page2.xaml
NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));
}
}
The solution that you are looking for is deeplinking your app to listen to custom URL protocols.
First setup your solution to listen to custom URLs. Follow the URI association section in this MSDN document. http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206987(v=vs.105).aspx#BKMK_URIassociations
Next in your web browser when you display a link make sure it is an absolute URL starting with your own protocol and NOT http or https.
So, your final url in the web browser must contain something like that: my_protocol://abc.xaml
In the AssociationURIMapper class, you catch such URLs and navigate to the desired XAML page.
This solution will not only enable your app to open from a web browser but also from other applications on windows phone!

Why isn't the page data tab showing in the Designer?

I'm editing a page in the ToolTwist Designer, and I have all the normal tabs shown - edit page, navpoint, test page, source, etc, but the "Page Data" tab is not showing. How can I make the tab show, so I can enter page data for my page?
The page data tab only appears if there is a widget on your page that requires page data. You also need to editing the navpoint, rather than the page, because the page data belongs to the navpoint, and a single page definition might be shared by many navpoints. In other words, the page data allows widgets to appear different at various locations (navpoints) within the website.
If you are developing a widget that you wish to have use page data, you need to do the following:
In the Widget Controller class, implement the "UsesPageData" interface. This tells the Designer that the page data tab needs to be displayed when you click on a navpoint that references a page that included this widget, and on the tab it creates a section where the XML for this widget can be entered, specific to that particular navpoint.
public class CarouselTab extends WbdWidgetController implements UsesPageData
To give the user an indication of what XML the widget expects, you need to implement a method that returns template XML code. For example:
public XData getInitialPageData(WbdWidget instance)
{
StringBuffer xml = new StringBuffer();
xml.append("\n");
xml.append("\n");
xml.append(" id01\n");
xml.append(" [Label 01]\n");
xml.append(" [Add your widget here 01]\n");
xml.append("\n");
xml.append("\n");
xml.append(" id02\n");
xml.append(" [Label 02]\n");
xml.append(" [Add your widget here 02]\n");
xml.append("\n");
xml.append("");
return new XData(xml);
}
Define a property that defines a name to be displayed above where you enter the XML on the page data tab:
protected void init(WbdWidget instance) throws WbdException
{
instance.defineProperty(new WbdStringProperty("pageDataSection", null, "PageDataSection", ""));
...
}
Use the page data when you are generating the page:
#Override
public void renderForJSP(WbdGenerator generator, WbdWidget instance, UimHelper ud, WbdRenderHelper rh) throws WbdException
{
...
Xpc xpc = ud.getXpc();
xpc.start("tooltwist.wbd.getPagedata", "select");
xpc.attrib("navpointId", WbdSession.getNavpointId(ud.getCredentials()));
xpc.attrib("pageDataSection", pageDataSection);
XData pagedata = xpc.run();
// Do something with the page data
...
}