Using Geb 0.13.1 here. I'm not trying to integrate it with any kind of testing framework (yet), just trying to get a feel for its DSL. I just want Geb to launch a Firefox browser, point it to Google's homepage and type in 'gmail' in the search address (HTML <input/> with an id of 'q'):
class GoogleHomepage extends Page {
static url = 'http://google.com'
static at = {
title == 'Google'
}
static content = {
search {
$('input#q')
}
}
}
class MyGebDriver {
static void main(String[] args) {
FirefoxDriver firefoxDriver = new FirefoxDriver()
Browser browser = new Browser(driver: firefoxDriver)
Browser.drive(browser) {
to(GoogleHomepage)
search.value('gmail')
quit()
}
}
}
When I run this, Firefox opens up and goes to Google, but seems to choke when finding the search ('q' element) bar to set a value for:
Exception in thread "main" geb.error.RequiredPageContentNotPresent: The required page
content 'sandbox.geb.GoogleHomepage -> search: geb.navigator.EmptyNavigator' is not
present
Any ideas as to what's going on here?
You're getting an EmptyNavigator because you're looking for an input with an id of q $('input#q') try $('input[name=q]') instead.
Your GoogleHomepage looks a bit goofy to me.
What if you made it look more like this which follows the geb dsl better.
class GoogleHomepage extends Page {
url = 'http://google.com'
static at = {
waitFor() {
title == 'Google'
content
}
}
static content = {
search(required: true) { $('input#lst-ib') }
}
}
Related
It looks like paypal has updated their plugin lately and my code stopped working. I tried using Selenium IDE but when I record using it I do not see the Accept Cookie modal popup. I am able to get pass login as below, but I tried many different way to get to submit payment button with no luck. Help appreciated.
public IDictionary<string, object> vars { get; private set; }
vars = new Dictionary<string, object>();
_driver.SwitchTo().Frame(0);
vars["WindowHandles"] = _driver.WindowHandles;
_driver.FindElement(By.CssSelector(".paypal-button")).Click();
vars["win8061"] = waitForWindow(2000);
vars["root"] = _driver.CurrentWindowHandle;
_driver.SwitchTo().Window(vars["win8061"].ToString());
_driver.FindElement(By.Id("email")).SendKeys(paypalEmail);
_driver.FindElement(By.Id("btnNext")).Click();
_driver.FindElement(By.Id("password")).SendKeys(paypalPassword);
_driver.FindElement(By.Id("btnLogin")).Click();
//The problem is here!!!
var element = _driver.FindElement(By.Id("payment-submit-btn"));
Actions builder = new Actions(_driver);
builder.MoveToElement(element).Perform();
public string waitForWindow(int timeout)
{
try
{
Thread.Sleep(timeout);
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
var whNow = ((IReadOnlyCollection<object>)_driver.WindowHandles).ToList();
var whThen = ((IReadOnlyCollection<object>)vars["WindowHandles"]).ToList();
if (whNow.Count > whThen.Count)
{
return whNow.Except(whThen).First().ToString();
}
else
{
return whNow.First().ToString();
}
}
Had same issue recently after PayPal made some kind of changes to their "Pay" button. All of the sudden it stopped working. Below is what worked for me. There is no logic behind it, besides "just because it works".
After PayPal login; in your case after:
_driver.FindElement(By.Id("btnLogin")).Click();
Use:
Thread.Sleep(1000);
_driver.FindElement(By.Id("acceptAllButton")).Click();
try
{
_driver.FindElement(By.Id("payment-submit-btn")).Click();
}
catch
{
_driver.FindElement(By.Id("payment-submit-btn")).Click();
}
With WebVeiw2 you can send a message to a web app running in it using WebView2Ctrl?.CoreWebView2?.PostWebMessageAsJson(message).
Is there a way of doing this in CefSharp
Create a class (I used JavascriptCallbackMessenger) to Set and Run the callbacks.
public class JavascriptCallbackMessenger
{
private IJavascriptCallback _callback;
public void SetCallBack(IJavascriptCallback callback)
{
_callback = callback;
}
public void RunCallback(string message)
{
if (_callback != null && _callback.CanExecute)
{
_callback.ExecuteAsync(message);
}
}
}
Create an instance of JavascriptCallbackMessenger and register it with the CefSharp control
CefSharpCtrl.JavascriptObjectRepository.Register(JavascriptCallbackMessengerName, _messenger, true, BindingOptions.DefaultBinder);
Set the callback in Javascript as follows (I'm not a JS developer, but this was my solution).
(async function() {
const cefSharp = (window as any).CefSharp;
await cefSharp.BindObjectAsync(JavascriptCallbackMessengerName);
window.javascriptCallbackMessenger.setCallBack(function(message: string)
{
console.log("messageHandler: " + message);
})
})();
I was using typescript, so I had to extend the Window with the newly created variable.
declare global {
interface Window { javascriptCallbackMessenger: any; }
}
Apologies, but the formatting seems to be a bit "off"!
After many trials, I can't seem to get Nancy's Diagnostic Tracing to show anything beyond a set of empty white boxes. It appears one box per browser session. Yet the boxes never include any information.
Per the diagnostics page I've added a diagnostics password and set
StaticConfiguration.EnableRequestTracing = true;
I expected there to be at some sort of default tracing out of the box, but just in case I made a call to
this.Context.Trace.TraceLog.WriteLog(x => x.AppendLine("What's ip?"));
in one of my modules, and confirmed said module route was getting called. Still no indication there was tracing going on.
We're running NancyFx version 1.45 in a framework 4.7.1 app. Any suggestions on why this could be happening?
Thanks
Enable tracing and diagnostics by using a custom bootstrapper.
For NancyFx v1:
NancyOptions options = new NancyOptions
{
Bootstrapper = new CustomBootstrapper()
};
app.UseNancy(options);
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
StaticConfiguration.DisableErrorTraces = false;
StaticConfiguration.EnableRequestTracing = true;
if (!StaticConfiguration.EnableRequestTracing)
{
DiagnosticsHook.Disable(pipelines);
}
}
protected override DiagnosticsConfiguration DiagnosticsConfiguration => new DiagnosticsConfiguration() { Enabled = true, Password = #"A2\6mVtH/XRT\p,B" };
}
For NancyFx v2:
NancyOptions options = new NancyOptions
{
Bootstrapper = new CustomBootstrapper()
};
app.UseNancy(options);
public class CustomBootstrapper : DefaultNancyBootstrapper
{
public override void Configure(INancyEnvironment environment)
{
environment.Diagnostics(
enabled: true,
password: #"A2\6mVtH/XRT\p,B");
environment.Tracing(
enabled: true,
displayErrorTraces: true);
}
}
I am using CrossMobile to create an app and I want to use the camera to capture and save photos from my app. I will also need to access the photos taken from the app to show them in a list. How can I present the camera view on a button press?
First of all you might need the CoreImage Plugin, or else some specific permissions will not be available.
Under iOS you also need to add the NSCameraUsageDescription key in the Info.plist by hand, (or else the application will crash due to Apple's limitation).
Let's assume that you have a UIButton with name cameraButton and an UIImageView with name imgV, both initialized in the loadView section of your code.
Then the core would be similar to:
public void loadView() {
// ....
cameraButton.addTarget((sender, event) -> {
if (!UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
new UIAlertView(null, "Unable to access camera", null, "Accept").show();
else {
UIImagePickerController picker = new UIImagePickerController();
picker.setSourceType(UIImagePickerControllerSourceType.Camera);
picker.setDelegate(new UIImagePickerControllerDelegate() {
#Override
public void didFinishPickingMediaWithInfo(UIImagePickerController picker, Map<String, Object> info) {
picker.dismissModalViewControllerAnimated(true);
UIImage img = (UIImage) info.get(UIImagePickerController.OriginalImage);
imgV.setImage(img);
}
#Override
public void didCancel(UIImagePickerController picker) {
picker.dismissModalViewControllerAnimated(true);
}
});
presentModalViewController(picker, true);
}
}, UIControlEvents.TouchUpInside);
// ....
}
I'm working on setting up two-factor in my application and I'm trying to make it redirect back to the verification page if the user is logged in but not verified (I'm keeping track of if the user is verified in the sessions table which is added to ClaimsPrincipal 'IsVerified').
The problem i'm having is the example I am using from the documentation doesn't seem to be working properly:
public static class ModuleSecurity
{
public static string[] ExcludedPaths = { "/", "/login", "/login/verify", "/admin/settings", "/login/tf/setup" };
public static void RequiresAuthentication(this NancyModule module)
{
module.Before.AddItemToEndOfPipeline(RequiresAuthentication);
}
private static Response RequiresAuthentication(NancyContext context)
{
// Check if user is authenticated
if (context.CurrentUser == null)
return new Response() { StatusCode = HttpStatusCode.Unauthorized };
if (context.CurrentUser.FindFirst("RequireVerification")?.Value == "True" && context.CurrentUser.FindFirst("IsVerified")?.Value != "True" && !ExcludedPaths.Any(x => x.ToLower() == context.Request.Path.ToLower()))
return new Response().WithHeader("Location", "/login/verify").WithContentType("text/html").WithStatusCode(HttpStatusCode.SeeOther);
return null;
}
}
Putting break points in I see the "module.Before.AddItemToEndOfPipeline" is executed but it is not executing the other method I have.
Then problem was I was adding this to the BEFORE pipeline but i'm calling this.RequiresClaims after the route was triggered (so I needed the AFTER pipeline). I was able to do this by adding the extensions and using the module.AddBeforeOrExecute option.