Selenium2 WebDriver (Page factory) error after a postback (Element not found in the cache) - postback

I'm using Selenium 2 tests (written in C#) that choose values from a "select" control.
Selection causes a post-back to the server, which updates the state of the page.
It s really frustrating because every PostBack occurs this exception
Element not found in the cache - perhaps the page has changed since it was looked up
Just to be precise i use Selenium 2 WebDriver (2.32.0.0)
And for my project i Use Pattern Page Factory
The code looks like that
class RegisterPersonelData
{
private IWebDriver driver;
[FindsBy(How = How.Id, Using = "ctl00_ContentMain_register1_txtName")]
private IWebElement txtLastname;
[FindsBy(How = How.Id, Using = "ctl00_ContentMain_register1_lstDrvLic")]
private IWebElement dlDrive;
private SelectElement selectDrive;
[FindsBy(How = How.Id, Using = "ctl00_ContentMain_register1_lstVeh")]
private IWebElement dlVehicule;
private SelectElement selectVehicule;
public RegisterPersonelData(IWebDriver driver)
{
this.driver = driver;
// initialize elements of the LoginPage class
PageFactory.InitElements(driver, this);
// all elements in the 'WebElements' region are now alive!
// FindElement or FindElements no longer required to locate elements
}
public void fillData(string lastname, string drive, string vehicule)
{
txtLastname.SendKeys(lastname);
this.selectDrive = new SelectElement(dlDrive);
selectDrive.SelectByText(drive);
selectVehicule = new SelectElement(dlVehicule);
IWait<IWebDriver> wait = new WebDriverWait(this.driver, TimeSpan.FromSeconds(Convert.ToInt32(ConfigurationManager.AppSettings["ExpliciteWait"])));
wait.Until(x => selectVehicule.Options.Count > 1);
selectVehicule.SelectByText(vehicule);
}
}
And here the code of main
class Program
{
static void Main()
{
IWebDriver driver = MyWebDriver.GetWebDriver(MyWebDriver.BrowserType.FIFREFOX);
driver.Navigate().GoToUrl("http://...");
...
registerPersonelData.fillData("lastname", "Permis B", "Auto");
}
}
This code doesn t work because one postback is triggered ...
I have try to use one explicite wait but it fails too !
Code use to retrieve one element with explicite wait
public static IWait<IWebDriver> GetWaitWebDriver(IWebDriver driver)
{
IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(Convert.ToInt32(ConfigurationManager.AppSettings["ExpliciteWait"])));
return wait;
}
public static IWebElement GetElementAndWaitForIt(IWebDriver driver, By by)
{
return GetWaitWebDriver(driver).Until(x =>
{
return x.FindElement(by);
});
}
Someone has one idea to fix it ?

You can re-initialize the elements at the end of the fillData method.
PageFactory.InitElements(driver, this);
You could do it in the main as well with:
PageFactory.InitElements(driver, registerPersonelData);
You could also try adding the following to the field you need to reuse.
[CacheLookup]

I have done a lot of tries and finally i have found something usefull
public static void WaitForAnWebElementDisplayed(IWait<IWebDriver> wait, IWebElement webElement)
{
wait.Until(x => webElement.Displayed);
}
public static void WaitForAnWebElementEnabled(IWait<IWebDriver> wait, IWebElement webElement)
{
wait.Until(x => webElement.Enabled);
}
and Consequently i can wait that the load of page triggered after to have choosen one item in select option is completed !

Related

Vaadin 11: refreshAll (again)

here is a good thread about DataProvider.refreshAll() on Vaadin 8.5.1, but it doesn't seem to work this way in Vaadin 11.
I used this starter app to play around. It displays some imaginary product data in a grid.
At first, I added a refresh command to SampleCrudView:
public HorizontalLayout createTopBar() {
...
HorizontalLayout topLayout = new HorizontalLayout();
Button btn = new Button("refresh");
btn.addClickListener(event -> dataProvider.refreshAll());
topLayout.add(btn);
...
return topLayout;
}
The folks from vaadin override getId() in their ProductDataProvider like this to use it as an object identifier:
#Override
public Integer getId(Product product) {
Objects.requireNonNull(product,
"Cannot provide an id for a null product.");
return product.getId();
}
That ProductDataProvider extends ListDataProvider, which is initialized on startup with data from MockDataService, so that we always deal with the same objects. I changed that:
public class MockDataService extends DataService {
...
#Override
public synchronized List<Product> getAllProducts() {
//added ->
MockDataGenerator.resetProductCounter(); //this one sets nextProductId = 1
products = MockDataGenerator.createProducts(categories);
products.stream().forEach(p -> System.out.println(p.getId() + ", " + p.getProductName()));
//<- added
return products;
}
So now you will get new Product instances within the same ID range every time you call getAllProducts():
public class ProductDataProvider extends ListDataProvider<Product> {
...
#Override
public Stream<Product> fetch(Query<Product, SerializablePredicate<Product>> query) {
//added ->
this.getItems().clear();
this.getItems().addAll(DataService.get().getAllProducts());
//<- added
return super.fetch(query);
}
So the point is, this doesn't work - the data in the grid is still the same after "refresh" has been clicked.
Any suggestions?
Regards,
m_OO_m
This is caused by a bug that was fixed a couple a days ago. The fix will be included in the next maintenance release.

Vaadin Grid middle mouse click

I'm trying to emulate normal browser behaviour in my vaadin grid, which includes middle mouse click to open in a new tab:
addItemClickListener(e -> {
boolean newTab = e.getMouseEventDetails().getButton() == MouseEventDetails.MouseButton.MIDDLE || e.getMouseEventDetails().isCtrlKey();
//open in window or new tab
});
However, the middle mouse button is not registered by vaadin. How could I get this to work?
That feature was included in vaadin-grid (which goes into Vaadin 10) and will not work in Vaadin 8.
For Vaadin 8, you can either intercept the event with some client-side extension, or use a ComponentRenderer for adding a Panel to each component (which works, but is not ideal because it degrades performance):
grid.addColumn(item->{
Panel p = new Panel(item.getName());
p.setStyleName(ValoTheme.PANEL_BORDERLESS);
p.addClickListener(ev->{
System.out.println(ev.getButtonName());
});
return p;
}).setRenderer(new ComponentRenderer());
A client-side extension, on the other hand, allows listening to javascript events (such as MouseEvent) and triggering a server event in response. Creating a extension is quite a complex topic (since it uses a part of the API that is normally hidden from the developer) but it allows direct access to rendered DOM, which is not possible otherwise.
The following resources from the documentation may give you a starting point:
Creating a component extension (which describes a simple extension with Java code only) and Integrating JavaScript Components and Extension (which explains how to add native JavaScript code to your extension).
How I solved the problem in my specific case:
Server side:
public class MyGrid<T> extends Grid<T> {
public MyGrid(String caption, DataProvider<T, ?> dataProvider) {
super(caption, dataProvider);
MiddleClickExtension.extend(this);
}
public static class MiddleClickExtension<T> extends AbstractGridExtension<T> {
private MiddleClickExtension(MyGrid<T> grid) {
super.extend(grid);
registerRpc((rowKey, columnInternalId, details) -> grid.fireEvent(
new ItemClick<>(grid, grid.getColumnByInternalId(columnInternalId), grid.getDataCommunicator().getKeyMapper().get(rowKey), details)),
MiddleClickGridExtensionConnector.Rpc.class);
}
public static void extend(MyGrid<?> grid) {
new MiddleClickExtension<>(grid);
}
#Override
public void generateData(Object item, JsonObject jsonObject) {
}
#Override
public void destroyData(Object item) {
}
#Override
public void destroyAllData() {
}
#Override
public void refreshData(Object item) {
}
}
}
Client side:
#Connect(MyGrid.MiddleClickExtension.class)
public class MiddleClickGridExtensionConnector extends AbstractExtensionConnector {
#Override
protected void extend(ServerConnector target) {
getParent().getWidget().addDomHandler(event -> {
if (event.getNativeButton() == NativeEvent.BUTTON_MIDDLE) {
event.preventDefault();
CellReference<JsonObject> cell = getParent().getWidget().getEventCell();
getRpcProxy(Rpc.class).middleClick(cell.getRow().getString(DataCommunicatorConstants.KEY), getParent().getColumnId(cell.getColumn()),
MouseEventDetailsBuilder.buildMouseEventDetails(event.getNativeEvent(), event.getRelativeElement()));
}
}, MouseDownEvent.getType());
}
#Override
public GridConnector getParent() {
return (GridConnector) super.getParent();
}
public interface Rpc extends ServerRpc {
void middleClick(String rowKey, String columnInternalId, MouseEventDetails details);
}
}

Verify Backing Bean values using Arquillian Warp

My goal is to test using Arquillian Warp
1. Already navigated to a JSF page on a previous test
2. On a another test set a text field to a value, using warp i need to inject the ViewScope Bean , and verify the value in the backing bean
Sample Code
#RunWith(Arquillian.class)
#WarpTest
#RunAsClient
public class TestIT {
private static final String WEBAPP_SRC = "src/main/webapp";
private static final String WEB_INF_SRC = "src/main/webapp/WEB-INF";
private static final String WEB_RESOURCES = "src/main/webapp/resources";
#Deployment(testable = true)
public static WebArchive createDeployment() {
File[] files = Maven.resolver().loadPomFromFile("pom.xml")
.importRuntimeDependencies().resolve().withTransitivity().asFile();
WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
.addPackages(true, "com.mobitill")
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
.addAsWebInfResource(new File(WEB_INF_SRC, "template.xhtml"))
.addAsWebInfResource(new File(WEB_INF_SRC, "jboss-web.xml"))
.addAsWebInfResource(new File(WEB_INF_SRC, "web.xml"))
.addAsWebResource(new File(WEBAPP_SRC, "index.xhtml"))
.addAsWebResource(new File("src/main/webapp/demo", "home.xhtml"), "demo/home.xhtml")
.addAsResource("test-persistence.xml", "META-INF/persistence.xml")
.merge(ShrinkWrap.create(GenericArchive.class).as(ExplodedImporter.class)
.importDirectory(WEB_RESOURCES).as(GenericArchive.class), "resources")
.addAsLibraries(files);
System.out.println(war.toString(true));
return war;
}
#Drone
private WebDriver browser;
#ArquillianResource
private URL deploymentUrl;
#Test
#InSequence(1)
public final void browserTest() throws Exception {
browser.get(deploymentUrl.toExternalForm() + "index");
guardHttp(loginImage).click();
Assert.assertEquals("navigate to home page ", "https://127.0.0.1:8080/citi/demo/home", browser.getCurrentUrl());
}
#Test
#InSequence(2)
public final void homeManagedBean() throws Exception {
Warp
.initiate(new Activity() {
#Override
public void perform() {
WebElement txtMerchantEmailAddress = browser.findElement(By.id("txtMerchantEmailAddress"));
txtMerchantEmailAddress.sendKeys("demouser#yahoo.com");
guardAjax(btnMerchantSave).click();
}
})
.observe(request().header().containsHeader("faces-request"))
.inspect(new Inspection() {
private static final long serialVersionUID = 1L;
#Inject
HomeManagedBean hmb;
#ArquillianResource
FacesContext facesContext;
#BeforePhase(UPDATE_MODEL_VALUES)
public void initial_state_havent_changed_yet() {
Assert.assertEquals("email value ", "demouser#yahoo.com", hmb.getMerchantEmail());
}
#AfterPhase(UPDATE_MODEL_VALUES)
public void changed_input_value_has_been_applied() {
Assert.assertEquals(" email value ", "demouser#yahoo.com", hmb.getMerchantEmail());
}
});
}
}
the error i keep gettting is
org.jboss.arquillian.warp.impl.client.execution.WarpSynchronizationException: The Warp failed to observe requests or match them with response.
There were no requests matched by observer [containsHeader('faces-request')]
If Warp enriched a wrong request, use observe(...) method to select appropriate request which should be enriched instead.
Otherwise check the server-side log and enable Arquillian debugging mode on both, test and server VM by passing -Darquillian.debug=true.
at org.jboss.arquillian.warp.impl.client.execution.SynchronizationPoint.awaitResponses(SynchronizationPoint.java:155)
at org.jboss.arquillian.warp.impl.client.execution.DefaultExecutionSynchronizer.waitForResponse(DefaultExecutionSynchronizer.java:60)
at org.jboss.arquillian.warp.impl.client.execution.WarpExecutionObserver.awaitResponse(WarpExecutionObserver.java:64)
any help will be welcomed or an alternative way of validating a jsf viewscope bean during integration testing
I was able to sort out it was not working and able to create a sample project for future reference if anyone comes by the same problem
Testing using arquillian warp example

how to pause and resume a download in javafx

I am building a download manager in javafx
I have added function to download button which initialises new task.More than one download is also being executed properly.
But I need to add pause and resume function. Please tell how to implement it using executor. Through execute function of Executors, task is being started but how do i pause & then resume it??
Below I am showing relevant portions of my code. Please tell if you need more details. thanks.
Main class
public class Controller implements Initializable {
public Button addDownloadButton;
public Button pauseResumeButton;
public TextField urlTextBox;
public TableView<DownloadEntry> downloadsTable;
ExecutorService executor;
#Override
public void initialize(URL location, ResourceBundle resources) {
// here tableview and table columns are initialised and cellValueFactory is set
executor = Executors.newFixedThreadPool(4);
}
public void addDownloadButtonClicked() {
DownloadEntry task = new DownloadEntry(new URL(urlTextBox.getText()));
downloadsTable.getItems().add(task);
executor.execute(task);
}
public void pauseResumeButtonClicked() {
//CODE FOR PAUSE AND RESUME
}
}
DownloadEntry.java
public class DownloadEntry extends Task<Void> {
public URL url;
public int downloaded;
final int MAX_BUFFER_SIZE=50*1024;
private String status;
//Constructor
public DownloadEntry(URL ur) throws Exception{
url = ur;
//other variables are initialised here
this.updateMessage("Downloading");
}
#Override
protected Void call() {
file = new RandomAccessFile(filename, "rw");
file.seek(downloaded);
stream = con.getInputStream();
while (status.equals("Downloading")) {
byte buffer=new byte[MAX_BUFFER_SIZE];
int c=stream.read(buffer);
if (c==-1){
break;
}
file.write(buffer,0,c);
downloaded += c;
status = "Downloading";
}
if (status.equals("Downloading")) {
status = "Complete";
updateMessage("Complete");
}
return null;
}
}
You may be interested in Concurrency in JavaFX.
I guess you should also have a look at pattern Observer.
By the way I think you should not use constant string as a status ("Downloading", etc), creating an enum would be a better approach.
In your loop, around the read/write part, there should be a synchronization mechanism, controlled by your pause/resume buttons (see the two links).

How to start a file download in vaadin without button?

I know that it is really easy to create a FileDownloader and call extend with a Button. But how do I start a download without the Button?
In my specific situation right now I have a ComboBox and the file I'd like to send to the user is generated after changing its value, based on the input. The file should be sent immediately without waiting for another click. Is that easily possible?
Thanks
raffael
I found a solution myself. Actually two.
The first one uses the deprecated method Page.open()
public class DownloadComponent extends CustomComponent implements ValueChangeListener {
private ComboBox cb = new ComboBox();
public DownloadComponent() {
cb.addValueChangeListener(this);
cb.setNewItemsAllowed(true);
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
setCompositionRoot(cb);
}
#Override
public void valueChange(ValueChangeEvent event) {
String val = (String) event.getProperty().getValue();
FileResource res = new FileResource(new File(val));
Page.getCurrent().open(res, null, false);
}
}
The javadoc here mentions some memory and security problems as reason for marking it deprecated
In the second I try to go around this deprecated method by registering the resource in the DownloadComponent. I'd be glad if a vaadin expert comments this solution.
public class DownloadComponent extends CustomComponent implements ValueChangeListener {
private ComboBox cb = new ComboBox();
private static final String MYKEY = "download";
public DownloadComponent() {
cb.addValueChangeListener(this);
cb.setNewItemsAllowed(true);
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
setCompositionRoot(cb);
}
#Override
public void valueChange(ValueChangeEvent event) {
String val = (String) event.getProperty().getValue();
FileResource res = new FileResource(new File(val));
setResource(MYKEY, res);
ResourceReference rr = ResourceReference.create(res, this, MYKEY);
Page.getCurrent().open(rr.getURL(), null);
}
}
Note: I do not really allow the user to open all my files on the server and you should not do that either. It is just for demonstration.
Here is my work-around. It works like a charm for me. Hope it will help you.
Create a button and hide it by Css (NOT by code: button.setInvisible(false))
final Button downloadInvisibleButton = new Button();
downloadInvisibleButton.setId("DownloadButtonId");
downloadInvisibleButton.addStyleName("InvisibleButton");
In your theme, add this rule to hide the downloadInvisibleButton:
.InvisibleButton {
display: none;
}
When the user clicks on menuItem: extend the fileDownloader to the downloadInvisibleButton, then simulate the click on the downloadInvisibleButton by JavaScript.
menuBar.addItem("Download", new MenuBar.Command() {
#Override
public void menuSelected(MenuBar.MenuItem selectedItem) {
FileDownloader fileDownloader = new FileDownloader(...);
fileDownloader.extend(downloadInvisibleButton);
//Simulate the click on downloadInvisibleButton by JavaScript
Page.getCurrent().getJavaScript()
.execute("document.getElementById('DownloadButtonId').click();");
}
});

Resources