Webdriver not saving entries - webdriver

I have a simple login page that I am testing using Webdriver. I have the user and password fields declared as webelements, which I look by id. Same with the sign-up button. I populate the user, and password fields before hitting sign-up, but things happen so fast, that it looks like sign up gets clicked before the user and p/w fields get populated, thereby always resulting in an error stating that the two fields cannot be empty. This does not always happen though. To be sure, I inserted a Thread.sleep after user and password setters, but didn't see any change. I can see that the fields get filled, and there is a wait time (which I introduced through sleep), but when the sign-up button is clicked, the user and password fields become red again as if they were not filled before hitting continue. I used Webdriver's fluent API to make sure the buttons are all available to be clicked, but that also didn't make a difference. Has anyone seen this behavior before? How did you solve it? (I haven't attached a code snippet here, since the scenario is really very basic).
Edit : Attaching the code snippet here :
#FindBy(id = "signUp_id")
WebElement signUpButton;
#FindBy(id = "UserName")
WebElement userNameElement;
#FindBy(id = "Password")
WebElement passwordElement;
writeInTextField(call(By.id("UserName")), userName);
writeInTextField(call(By.id("Password")), password);
Thread.sleep(10000);
call(By.id("signUp_id")).click();
public WebElement call(final By locator) {
WebElement webElement = fluentWait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
});
return webElement;
}
public void writeInTextField(WebElement we, String sText) {
we.clear();
we.sendKeys(sText);
}
I initialize fluentWait variable as :
fluentWait = new FluentWait<WebDriver>(driver).withTimeout(waitTimeOutInSeconds,
TimeUnit.SECONDS).pollingEvery(pollingInterval,
TimeUnit.MILLISECONDS).ignoring(NoSuchElementException.class,
StaleElementReferenceException.class);

This is more of common,
f developers have used any js based actions to verify fields are filled properly.
You should try entering "tab" character after doing "sendKeys". And then it should work.
I am using qaf, which has listeners capabilities and I am doing 'clear" of webelement via listener whenever click happens which makes actual code look clean.

Related

Using CEFSharp ILifeSpanHandler interface to Handle Popups

I have an issue with handling popups. I have implemented ILifeSpanHandler and OnBeforeBrowse (amoungst others) from the IRequestHandler.
How do I know in the ILifeSpanHandler what URL is being called? I am unable to get it in either the OnAfterCreated or OnBeforePopup. Currently I see it first in OnBeforeBrowse.
I have no code as my question is a "How to". In OnBeforePopup I have checked targetUrl however it seems to be there for decoration as I have read that it is not implemented anyway. I have also looked at the browner/chromiumWebBrowser objects, browser and newBroswer seem to be nothing. One would expect in OnAfterCreated chromiumWebBrowser would return an object but it is nothing in my case.
I am testing with the following
Public Sub OnAfterCreated(chromiumWebBrowser As IWebBrowser, browser As IBrowser) Implements ILifeSpanHandler.OnAfterCreated
Try
Debug.Print(vbNewLine)
Debug.Print("OnAfterCreated")
Debug.Print(String.Concat("OnAfterCreated - MainFrame.Url "), browser.MainFrame.Url)
Debug.Print("OnAfterCreated")
Debug.Print(vbNewLine)
Catch ex As Exception
End Try
End Sub
And I have the following
Public Function OnBeforePopup(chromiumWebBrowser As IWebBrowser, browser As IBrowser, frame As IFrame, targetUrl As String, targetFrameName As String, targetDisposition As WindowOpenDisposition, userGesture As Boolean, popupFeatures As IPopupFeatures, windowInfo As IWindowInfo, browserSettings As IBrowserSettings, ByRef noJavascriptAccess As Boolean, ByRef newBrowser As IWebBrowser) As Boolean Implements ILifeSpanHandler.OnBeforePopup
Try
Debug.Print(vbNewLine)
Debug.Print("OnBeforePopup")
Debug.Print(String.Concat("OnBeforePopup - targetUrl "), targetUrl)
Debug.Print(String.Concat("OnBeforePopup - browser.MainFrame.Url "), browser.MainFrame.Url)
Debug.Print(String.Concat("OnBeforePopup - chromiumWebBrowser.Address "), chromiumWebBrowser.Address)
Debug.Print("OnBeforePopup")
Debug.Print(vbNewLine)
Catch ex As Exception
End Try
Return False
End Function
I have seen different approaches in handling popups using ILifeSpanHandler interface. One approach that I've seen also here in Stack Overflow and was accepted as the correct answer to that particular question is to return true in the OnBeforePopup implementation of ILifeSpanHandler then pass the targetURL argument to a handler that creates the popup.
This approach is very unideal because you are destroying the link between the page that actually opened the popup and the popup itself. If you access via JavaScript the opener property of the window object inside the popup you would notice that it is null. And the page that opened the popup would never know that the popup was actually opened because returning true cancels the creation.
The other approach is to let Cef create the popup and the programmer just decides whether to show the browser as a popup window or a child to control (like in tabbed browsing). This is error-free and almost ideal. But the problem with this approach is that you are not able to listen to events such as FrameLoadStart, FrameLoadEnd, AddressChanged, TitleChanged, etc.
One approach that is tagged experimental by the Cef developers is to return a new IWebBrowser instance via newWebBrowser out parameter. This has so many many side effects. The page that opened the popup would, of course, recognize the popup as his although it was not the original browser (IBrowser) that it created. The page may just ignore it like btcclicks.com and in that case, there'd be no problem. But there are websites like drops.xyz that is so particular with his stuff and will discard everything that is not originally his. So this is a problem.
So what is the correct approach?
The ChromeWebBrowser control
Now I'm going to share with you an undocumented approach in handling popups. Speaking of ChromeWebBrowser control, it is very much of help that we know how it creates the webbrowser which, in reality, it doesn't. The control just hosts the webbrowser window handle. It has a private field called managedCefBrowserAdapter (ManagedCefBrowserAdapter class) that handles the actual creation of the web browser. ChromiumWEbBrowser implements the IWebBrowserInternal that has a method OnAfterBrowserCreated with a single parameter of type IBrowser. The control then invokes browser.GetHost().GetWindowHandle() to get the actual window handle (HWND) of the webbrowser it is being hosted. It is quite good.
The problem of the ChromeWebBrowser is that it won't have a constructor that accepts an IBrowser as an argument. It only has constructor that accepts HtmlString, string and IRequestContext arguments. These control waits for the
invocation of OnHandleCreated (a base class override) where it calls the managedCefBrowserAdapter.CreateBrowser after which it waits till its implementation of IWebBrowserInternal's OnAfterBrowserCreated is invoked.
Again, what is the approach that works?
Now, this approach that actually works is a product of long series of trial and error. One caution though is that I don't know why and how it works but I know it works.
First, I did not use ChromeWebBrowser. But I copied its code omitting the part where it creates .net control. In this case, I am targeting the browser's window handle (HWND) to be host by any object that exposes a HWND. Obviously I created a class (NativeCefWebBrowser) that uses the modified code. The ChromeWebBrowser orignal constructors were still there untouched becuase they are used to the create the parent webrowser. But I added one constructor that accept the following arguments: ICefBrowserParent parent (an interface I've created and IBrowser browser that receives the browser argument in the ILifeSpanHandler's OnBeforePopup. I also added a public method AttachBrowser that has a single parameter IBrowser that recieves the IBrowser argument in the ILifeSpanHandler's OnAfterCreated. It the browser that will be kept by CefNativeWebBrowser class.
Why didn't I keep the browser instance received form ILifeSpanHandler.OnBeforePopup but used the instance received from ILifeSpanHandler.OnAfterCreated when they are the same browser instance? This is one of those parts that I don't know why. One thing I noticed is that when I called browser.GetHost().GetWindowHandle() during ILiffeSpanHandler.OnBeforePopup, the first window handle I received was the different compared to when I invoked the method during ILifeSpanHandler.OnAfterCreatd. Because of that, I store the browser instance from the latter that I passed to the NativeCefWebBrowser.AttachBrowser for its safekeeping.
In the NativeCefWebBrowser(ICefBrowserParent parent, IBrowser browser) contructor, I set the private following fields to true: browsercreated, browserinitialized (chromewebbrwoser orginal fields) and isAttachingBrowser (added private field). You don't call the ManagedCefBrowserAdapter's CreateBrowser in this contructor in instead call its OnAfterBrowserCreated passing the browser instance. You don't much in this constructor as you will wait the ILifeSpanHandler implementor to pass you the browser instance it will receive during its OnAfterCreated method. Take note that when calling the ManagedCefBrowserAdapter's OnAfterBrowserCreated method, ManagedCefBrowserAdapter will still invoke IWebBrowserInternal implementation of OnAfterBrowserCreated that when happens you have to exit immediately when isAttachingBrowser is true as the following code will no sense no more.
After calling the NativeCefWebBrowser(ICefBrowserParent, IBroser) construct, you can normally set event listeners as you will normally do.
And that's it.
The following are parts of the code that I wrote
The ICefBrowserParent interface
public interface ICefBrowserParent
{
IntPtr Handle { get; }
Size ClientSize { get; }
bool Disposing { get; }
bool IsDisposed { get; }
bool InvokeRequired { get; }
IAsyncResult BeginInvoke(Delegate d);
object Invoke(Delegate d);
event EventHandler Resize;
}
As you would notice, the methods, properties and events in this interface are already implemented by the System.Windowns.Forms.Control class. So if you implementing this from class inhering Control class, you would not need to implement this anymore. This interface is only for non-Control class.
class NativeCefWebBrowser
{
public NativeCefWebBrowser(ICefBrowserParent, IBroser)
{
requestContext = browser.GetHost().RequestContext;
this.parent = parent; // added field
HasParent = true; // IWebBrowserInternal. I don't know what's this for
mustSetBounds = true; // added field
browserCreated = true;
isAttachingBrowser = true; // added field
InitializeFieldsAndCefIfRequired();
managedCefBrowserAdapter.OnAfterBrowserCreated(browser);
}
}
ILifeSpanHandler.OnBeforePopup(..., out IWebBrowser newWebBrowser)
{
CefNativeWebBrowser b = new CefNativeWebBrowser
(
parent, // defined else where
browser
);
// Attach event handlers
b.TitleChanged...;
newWebBrowser = b;
}
ILifeSpanHandler.OnAfterCreated(...)
{
((CefNativeWebBrowser)webBrowser).AttachBrowser(browser);
}

Where to place validation code

I've created a simple form with an enum field on a grid, dragged from the DataSource CompanyImage:
Table CompanyImage has an Index on this field named Brand in my example and AllowDuplicates is set to No :
And here is the form:
I've overridden the close() method of the form like this:
public void close()
{
CompanyImage_ds.write();
super();
}
An error is displayed when I close it saying that
"Cannot create a record in CompanyImage(CompanyImage). Legal entities: Example1.
The record already exists."
That's fine but I would like a way to stop closing the window when this happens. A validateWrite() would be nice but I am not really able to figure out where and what to write in order to accomplish this behavior.
I mean, how to check that new row is added and it contains a field that already exists in the table ?
You shouldn't have to force the write() method. Closing the form should already do it.
If you wish to check something to allow the form to be closed, the close() method is too late in execution. You should leverage the canClose() method.
You could override the validate method of the grid column. You would need to write some validation logic in that method but that would prevent the column from saving at all if validation failed.
public boolean validate()
{
boolean ret;
// write your own validation logic
if (validation logic is true)
{
ret = true;
}
return ret;
}

Trouble with dispatching events from external AS class in Flex

I've been trying this for a day now and I can't work it out.
I have a main application Planner.mxml. This view has a couple of custom components, one of which is LoginView.mxml. In LoginView.mxml I do the following:
protected function btnLoginClick(event:MouseEvent):void
{
try
{
var login:Login = new Login(txtEmail.text, txtPassword.text);
}
catch(error:Error)
{
Alert.show(error.message, "Oops!");
}
}
I create a new instance of my Login class and send some parameters to the constructor. My constructor looks like this:
public function Login(email:String, password:String)
{
if(email == "" || password == "")
{
throw new Error("Please complete all fields.");
}
else
{
var loginRequest:HTTPService = new HTTPService();
var parameters:Object = new Object();
parameters.email = email;
parameters.password = password;
loginRequest.url = Globals.LOGIN_URL;
loginRequest.resultFormat = "object";
loginRequest.method = "POST";
loginRequest.addEventListener("result", loginHandleResult);
loginRequest.addEventListener("fault", loginHandleFault);
loginRequest.send(parameters);
}
}
Here I check if all fields are complete, and if so, I put the constructor parameters in a parameters object which I then send to the HTTPService, which is a simple PHP file that handles the request, checks with the db and returns some xml. (This might not be the best way, but this really isn't too important at this point).
If the user is logged in successfully, the xml will contain a status property which is set to true. I check for this in the result event handler of the HTTP service. This is where everything goes wrong though.
protected function loginHandleResult(event:ResultEvent):void
{
if(event.result.status == true)
{
trace("logged in");
// here stuff goes wrong
var e:LoggedInEvent = new LoggedInEvent("loggedIn");
dispatchEvent(e);
}
else
{
trace("not logged in");
Alert.show("Wrong credentials.", "Oops!");
}
}
As you can see, when the user is successfully logged in, I want to dispatch a custom event; if not, I show an alert box. However, this event doesn't dispatch (or at least, I don't know how to listen for it).
I would like to listen for it in my main application where I can then change my viewstate to the logged-in state. However, the event never seems to get there. I listen for it by having loggedIn="loggedInHandler(event)" on my loginComponent.
Any idea how to do this? Thanks in advance. I would really appreciate any help.
First, your Login needs to extend event dispatcher or implement IEventDispatcher. I'm not sure why you're getting compiler errors trying to dispatch events from it.
Next, you need to listen to the new Login instance for that event.
However, you have an architectural problem here that your View should NOT be handling business logic and it should DEFINITELY not be creating new objects that are not its own children on the Display List.
Instead, you should dispatch an event from the View that REQUESTS that a login occur, and then that request should be handled further up. Depending on the scale of your application, this can be the main mxml file or separate controller or Command logic. It is ok for the View to do a minimal amount of validation prior to dispatching the Event, but ideally you would want to encapsulate this stuff into a PresentationModel (because it is easier to test).
If you dispatch event then somebody who interested in this event must to subscribe to this event.
If you dispatch event from LoginView instance then in object who wait this event you need such lines:
loginViewInstance.addEventListemer("loggedIn", loggedInHandler);
and in handler:
private function loggedInHandler(event:LoggedInEvent):void
{
//do something
}
do what you need.

Delete link with jquery confirm in Asp.Net MVC 2 application

I have a table with records that has delete links. Basically I followed the NerdDinner tutorial for that part in MVC. But I don't want to have the confirm view, I'd rather have a confirm dialog, and then if confirmed let the HttPost action method delete the record directly.
I have something working, but being new to both MVC and jQuery, I'm not sure if I'm doing it right.
Here's the jQuery:
$(function () {
$('.delete').click(function () {
var answer = confirm('Do you want to delete this record?');
if (answer) {
$.post(this.href, function () {
window.location.reload(); //Callback
});
return false;
}
return false;
});
});
And the delete actionlink:
<%: Html.ActionLink("Delete", "Delete", new { id = user.UserID }, new { #class = "delete" })%>
And finally, the delete action method:
[HttpPost]
public ActionResult Delete(int id)
{
_db = new UsersEntities();
try
{
//First delete the dependency relationship:
DeleteUserVisits(id);
//Then delete the user object itself:
DeleteUser(id);
}
catch (Exception)
{
return View("NotFound");
}
return RedirectToAction("Index");
}
Now, I have a few questions about this:
I found the function for making the link POST instead of GET on the internet: `$.post(this.href); return false; And I'm not sure what the "return false" part does. I tried to modify it for my needs with a callback and so on, and kept the return part without knowing what it's for.
Secondly, the action method has the HttpPost attribute, but I have also read somewhere that you can use a delete verb. Should you? And what about the RedirectToAction? The purpose of that was originally to refresh the page, but that didn't work, so I added the window.location.reload instead in a callback in the jQuery. Any thoughts?
The Delete action method calls a couple of helper methods because it seems with the Entity Framework that I use for data, I can't just delete an record if it has relationship dependencies. I had to first delete the relationships and then the "User" record itself. That works fine, but I would have thought it would be possible to just delete a record and all the relationships would be automatically deleted...?
I know you're not supposed to just delete with links directly because crawlers etc could accidentally be deleting records. But with the jQuery, are there any security issues with this? Crawlers couldn't do that when there is a jQuery check in between, right?
Any clarifications would be greatly appreciated!
The return false statement serves
the same purpose as
e.preventDefault() in this case.
By returning false JavaScript is preventing
the browser from executing the link's
default click handler.
The DELETE verb is for RESTful web
services, it is most likely not what
you want in this situation because
not all browsers fully implement it.
Read more about them here: Creating
a RESTful Web Service Using ASP.Net
MVC
The deletion rules for child
entities depend on the entity
OnDelete/OnUpdate rules in the
context definition and also on
foreign key constraints in the
database. You can learn more about
foreign key constraints here.
A crawler will not be able to
activate your delete link in this
fashion because you have specified
the delete action be issued via a
POST. If the delete were a GET then
it would be a concern. Still, it's
not wise to keep links that directly
modify your content on front-facing
pages that do not require
authentication as a human could most
certainly exploit the process.
There you go, with full code :
http://haacked.com/archive/2009/01/30/delete-link-with-downlevel-support.aspx
Or just the html helper :
public static string DeleteLink(this HtmlHelper html, string linkText, string routeName, object routeValues) {
var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
string url = urlHelper.RouteUrl(routeName, routeValues);
string format = #"<form method=""post"" action=""{0}"" class=""delete-link"">
<input type=""submit"" value=""{1}"" />
{2}
</form>";
string form = string.Format(format, html.AttributeEncode(url), html.AttributeEncode(linkText), html.AntiForgeryToken());
return form + html.RouteLink(linkText, routeName, routeValues, new { #class = "delete-link", style = "display:none;" });
}
For your questions :
When you do a return false at the end of a javascript click handler on a link, the browser executes the javascript but doesn't follow the link, because of the return false.
For (maximum) cross browser compatibility, you shouldn't use the DELETE verb.
I don't know EF well enough, but doesn't it provide mapping configuration for cascading delete ?
HTTP GET should only be used to get information, for example, provide parameters for a search. Crawlers usually don't care about javascript, so they will blindly follow you links. If it is http://mysite/delete/everything, then, bad for you, if you hadn't the [HttpPost] on you controller action
If you also want to throw the jQuery dialog to the party, this Ricardo Covo post does a good job

Dynamic list constraint on Alfresco

I'm trying to follow the examples provided in this post, to create a dynamic list constraint in Alfresco 3.3.
So, I've created my own class extending ListOfValuesConstraint:
public class MyConstraint extends ListOfValuesConstraint {
private static ServiceRegistry registry;
#Override
public void initialize() {
loadData();
}
#Override
public List getAllowedValues() {
//loadData();
return super.getAllowedValues();
}
#Override
public void setAllowedValues(List allowedValues) {
}
protected void loadData() {
List<String> values = new LinkedList<String>();
String query = "+TYPE:\"cm:category\" +#cm\\:description:\"" + tipo + "\"";
StoreRef storeRef = new StoreRef("workspace://SpacesStore");
ResultSet resultSet = registry.getSearchService().query(storeRef, SearchService.LANGUAGE_LUCENE, query);
// ... values.add(data obtained using searchService and nodeService) ...
if (values.isEmpty()) {
values.add("-");
}
super.setAllowedValues(values);
}
}
ServiceRegistry reference is injected by Spring, and it's working fine. If I only call loadData() from initialize(), it executes the Lucene query, gets the data, and the dropdown displays it correctly. Only that it's not dynamic: data doesn't get refreshed unless I restart the Alfresco server.
getAllowedValues() is called each time the UI has to display a property having this constraint. The idea on the referred post is to call loadData() from getAllowedValues() too, so the values will be actually dynamic. But when I do this, I don't get any data. The Lucene query is the same, but returns 0 results, so my dropdown only displays -.
BTW, the query I'm doing is: +TYPE:"cm:category" +#cm\:description:"something here", and it's the same on each case. It works from initialize, but doesn't from getAllowedValues.
Any ideas on why is this happening, or how can I solve it?
Thanks
Edit: we upgraded to Alfresco 3.3.0g Community yesterday, but we're still having the same issues.
This dynamic-list-of-values-constraint is a bad idea and I tell you why:
The Alfresco repository should be in a valid state all the time. Your (dynamic) list of constraints will change (that's why you want it to be dynamic). Adding items would not be a problem, but editing and removing items are. If you would remove an item from your option-list, the nodes in the repository with this property value will be invalid.
You will not be able to fix this easily. The standard UI will fail on invalid-state-nodes. Simply editing this value and setting it to something valid will not work. You have been warned.
Because the default UI widget for a ListConstraint is a dropdown, not every dropdown should be a ListConstraint. ListConstraints are designed for something like a Status property: { Draft, Waiting Approval, Approved }. Not for a list of customer-names.
I have seen this same topic come up again and again over the last few years. What you actually want is let the user choose a value from a dynamic list of options (combo box). This is a UI problem, not a dictionary-model-issue. You should setup something like this with the web-config-context.xml (Alfresco web UI) or in Alfresco Share. The last one is more flexible and I would recommend taking that path.

Resources