I have a semi-vague question to ask about Selenium. I've discovered a few different ways to perform actions using the FirefoxDriver. What I need to do is repeat actions that a user performs on a web page (clicking a link, checking a checkbox, etc.). Is there any method or combination of methods that allows me to "record" the user's actions? Here is what I have so far to perform actions (you'll notice I've tried using the WebDriverBackedSelenium and Actions classes to perform actions)
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverBackedSelenium;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.Action;
public class MyReplayer {
public static void main(String[] args) throws Exception {
// The Firefox driver supports javascript
FirefoxDriver driver = new FirefoxDriver();
driver.get("http://www.cs.umd.edu");
List<WebElement> elements = driver.findElements(By.tagName("a"));
//WebDriverBackedSelenium driverBacked = new WebDriverBackedSelenium(driver, "http://www.cs.umd.edu");
Actions builder = new Actions(driver);
Action clickLink = builder.click(elements.get(100)).build();
clickLink.perform();
//driverBacked.click("document.getElementsByTagName('a')[100]");
}
}
I came across Huxley. It allows recording and playback of user actions. I found this question in search of how they did it, but had to resort to source code.
Lines 98-154 of huxley/run.py define the record function. It uses webdirvier to execute some js on the page which adds some event listeners. It also adds a function to return the events.
(function() {
var events = [];
window.addEventListener('click', function (e) { events.push([Date.now(), 'click', [e.clientX, e.clientY]]); }, true);
window.addEventListener('keyup', function (e) { events.push([Date.now(), 'keyup', String.fromCharCode(e.keyCode)]); }, true);
window._getHuxleyEvents = function() { return events; };
})();
To read the events the js function is called
events = d.execute_script('return window._getHuxleyEvents();')
Then the events are stored in a way that seems application specific.
Sorry, I do not have Java code. I hope this helps.
You can use the Selenium IDE Addon for Firefox and export the generated test for Webdriver. It doesn't specifically say FirefoxDriver, but the methods of the interface look similar to what you posted. I hope this helps.
I am currently working on a project that does something like this: https://github.com/hristo-vrigazov/selenium-record-replay
It works by putting a proxy between the browser and the application, and injecting javascript which listens for actions that you have defined. See for example https://github.com/hristo-vrigazov/selenium-record-replay/blob/master/terminator-cli/src/main/java/browser/Main.java#L74
RecordBrowserBase recordBrowserBase = new ChromeRecordBrowser(pathToChromedriver, pathToJSInjectionFile);
try {
recordBrowserBase.record(baseUrl);
System.out.println("Press Enter when finished recording");
System.in.read();
recordBrowserBase.dumpActions(outputFile);
} catch (IOException | InterruptedException | URISyntaxException e) {
e.printStackTrace();
}
recordBrowserBase.cleanUp();
System.exit(0);
The project is still in a very early stage, but it can be used even now. Currently only Chrome is supported, but I will soon add other browsers as well.
Disclaimer: I am the creator and maintainer of the project
Related
I have a Spring Boot project with Vaadin integration (v14). I want my application to do some background operation and represent the results on the Vaadin-based frontend. For this I have a view which is a Polymer template generated with Vaadin Designer (.js) and connected to a Java companion class. To this view I've just simply added a button initialized with the following listener:
_btnMyTriggerButton.addClickListener(event -> {
CompletableFuture<Void> c = CompletableFuture.supplyAsync(() -> {
for (int i = 0; i < 5; i++)
{
try
{
System.out.println("Waiting");
Thread.sleep(1000);
UI.getCurrent().access(() -> {
Notification.show("Waiting");
});
}
catch (InterruptedException e)
{
}
}
return "Waiting over. Greet!";
}).thenAccept(s -> {
System.out.println(s);
UI.getCurrent().access(() -> {
Notification.show(s);
});
});
I'm trying to access the UI as the documentation says. However when this is being executed it only reaches the first "Waiting", then stops. If I remove the UI interaction (Notification.show()) the output is printed to the backend as desired, but not when attempting do any interaction on the UI..
The structure of my java companion class is the following:
#Tag("my-view")
#JsModule("./my-view.js")
#Route("")
#Push(PushMode.AUTOMATIC)
public class MyView extends PolymerTemplate<MyView.MyModel>
{
#Id("trigger-button")
private Button _btnMyTriggerButton;
MyView() {
// listener initialization code described above
}
public interface MyModel extends TemplateModel
{
}
}
Do I miss something to achieve asynchronous behavior on this webpage?
Any help is appreciated.
The problem in this case is that the first callback terminates with a NullPointerException because UI.getCurrent() returns null when it's run from a background thread. CompletableFuture will just ignore the exception unless you explicitly handle it (e.g. using handle instead of thenAccept) or block on the result.
You can fix this by adding UI ui = UI.getCurrent(); in the beginning of the click listener and then referencing ui in both the supplyAsync and thenAccept callbacks instead of using UI.getCurrent() there.
I have set up a signalR website .net core. My function in my hub is:
public async Task Notify(int id) {
await Clients.All.InvokeAsync("Notified", id);
}
I have also tested this with the following js:
let connection = new signalR.HubConnection(myURL);
connection.on('Notified', data => {
console.log(4, data);
});
connection.start();
The js code seems to work fine and I see the log when I try connection.Invoke('Notify').
Now I have a console app that can needs to make the invoke. I am trying this in two ways and don't mind either solution:
1. A mvc controller within the signalR website that can take the id and invoke 'Notified'.
2. Use the client library Microsoft.AspNetCore.SignalR.Client in the console app.
The way 1 I have only done in classic asp.net like this:
GlobalHost.ConnectionManager.GetHubContext(hubName)
But couldn't find a way to do this in .net core.
Way 2 I have used the library and tried this so far:
var con = new HubConnectionBuilder();
con.WithUrl(myURL);
var connection = con.Build();
connection.InvokeAsync("Notify",args[0]).Wait();
This is the closest I have come to create a connection in the same way as the js code. However this code throws a null pointer when calling connection.InvokeAsync. The connection object is not null. It seems to be an internal object that is null. According to the stack trace the exception is thrown when a MoveNext() function is internally called.
Well looks like both are not currently possible. As of now I just used a forced way which is hopefully temporary.
I have created and used the following base class for hubs:
public abstract class MyHub : Hub
{
private static Dictionary<string, IHubClients> _clients = new Dictionary<string, IHubClients>();
public override Task OnConnectedAsync()
{
var c = base.OnConnectedAsync();
_clients.Remove(Name);
_clients.Add(Name, Clients);
return c;
}
public static IHubClients GetClients(string Name) {
return _clients.GetValueOrDefault(Name);
}
}
GlobalHost is gone. You need to inject IHubContext<THub> like in this sample.
This can be a bug in SignalR alpha1. Can you file an issue on https://github.com/aspnet/signalr and include a simplified repro?
So i don't actually have a question because i've already solved it, but in case someone else runs into this issue it's always nice to have a neat solution.
And while there is a plentitude of "Can't create handler inside thread which has not called Looper.prepare()" - questions there is none tagged with xamarin. (so theirs is all java and i had 0 matches for "Can't create handler inside thread which has not called Looper.prepare() [xamarin]")
The issue is generated because You tried to do work on UI from other thread. If you want to change UI, Must call UI changes from UI thread.
Xamarin Android:
activity.RunOnUiThread(() =>
{
// Write your code here
});
Xamarin IOS:
nsObject.BeginInvokeOnMainThread(() =>
{
// Write your code here
});
Xamarin Forms:
Device.BeginInvokeOnMainThread(() =>
{
// Write your code here
});
public static class PageExtensions
{
public static Task<bool> DisplayAlertOnUi(this Page source, string title, string message, string accept, string cancel)
{
TaskCompletionSource<bool> doneSource = new TaskCompletionSource<bool>();
Device.BeginInvokeOnMainThread(async () =>
{
try
{
var result = await source.DisplayAlert(title, message, accept, cancel);
doneSource.SetResult(result);
}
catch (Exception ex)
{
doneSource.SetException(ex);
}
});
return doneSource.Task;
}
}
Finally i had a case for using TaskCompletionSource to solve an issue.
Very similar actually happend to me. Previous evening I was developing and testing my app. Next morning, from other computer I got the exception you described. I was remembered from a official Xamarin.Forms documentation that sometimes a bin and obj folder removal solves lot of issues.
I did exactly the same, removed my bin and obj folder from my shared Xamarin.Forms library and also from Xamarin.Android library.
The strange exception disappeared.
I want to built a program which is get problems and I found that my first batches of tests involving custom components would tend to follow code:
import mx.core.Application;
import mx.events.FlexEvent;
import flexunit.framework.TestCase;
public class CustomComponentTest extends TestCase {
private var component:CustomComponent;
public function testSomeAspect() : void {
component = new CustomComponent();
component.addEventListener(FlexEvent.CREATION_COMPLETE,
addAsync(verifySomeAspect, 5000));
component.height = 0;
component.width = 0;
Application.application.addChild(component);
}
public function verifySomeAspect(event:FlexEvent) : void {}
override public function tearDown() : void {
try {
if (component) {
Application.application.removeChild(component);
component = null;
}
} catch (e:Error) {
}
}
First, you need to make sure the component has been fully initialized before you can reliably verify anything about it, and in Flex this happens asynchronously after it has been added to the display list. So you need to setup a callback (using FlexUnit's addAsync function) to be notified when that's happened.
Lately i've been just manually calling the methods that the runtime would call for you in the necessary places, so now my tests tend to look more like this:
import flexunit.framework.TestCase;
public class CustomComponentTest extends TestCase {
public function testSomeAspect() : void {
var component:CustomComponent = new CustomComponent();
component.initialize();
component.validateProperties();
}
This is much easier to follow, but it kinda feels like I'm cheating a little either way. The first case is slamming it into the current Application (which would be the unit test runner shell app), and the latter isn't a "real" environment.I was wondering how other people would handle this sort of situation?
I can agree that the second version is shorter, but I'm not sure that I think it's easier to follow. The test does a lot of things that you wouldn't normally do, whereas the first example is more true to how you would use the component outside the test environment.
Also, in the second form you have to make sure that you do exactly what the framework would do, miss one step and your test isn't relevant, and each test must repeat this code. Seems to me it's better to test it in a situation that is as close to the real thing as possible.
You could have a look at dpUint's sequences, they made component testing a little more declarative:
public function testLogin():void {
var passThroughData:Object = new Object();
passThroughData.username = "myuser1";
passThroughData.password = "somepsswd";
var sequence:SequenceRunner = new SequenceRunner(this);
sequence.addStep(new SequenceSetter(form.usernameTI,
{text:passThroughData.username}));
sequence.addStep(new SequenceWaiter(form.usernameTI,
FlexEvent.VALUE_COMMIT, 100));
sequence.addStep(new SequenceSetter(form.passwordTI,
{text:passThroughData.password}));
sequence.addStep(new SequenceWaiter(form.passwordTI, FlexEvent.VALUE_COMMIT, 100));
sequence.addStep(new SequenceEventDispatcher(form.loginBtn,
new MouseEvent("click", true, false)));
sequence.addStep(new SequenceWaiter(form, "loginRequested", 100));
sequence.addAssertHandler(handleLoginEvent, passThroughData);
sequence.run();}
I am looking for a way to subscribe to events like Storing a specific object type to ServiceStack.Redis.
For example I may
using (var redisClient = new RedisClient())
using (var redisMyObjects = redisClient.As<MyObject>())
{
redisMyObjects.Store(myObject);//<-- I want this to trigger an event somehow
}
Is there anything like a OnStore event which I can hook too, anything out of the box? if not, is there any recommendation about how this should be done?
I don't think there is anything you can hook into (could be wrong).
Two options that came to mind:
1 - Make an extension method
2 - Publish a message to store your object and have a handler that listens for a response and does something. This is probably overkill since it's heading into the publish/subscribe realm. But, I think, worth looking into. (Basic example here and see Pub/Sub here).
Extension Method
public static class RedisClientExtensions
{
public static void StoreWithTrigger<T>(this IRedisTypedClient<T> redisClient, T value, Action<T> trigger)
{
redisClient.Store(value);
trigger(value);
}
}
Using ExtensionMethod
public void MyMethod()
{
using (var redisClient = new RedisClient())
using (var redisMyObjects = redisClient.As<MyObject>())
{
redisMyObjects.StoreWithTrigger<MyObject>(new MyObject(), TriggerEvent);//<-- I want this to trigger an event somehow
}
}
private void TriggerEvent<T>(T value)
{
//dosomething
}
Hope this gives you some ideas.